xref: /freebsd/contrib/llvm-project/llvm/lib/Target/CSKY/MCTargetDesc/CSKYAsmBackend.cpp (revision e3f4a63af63bea70bc86b6c790b14aa5ee99fcd0)
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>
23 CSKYAsmBackend::createObjectTargetWriter() const {
24   return createCSKYELFObjectWriter();
25 }
26 
27 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 
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 
160 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 
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 
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 
242 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 
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 
279 bool CSKYAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup,
280                                           uint64_t Value) const {
281   return false;
282 }
283 
284 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 
339 bool CSKYAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,
340                                   const MCSubtargetInfo *STI) const {
341   OS.write_zeros(Count);
342   return true;
343 }
344 
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