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 FK_Data_1:
92   case FK_Data_2:
93   case FK_Data_4:
94   case FK_Data_8:
95     return Value;
96   case CSKY::fixup_csky_addr32:
97     return Value & 0xffffffff;
98   case CSKY::fixup_csky_pcrel_imm16_scale2:
99     if (!isIntN(17, Value))
100       Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value.");
101     if (Value & 0x1)
102       Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned.");
103 
104     return (Value >> 1) & 0xffff;
105   case CSKY::fixup_csky_pcrel_uimm16_scale4:
106     if (!isUIntN(18, Value))
107       Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value.");
108     if (Value & 0x3)
109       Ctx.reportError(Fixup.getLoc(), "fixup value must be 4-byte aligned.");
110 
111     return (Value >> 2) & 0xffff;
112   case CSKY::fixup_csky_pcrel_imm26_scale2:
113     if (!isIntN(27, 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) & 0x3ffffff;
119   case CSKY::fixup_csky_pcrel_imm18_scale2:
120     if (!isIntN(19, 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) & 0x3ffff;
126   }
127 }
128 
129 void CSKYAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
130                                 const MCValue &Target,
131                                 MutableArrayRef<char> Data, uint64_t Value,
132                                 bool IsResolved,
133                                 const MCSubtargetInfo *STI) const {
134   MCFixupKind Kind = Fixup.getKind();
135   if (Kind >= FirstLiteralRelocationKind)
136     return;
137   MCContext &Ctx = Asm.getContext();
138   MCFixupKindInfo Info = getFixupKindInfo(Kind);
139   if (!Value)
140     return; // Doesn't change encoding.
141   // Apply any target-specific value adjustments.
142   Value = adjustFixupValue(Fixup, Value, Ctx);
143 
144   // Shift the value into position.
145   Value <<= Info.TargetOffset;
146 
147   unsigned Offset = Fixup.getOffset();
148   unsigned NumBytes = alignTo(Info.TargetSize + Info.TargetOffset, 8) / 8;
149 
150   assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!");
151 
152   // For each byte of the fragment that the fixup touches, mask in the
153   // bits from the fixup value.
154   bool IsLittleEndian = (Endian == support::little);
155 
156   if (IsLittleEndian && (NumBytes == 4)) {
157     Data[Offset + 0] |= uint8_t((Value >> 16) & 0xff);
158     Data[Offset + 1] |= uint8_t((Value >> 24) & 0xff);
159     Data[Offset + 2] |= uint8_t(Value & 0xff);
160     Data[Offset + 3] |= uint8_t((Value >> 8) & 0xff);
161   } else {
162     for (unsigned I = 0; I != NumBytes; I++) {
163       unsigned Idx = IsLittleEndian ? I : (NumBytes - 1 - I);
164       Data[Offset + Idx] |= uint8_t((Value >> (I * 8)) & 0xff);
165     }
166   }
167 }
168 
169 bool CSKYAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
170                                           const MCRelaxableFragment *DF,
171                                           const MCAsmLayout &Layout) const {
172   return false;
173 }
174 
175 void CSKYAsmBackend::relaxInstruction(MCInst &Inst,
176                                       const MCSubtargetInfo &STI) const {
177   llvm_unreachable("CSKYAsmBackend::relaxInstruction() unimplemented");
178 }
179 
180 bool CSKYAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,
181                                   const MCSubtargetInfo *STI) const {
182   if (Count % 2)
183     return false;
184 
185   // MOV32 r0, r0
186   while (Count >= 4) {
187     OS.write("\xc4\x00\x48\x20", 4);
188     Count -= 4;
189   }
190   // MOV16 r0, r0
191   if (Count)
192     OS.write("\x6c\x03", 2);
193 
194   return true;
195 }
196 
197 MCAsmBackend *llvm::createCSKYAsmBackend(const Target &T,
198                                          const MCSubtargetInfo &STI,
199                                          const MCRegisterInfo &MRI,
200                                          const MCTargetOptions &Options) {
201   return new CSKYAsmBackend(STI, Options);
202 }
203