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/MCAsmLayout.h"
13 #include "llvm/MC/MCAssembler.h"
14 #include "llvm/MC/MCContext.h"
15 #include "llvm/MC/MCFixupKindInfo.h"
16 #include "llvm/MC/MCObjectWriter.h"
17 #include "llvm/Support/Debug.h"
18
19 #define DEBUG_TYPE "csky-asmbackend"
20
21 using namespace llvm;
22
23 std::unique_ptr<MCObjectTargetWriter>
createObjectTargetWriter() const24 CSKYAsmBackend::createObjectTargetWriter() const {
25 return createCSKYELFObjectWriter();
26 }
27
28 const MCFixupKindInfo &
getFixupKindInfo(MCFixupKind Kind) const29 CSKYAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
30
31 static llvm::DenseMap<unsigned, MCFixupKindInfo> Infos = {
32 {CSKY::Fixups::fixup_csky_addr32, {"fixup_csky_addr32", 0, 32, 0}},
33 {CSKY::Fixups::fixup_csky_addr_hi16, {"fixup_csky_addr_hi16", 0, 32, 0}},
34 {CSKY::Fixups::fixup_csky_addr_lo16, {"fixup_csky_addr_lo16", 0, 32, 0}},
35 {CSKY::Fixups::fixup_csky_pcrel_imm16_scale2,
36 {"fixup_csky_pcrel_imm16_scale2", 0, 32, MCFixupKindInfo::FKF_IsPCRel}},
37 {CSKY::Fixups::fixup_csky_pcrel_uimm16_scale4,
38 {"fixup_csky_pcrel_uimm16_scale4", 0, 32,
39 MCFixupKindInfo::FKF_IsPCRel |
40 MCFixupKindInfo::FKF_IsAlignedDownTo32Bits}},
41 {CSKY::Fixups::fixup_csky_pcrel_uimm8_scale4,
42 {"fixup_csky_pcrel_uimm8_scale4", 0, 32,
43 MCFixupKindInfo::FKF_IsPCRel |
44 MCFixupKindInfo::FKF_IsAlignedDownTo32Bits}},
45 {CSKY::Fixups::fixup_csky_pcrel_imm26_scale2,
46 {"fixup_csky_pcrel_imm26_scale2", 0, 32, MCFixupKindInfo::FKF_IsPCRel}},
47 {CSKY::Fixups::fixup_csky_pcrel_imm18_scale2,
48 {"fixup_csky_pcrel_imm18_scale2", 0, 32, MCFixupKindInfo::FKF_IsPCRel}},
49 {CSKY::Fixups::fixup_csky_got32, {"fixup_csky_got32", 0, 32, 0}},
50 {CSKY::Fixups::fixup_csky_got_imm18_scale4,
51 {"fixup_csky_got_imm18_scale4", 0, 32, 0}},
52 {CSKY::Fixups::fixup_csky_gotoff, {"fixup_csky_gotoff", 0, 32, 0}},
53 {CSKY::Fixups::fixup_csky_gotpc,
54 {"fixup_csky_gotpc", 0, 32, MCFixupKindInfo::FKF_IsPCRel}},
55 {CSKY::Fixups::fixup_csky_plt32, {"fixup_csky_plt32", 0, 32, 0}},
56 {CSKY::Fixups::fixup_csky_plt_imm18_scale4,
57 {"fixup_csky_plt_imm18_scale4", 0, 32, 0}},
58 {CSKY::Fixups::fixup_csky_pcrel_imm10_scale2,
59 {"fixup_csky_pcrel_imm10_scale2", 0, 16, MCFixupKindInfo::FKF_IsPCRel}},
60 {CSKY::Fixups::fixup_csky_pcrel_uimm7_scale4,
61 {"fixup_csky_pcrel_uimm7_scale4", 0, 16,
62 MCFixupKindInfo::FKF_IsPCRel |
63 MCFixupKindInfo::FKF_IsAlignedDownTo32Bits}},
64 {CSKY::Fixups::fixup_csky_doffset_imm18,
65 {"fixup_csky_doffset_imm18", 0, 18, 0}},
66 {CSKY::Fixups::fixup_csky_doffset_imm18_scale2,
67 {"fixup_csky_doffset_imm18_scale2", 0, 18, 0}},
68 {CSKY::Fixups::fixup_csky_doffset_imm18_scale4,
69 {"fixup_csky_doffset_imm18_scale4", 0, 18, 0}}};
70
71 assert(Infos.size() == CSKY::NumTargetFixupKinds &&
72 "Not all fixup kinds added to Infos array");
73
74 if (FirstTargetFixupKind <= Kind && Kind < FirstLiteralRelocationKind) {
75 assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() &&
76 "Invalid kind!");
77
78 return Infos[Kind];
79 } else if (Kind < FirstTargetFixupKind) {
80 return MCAsmBackend::getFixupKindInfo(Kind);
81 } else {
82 return MCAsmBackend::getFixupKindInfo(FK_NONE);
83 }
84 }
85
adjustFixupValue(const MCFixup & Fixup,uint64_t Value,MCContext & Ctx)86 static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
87 MCContext &Ctx) {
88 switch (Fixup.getTargetKind()) {
89 default:
90 llvm_unreachable("Unknown fixup kind!");
91 case CSKY::fixup_csky_got32:
92 case CSKY::fixup_csky_got_imm18_scale4:
93 case CSKY::fixup_csky_gotoff:
94 case CSKY::fixup_csky_gotpc:
95 case CSKY::fixup_csky_plt32:
96 case CSKY::fixup_csky_plt_imm18_scale4:
97 llvm_unreachable("Relocation should be unconditionally forced\n");
98 case FK_Data_1:
99 case FK_Data_2:
100 case FK_Data_4:
101 case FK_Data_8:
102 return Value;
103 case CSKY::fixup_csky_addr32:
104 return Value & 0xffffffff;
105 case CSKY::fixup_csky_pcrel_imm16_scale2:
106 if (!isIntN(17, 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) & 0xffff;
112 case CSKY::fixup_csky_pcrel_uimm16_scale4:
113 if (!isUIntN(18, Value))
114 Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value.");
115 if (Value & 0x3)
116 Ctx.reportError(Fixup.getLoc(), "fixup value must be 4-byte aligned.");
117
118 return (Value >> 2) & 0xffff;
119 case CSKY::fixup_csky_pcrel_imm26_scale2:
120 if (!isIntN(27, Value))
121 Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value.");
122 if (Value & 0x1)
123 Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned.");
124
125 return (Value >> 1) & 0x3ffffff;
126 case CSKY::fixup_csky_pcrel_imm18_scale2:
127 if (!isIntN(19, Value))
128 Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value.");
129 if (Value & 0x1)
130 Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned.");
131
132 return (Value >> 1) & 0x3ffff;
133 case CSKY::fixup_csky_pcrel_uimm8_scale4: {
134 if (!isUIntN(10, Value))
135 Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value.");
136 if (Value & 0x3)
137 Ctx.reportError(Fixup.getLoc(), "fixup value must be 4-byte aligned.");
138
139 unsigned IMM4L = (Value >> 2) & 0xf;
140 unsigned IMM4H = (Value >> 6) & 0xf;
141
142 Value = (IMM4H << 21) | (IMM4L << 4);
143 return Value;
144 }
145 case CSKY::fixup_csky_pcrel_imm10_scale2:
146 if (!isIntN(11, Value))
147 Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value.");
148 if (Value & 0x1)
149 Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned.");
150
151 return (Value >> 1) & 0x3ff;
152 case CSKY::fixup_csky_pcrel_uimm7_scale4:
153 if ((Value >> 2) > 0xfe)
154 Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value.");
155 if (Value & 0x3)
156 Ctx.reportError(Fixup.getLoc(), "fixup value must be 4-byte aligned.");
157
158 if ((Value >> 2) <= 0x7f) {
159 unsigned IMM5L = (Value >> 2) & 0x1f;
160 unsigned IMM2H = (Value >> 7) & 0x3;
161
162 Value = (1 << 12) | (IMM2H << 8) | IMM5L;
163 } else {
164 unsigned IMM5L = (~Value >> 2) & 0x1f;
165 unsigned IMM2H = (~Value >> 7) & 0x3;
166
167 Value = (IMM2H << 8) | IMM5L;
168 }
169
170 return Value;
171 }
172 }
173
fixupNeedsRelaxationAdvanced(const MCFixup & Fixup,bool Resolved,uint64_t Value,const MCRelaxableFragment * DF,const MCAsmLayout & Layout,const bool WasForced) const174 bool CSKYAsmBackend::fixupNeedsRelaxationAdvanced(const MCFixup &Fixup,
175 bool Resolved, uint64_t Value,
176 const MCRelaxableFragment *DF,
177 const MCAsmLayout &Layout,
178 const bool WasForced) const {
179 // Return true if the symbol is actually unresolved.
180 // Resolved could be always false when shouldForceRelocation return true.
181 // We use !WasForced to indicate that the symbol is unresolved and not forced
182 // by shouldForceRelocation.
183 if (!Resolved && !WasForced)
184 return true;
185
186 int64_t Offset = int64_t(Value);
187 switch (Fixup.getTargetKind()) {
188 default:
189 return false;
190 case CSKY::fixup_csky_pcrel_imm10_scale2:
191 return !isShiftedInt<10, 1>(Offset);
192 case CSKY::fixup_csky_pcrel_imm16_scale2:
193 return !isShiftedInt<16, 1>(Offset);
194 case CSKY::fixup_csky_pcrel_imm26_scale2:
195 return !isShiftedInt<26, 1>(Offset);
196 case CSKY::fixup_csky_pcrel_uimm7_scale4:
197 return ((Value >> 2) > 0xfe) || (Value & 0x3);
198 }
199 }
200
applyFixup(const MCAssembler & Asm,const MCFixup & Fixup,const MCValue & Target,MutableArrayRef<char> Data,uint64_t Value,bool IsResolved,const MCSubtargetInfo * STI) const201 void CSKYAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
202 const MCValue &Target,
203 MutableArrayRef<char> Data, uint64_t Value,
204 bool IsResolved,
205 const MCSubtargetInfo *STI) const {
206 MCFixupKind Kind = Fixup.getKind();
207 if (Kind >= FirstLiteralRelocationKind)
208 return;
209 MCContext &Ctx = Asm.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(const MCInst & Inst,const MCSubtargetInfo & STI) const242 bool CSKYAsmBackend::mayNeedRelaxation(const MCInst &Inst,
243 const MCSubtargetInfo &STI) const {
244 switch (Inst.getOpcode()) {
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 MCAssembler & Asm,const MCFixup & Fixup,const MCValue & Target,const MCSubtargetInfo *)263 bool CSKYAsmBackend::shouldForceRelocation(const MCAssembler &Asm,
264 const MCFixup &Fixup,
265 const MCValue &Target,
266 const MCSubtargetInfo * /*STI*/) {
267 if (Fixup.getKind() >= FirstLiteralRelocationKind)
268 return true;
269 switch (Fixup.getTargetKind()) {
270 default:
271 break;
272 case CSKY::fixup_csky_got32:
273 case CSKY::fixup_csky_got_imm18_scale4:
274 case CSKY::fixup_csky_gotoff:
275 case CSKY::fixup_csky_gotpc:
276 case CSKY::fixup_csky_plt32:
277 case CSKY::fixup_csky_plt_imm18_scale4:
278 case CSKY::fixup_csky_doffset_imm18:
279 case CSKY::fixup_csky_doffset_imm18_scale2:
280 case CSKY::fixup_csky_doffset_imm18_scale4:
281 return true;
282 }
283
284 return false;
285 }
286
fixupNeedsRelaxation(const MCFixup & Fixup,uint64_t Value,const MCRelaxableFragment * DF,const MCAsmLayout & Layout) const287 bool CSKYAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
288 const MCRelaxableFragment *DF,
289 const MCAsmLayout &Layout) const {
290 return false;
291 }
292
relaxInstruction(MCInst & Inst,const MCSubtargetInfo & STI) const293 void CSKYAsmBackend::relaxInstruction(MCInst &Inst,
294 const MCSubtargetInfo &STI) const {
295 MCInst Res;
296
297 switch (Inst.getOpcode()) {
298 default:
299 LLVM_DEBUG(Inst.dump());
300 llvm_unreachable("Opcode not expected!");
301 case CSKY::LRW16:
302 Res.setOpcode(CSKY::LRW32);
303 Res.addOperand(Inst.getOperand(0));
304 Res.addOperand(Inst.getOperand(1));
305 break;
306 case CSKY::BR16:
307 Res.setOpcode(CSKY::BR32);
308 Res.addOperand(Inst.getOperand(0));
309 break;
310 case CSKY::JBSR32:
311 Res.setOpcode(CSKY::JSRI32);
312 Res.addOperand(Inst.getOperand(1));
313 break;
314 case CSKY::JBR32:
315 Res.setOpcode(CSKY::JMPI32);
316 Res.addOperand(Inst.getOperand(1));
317 break;
318 case CSKY::JBT32:
319 case CSKY::JBF32:
320 Res.setOpcode(Inst.getOpcode() == CSKY::JBT32 ? CSKY::JBT_E : CSKY::JBF_E);
321 Res.addOperand(Inst.getOperand(0));
322 Res.addOperand(Inst.getOperand(1));
323 Res.addOperand(Inst.getOperand(2));
324 break;
325 case CSKY::JBR16:
326 Res.setOpcode(CSKY::JBR32);
327 Res.addOperand(Inst.getOperand(0));
328 Res.addOperand(Inst.getOperand(1));
329 break;
330 case CSKY::JBT16:
331 case CSKY::JBF16:
332 // ck801
333 unsigned opcode;
334 if (STI.hasFeature(CSKY::HasE2))
335 opcode = Inst.getOpcode() == CSKY::JBT16 ? CSKY::JBT32 : CSKY::JBF32;
336 else
337 opcode = Inst.getOpcode() == CSKY::JBT16 ? CSKY::JBT_E : CSKY::JBF_E;
338
339 Res.setOpcode(opcode);
340 Res.addOperand(Inst.getOperand(0));
341 Res.addOperand(Inst.getOperand(1));
342 Res.addOperand(Inst.getOperand(2));
343 break;
344 }
345 Inst = std::move(Res);
346 }
347
writeNopData(raw_ostream & OS,uint64_t Count,const MCSubtargetInfo * STI) const348 bool CSKYAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,
349 const MCSubtargetInfo *STI) const {
350 OS.write_zeros(Count);
351 return true;
352 }
353
createCSKYAsmBackend(const Target & T,const MCSubtargetInfo & STI,const MCRegisterInfo & MRI,const MCTargetOptions & Options)354 MCAsmBackend *llvm::createCSKYAsmBackend(const Target &T,
355 const MCSubtargetInfo &STI,
356 const MCRegisterInfo &MRI,
357 const MCTargetOptions &Options) {
358 return new CSKYAsmBackend(STI, Options);
359 }
360