xref: /freebsd/contrib/llvm-project/llvm/lib/Target/CSKY/MCTargetDesc/CSKYAsmBackend.cpp (revision b64c5a0ace59af62eff52bfe110a521dc73c937b)
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>
23 CSKYAsmBackend::createObjectTargetWriter() const {
24   return createCSKYELFObjectWriter();
25 }
26 
27 const MCFixupKindInfo &
28 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 
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 
173 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 
200 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 
241 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 
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 
286 bool CSKYAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup,
287                                           uint64_t Value) const {
288   return false;
289 }
290 
291 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 
346 bool CSKYAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,
347                                   const MCSubtargetInfo *STI) const {
348   OS.write_zeros(Count);
349   return true;
350 }
351 
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