xref: /freebsd/contrib/llvm-project/llvm/lib/Target/CSKY/MCTargetDesc/CSKYAsmBackend.cpp (revision aa1a8ff2d6dbc51ef058f46f3db5a8bb77967145)
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>
24 CSKYAsmBackend::createObjectTargetWriter() const {
25   return createCSKYELFObjectWriter();
26 }
27 
28 const MCFixupKindInfo &
29 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 
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 
174 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 
201 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 
242 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 
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 
287 bool CSKYAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
288                                           const MCRelaxableFragment *DF,
289                                           const MCAsmLayout &Layout) const {
290   return false;
291 }
292 
293 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 
348 bool CSKYAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,
349                                   const MCSubtargetInfo *STI) const {
350   OS.write_zeros(Count);
351   return true;
352 }
353 
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