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