1 //===-- CSKYAsmBackend.cpp - CSKY Assembler Backend -----------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "CSKYAsmBackend.h"
10 #include "MCTargetDesc/CSKYMCTargetDesc.h"
11 #include "llvm/ADT/DenseMap.h"
12 #include "llvm/MC/MCAssembler.h"
13 #include "llvm/MC/MCContext.h"
14 #include "llvm/MC/MCObjectWriter.h"
15 #include "llvm/MC/MCValue.h"
16 #include "llvm/Support/Debug.h"
17
18 #define DEBUG_TYPE "csky-asmbackend"
19
20 using namespace llvm;
21
22 std::unique_ptr<MCObjectTargetWriter>
createObjectTargetWriter() const23 CSKYAsmBackend::createObjectTargetWriter() const {
24 return createCSKYELFObjectWriter();
25 }
26
getFixupKindInfo(MCFixupKind Kind) const27 MCFixupKindInfo CSKYAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
28
29 static llvm::DenseMap<unsigned, MCFixupKindInfo> Infos = {
30 {CSKY::Fixups::fixup_csky_addr32, {"fixup_csky_addr32", 0, 32, 0}},
31 {CSKY::Fixups::fixup_csky_addr_hi16, {"fixup_csky_addr_hi16", 0, 32, 0}},
32 {CSKY::Fixups::fixup_csky_addr_lo16, {"fixup_csky_addr_lo16", 0, 32, 0}},
33 {CSKY::Fixups::fixup_csky_pcrel_imm16_scale2,
34 {"fixup_csky_pcrel_imm16_scale2", 0, 32, 0}},
35 {CSKY::Fixups::fixup_csky_pcrel_uimm16_scale4,
36 {"fixup_csky_pcrel_uimm16_scale4", 0, 32, 0}},
37 {CSKY::Fixups::fixup_csky_pcrel_uimm8_scale4,
38 {"fixup_csky_pcrel_uimm8_scale4", 0, 32, 0}},
39 {CSKY::Fixups::fixup_csky_pcrel_imm26_scale2,
40 {"fixup_csky_pcrel_imm26_scale2", 0, 32, 0}},
41 {CSKY::Fixups::fixup_csky_pcrel_imm18_scale2,
42 {"fixup_csky_pcrel_imm18_scale2", 0, 32, 0}},
43 {CSKY::Fixups::fixup_csky_got32, {"fixup_csky_got32", 0, 32, 0}},
44 {CSKY::Fixups::fixup_csky_got_imm18_scale4,
45 {"fixup_csky_got_imm18_scale4", 0, 32, 0}},
46 {CSKY::Fixups::fixup_csky_gotoff, {"fixup_csky_gotoff", 0, 32, 0}},
47 {CSKY::Fixups::fixup_csky_gotpc, {"fixup_csky_gotpc", 0, 32, 0}},
48 {CSKY::Fixups::fixup_csky_plt32, {"fixup_csky_plt32", 0, 32, 0}},
49 {CSKY::Fixups::fixup_csky_plt_imm18_scale4,
50 {"fixup_csky_plt_imm18_scale4", 0, 32, 0}},
51 {CSKY::Fixups::fixup_csky_pcrel_imm10_scale2,
52 {"fixup_csky_pcrel_imm10_scale2", 0, 16, 0}},
53 {CSKY::Fixups::fixup_csky_pcrel_uimm7_scale4,
54 {"fixup_csky_pcrel_uimm7_scale4", 0, 16, 0}},
55 {CSKY::Fixups::fixup_csky_doffset_imm18,
56 {"fixup_csky_doffset_imm18", 0, 18, 0}},
57 {CSKY::Fixups::fixup_csky_doffset_imm18_scale2,
58 {"fixup_csky_doffset_imm18_scale2", 0, 18, 0}},
59 {CSKY::Fixups::fixup_csky_doffset_imm18_scale4,
60 {"fixup_csky_doffset_imm18_scale4", 0, 18, 0}}};
61
62 assert(Infos.size() == CSKY::NumTargetFixupKinds &&
63 "Not all fixup kinds added to Infos array");
64
65 if (mc::isRelocation(Kind))
66 return {};
67 if (Kind < FirstTargetFixupKind)
68 return MCAsmBackend::getFixupKindInfo(Kind);
69 return Infos[Kind];
70 }
71
adjustFixupValue(const MCFixup & Fixup,uint64_t Value,MCContext & Ctx)72 static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
73 MCContext &Ctx) {
74 switch (Fixup.getKind()) {
75 default:
76 llvm_unreachable("Unknown fixup kind!");
77 case CSKY::fixup_csky_got32:
78 case CSKY::fixup_csky_got_imm18_scale4:
79 case CSKY::fixup_csky_gotoff:
80 case CSKY::fixup_csky_gotpc:
81 case CSKY::fixup_csky_plt32:
82 case CSKY::fixup_csky_plt_imm18_scale4:
83 llvm_unreachable("Relocation should be unconditionally forced\n");
84 case FK_Data_1:
85 case FK_Data_2:
86 case FK_Data_4:
87 case FK_Data_8:
88 return Value;
89 case CSKY::fixup_csky_addr32:
90 return Value & 0xffffffff;
91 case CSKY::fixup_csky_pcrel_imm16_scale2:
92 if (!isIntN(17, Value))
93 Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value.");
94 if (Value & 0x1)
95 Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned.");
96
97 return (Value >> 1) & 0xffff;
98 case CSKY::fixup_csky_pcrel_uimm16_scale4:
99 if (!isUIntN(18, Value))
100 Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value.");
101 if (Value & 0x3)
102 Ctx.reportError(Fixup.getLoc(), "fixup value must be 4-byte aligned.");
103
104 return (Value >> 2) & 0xffff;
105 case CSKY::fixup_csky_pcrel_imm26_scale2:
106 if (!isIntN(27, Value))
107 Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value.");
108 if (Value & 0x1)
109 Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned.");
110
111 return (Value >> 1) & 0x3ffffff;
112 case CSKY::fixup_csky_pcrel_imm18_scale2:
113 if (!isIntN(19, Value))
114 Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value.");
115 if (Value & 0x1)
116 Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned.");
117
118 return (Value >> 1) & 0x3ffff;
119 case CSKY::fixup_csky_pcrel_uimm8_scale4: {
120 if (!isUIntN(10, Value))
121 Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value.");
122 if (Value & 0x3)
123 Ctx.reportError(Fixup.getLoc(), "fixup value must be 4-byte aligned.");
124
125 unsigned IMM4L = (Value >> 2) & 0xf;
126 unsigned IMM4H = (Value >> 6) & 0xf;
127
128 Value = (IMM4H << 21) | (IMM4L << 4);
129 return Value;
130 }
131 case CSKY::fixup_csky_pcrel_imm10_scale2:
132 if (!isIntN(11, Value))
133 Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value.");
134 if (Value & 0x1)
135 Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned.");
136
137 return (Value >> 1) & 0x3ff;
138 case CSKY::fixup_csky_pcrel_uimm7_scale4:
139 if ((Value >> 2) > 0xfe)
140 Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value.");
141 if (Value & 0x3)
142 Ctx.reportError(Fixup.getLoc(), "fixup value must be 4-byte aligned.");
143
144 if ((Value >> 2) <= 0x7f) {
145 unsigned IMM5L = (Value >> 2) & 0x1f;
146 unsigned IMM2H = (Value >> 7) & 0x3;
147
148 Value = (1 << 12) | (IMM2H << 8) | IMM5L;
149 } else {
150 unsigned IMM5L = (~Value >> 2) & 0x1f;
151 unsigned IMM2H = (~Value >> 7) & 0x3;
152
153 Value = (IMM2H << 8) | IMM5L;
154 }
155
156 return Value;
157 }
158 }
159
fixupNeedsRelaxationAdvanced(const MCFixup & Fixup,const MCValue &,uint64_t Value,bool Resolved) const160 bool CSKYAsmBackend::fixupNeedsRelaxationAdvanced(const MCFixup &Fixup,
161 const MCValue &,
162 uint64_t Value,
163 bool Resolved) const {
164 // Return true if the symbol is unresolved.
165 if (!Resolved)
166 return true;
167
168 int64_t Offset = int64_t(Value);
169 switch (Fixup.getKind()) {
170 default:
171 return false;
172 case CSKY::fixup_csky_pcrel_imm10_scale2:
173 return !isShiftedInt<10, 1>(Offset);
174 case CSKY::fixup_csky_pcrel_imm16_scale2:
175 return !isShiftedInt<16, 1>(Offset);
176 case CSKY::fixup_csky_pcrel_imm26_scale2:
177 return !isShiftedInt<26, 1>(Offset);
178 case CSKY::fixup_csky_pcrel_uimm7_scale4:
179 return ((Value >> 2) > 0xfe) || (Value & 0x3);
180 }
181 }
182
evaluateFixup(const MCFragment & F,MCFixup & Fixup,MCValue &,uint64_t & Value)183 std::optional<bool> CSKYAsmBackend::evaluateFixup(const MCFragment &F,
184 MCFixup &Fixup, MCValue &,
185 uint64_t &Value) {
186 // For a few PC-relative fixups, offsets need to be aligned down. We
187 // compensate here because the default handler's `Value` decrement doesn't
188 // account for this alignment.
189 switch (Fixup.getKind()) {
190 case CSKY::fixup_csky_pcrel_uimm16_scale4:
191 case CSKY::fixup_csky_pcrel_uimm8_scale4:
192 case CSKY::fixup_csky_pcrel_uimm7_scale4:
193 Value = (Asm->getFragmentOffset(F) + Fixup.getOffset()) % 4;
194 }
195 return {};
196 }
197
applyFixup(const MCFragment & F,const MCFixup & Fixup,const MCValue & Target,MutableArrayRef<char> Data,uint64_t Value,bool IsResolved)198 void CSKYAsmBackend::applyFixup(const MCFragment &F, const MCFixup &Fixup,
199 const MCValue &Target,
200 MutableArrayRef<char> Data, uint64_t Value,
201 bool IsResolved) {
202 if (IsResolved && shouldForceRelocation(Fixup, Target))
203 IsResolved = false;
204 maybeAddReloc(F, Fixup, Target, Value, IsResolved);
205
206 MCFixupKind Kind = Fixup.getKind();
207 if (mc::isRelocation(Kind))
208 return;
209 MCContext &Ctx = getContext();
210 MCFixupKindInfo Info = getFixupKindInfo(Kind);
211 if (!Value)
212 return; // Doesn't change encoding.
213 // Apply any target-specific value adjustments.
214 Value = adjustFixupValue(Fixup, Value, Ctx);
215
216 // Shift the value into position.
217 Value <<= Info.TargetOffset;
218
219 unsigned Offset = Fixup.getOffset();
220 unsigned NumBytes = alignTo(Info.TargetSize + Info.TargetOffset, 8) / 8;
221
222 assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!");
223
224 // For each byte of the fragment that the fixup touches, mask in the
225 // bits from the fixup value.
226 bool IsLittleEndian = (Endian == llvm::endianness::little);
227 bool IsInstFixup = (Kind >= FirstTargetFixupKind);
228
229 if (IsLittleEndian && IsInstFixup && (NumBytes == 4)) {
230 Data[Offset + 0] |= uint8_t((Value >> 16) & 0xff);
231 Data[Offset + 1] |= uint8_t((Value >> 24) & 0xff);
232 Data[Offset + 2] |= uint8_t(Value & 0xff);
233 Data[Offset + 3] |= uint8_t((Value >> 8) & 0xff);
234 } else {
235 for (unsigned I = 0; I != NumBytes; I++) {
236 unsigned Idx = IsLittleEndian ? I : (NumBytes - 1 - I);
237 Data[Offset + Idx] |= uint8_t((Value >> (I * 8)) & 0xff);
238 }
239 }
240 }
241
mayNeedRelaxation(unsigned Opcode,ArrayRef<MCOperand>,const MCSubtargetInfo & STI) const242 bool CSKYAsmBackend::mayNeedRelaxation(unsigned Opcode, ArrayRef<MCOperand>,
243 const MCSubtargetInfo &STI) const {
244 switch (Opcode) {
245 default:
246 return false;
247 case CSKY::JBR32:
248 case CSKY::JBT32:
249 case CSKY::JBF32:
250 case CSKY::JBSR32:
251 if (!STI.hasFeature(CSKY::Has2E3))
252 return false;
253 return true;
254 case CSKY::JBR16:
255 case CSKY::JBT16:
256 case CSKY::JBF16:
257 case CSKY::LRW16:
258 case CSKY::BR16:
259 return true;
260 }
261 }
262
shouldForceRelocation(const MCFixup & Fixup,const MCValue & Target)263 bool CSKYAsmBackend::shouldForceRelocation(const MCFixup &Fixup,
264 const MCValue &Target /*STI*/) {
265 if (Target.getSpecifier())
266 return true;
267 switch (Fixup.getKind()) {
268 default:
269 break;
270 case CSKY::fixup_csky_doffset_imm18:
271 case CSKY::fixup_csky_doffset_imm18_scale2:
272 case CSKY::fixup_csky_doffset_imm18_scale4:
273 return true;
274 }
275
276 return false;
277 }
278
fixupNeedsRelaxation(const MCFixup & Fixup,uint64_t Value) const279 bool CSKYAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup,
280 uint64_t Value) const {
281 return false;
282 }
283
relaxInstruction(MCInst & Inst,const MCSubtargetInfo & STI) const284 void CSKYAsmBackend::relaxInstruction(MCInst &Inst,
285 const MCSubtargetInfo &STI) const {
286 MCInst Res;
287
288 switch (Inst.getOpcode()) {
289 default:
290 LLVM_DEBUG(Inst.dump());
291 llvm_unreachable("Opcode not expected!");
292 case CSKY::LRW16:
293 Res.setOpcode(CSKY::LRW32);
294 Res.addOperand(Inst.getOperand(0));
295 Res.addOperand(Inst.getOperand(1));
296 break;
297 case CSKY::BR16:
298 Res.setOpcode(CSKY::BR32);
299 Res.addOperand(Inst.getOperand(0));
300 break;
301 case CSKY::JBSR32:
302 Res.setOpcode(CSKY::JSRI32);
303 Res.addOperand(Inst.getOperand(1));
304 break;
305 case CSKY::JBR32:
306 Res.setOpcode(CSKY::JMPI32);
307 Res.addOperand(Inst.getOperand(1));
308 break;
309 case CSKY::JBT32:
310 case CSKY::JBF32:
311 Res.setOpcode(Inst.getOpcode() == CSKY::JBT32 ? CSKY::JBT_E : CSKY::JBF_E);
312 Res.addOperand(Inst.getOperand(0));
313 Res.addOperand(Inst.getOperand(1));
314 Res.addOperand(Inst.getOperand(2));
315 break;
316 case CSKY::JBR16:
317 Res.setOpcode(CSKY::JBR32);
318 Res.addOperand(Inst.getOperand(0));
319 Res.addOperand(Inst.getOperand(1));
320 break;
321 case CSKY::JBT16:
322 case CSKY::JBF16:
323 // ck801
324 unsigned opcode;
325 if (STI.hasFeature(CSKY::HasE2))
326 opcode = Inst.getOpcode() == CSKY::JBT16 ? CSKY::JBT32 : CSKY::JBF32;
327 else
328 opcode = Inst.getOpcode() == CSKY::JBT16 ? CSKY::JBT_E : CSKY::JBF_E;
329
330 Res.setOpcode(opcode);
331 Res.addOperand(Inst.getOperand(0));
332 Res.addOperand(Inst.getOperand(1));
333 Res.addOperand(Inst.getOperand(2));
334 break;
335 }
336 Inst = std::move(Res);
337 }
338
writeNopData(raw_ostream & OS,uint64_t Count,const MCSubtargetInfo * STI) const339 bool CSKYAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,
340 const MCSubtargetInfo *STI) const {
341 OS.write_zeros(Count);
342 return true;
343 }
344
createCSKYAsmBackend(const Target & T,const MCSubtargetInfo & STI,const MCRegisterInfo & MRI,const MCTargetOptions & Options)345 MCAsmBackend *llvm::createCSKYAsmBackend(const Target &T,
346 const MCSubtargetInfo &STI,
347 const MCRegisterInfo &MRI,
348 const MCTargetOptions &Options) {
349 return new CSKYAsmBackend(STI, Options);
350 }
351