xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/CSKY/MCTargetDesc/CSKYAsmBackend.cpp (revision 349cc55c9796c4596a5b9904cd3281af295f878f)
1e8d8bef9SDimitry Andric //===-- CSKYAsmBackend.cpp - CSKY Assembler Backend -----------------------===//
2e8d8bef9SDimitry Andric //
3e8d8bef9SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e8d8bef9SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e8d8bef9SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e8d8bef9SDimitry Andric //
7e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===//
8e8d8bef9SDimitry Andric 
9e8d8bef9SDimitry Andric #include "CSKYAsmBackend.h"
10e8d8bef9SDimitry Andric #include "MCTargetDesc/CSKYMCTargetDesc.h"
11fe6060f1SDimitry Andric #include "llvm/ADT/DenseMap.h"
12e8d8bef9SDimitry Andric #include "llvm/MC/MCAsmLayout.h"
13e8d8bef9SDimitry Andric #include "llvm/MC/MCAssembler.h"
14e8d8bef9SDimitry Andric #include "llvm/MC/MCContext.h"
15e8d8bef9SDimitry Andric #include "llvm/MC/MCFixupKindInfo.h"
16e8d8bef9SDimitry Andric #include "llvm/MC/MCObjectWriter.h"
17e8d8bef9SDimitry Andric #include "llvm/Support/Debug.h"
18e8d8bef9SDimitry Andric 
19e8d8bef9SDimitry Andric #define DEBUG_TYPE "csky-asmbackend"
20e8d8bef9SDimitry Andric 
21e8d8bef9SDimitry Andric using namespace llvm;
22e8d8bef9SDimitry Andric 
23e8d8bef9SDimitry Andric std::unique_ptr<MCObjectTargetWriter>
24e8d8bef9SDimitry Andric CSKYAsmBackend::createObjectTargetWriter() const {
25e8d8bef9SDimitry Andric   return createCSKYELFObjectWriter();
26e8d8bef9SDimitry Andric }
27e8d8bef9SDimitry Andric 
28fe6060f1SDimitry Andric const MCFixupKindInfo &
29fe6060f1SDimitry Andric CSKYAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
30fe6060f1SDimitry Andric 
31fe6060f1SDimitry Andric   static llvm::DenseMap<unsigned, MCFixupKindInfo> Infos = {
32fe6060f1SDimitry Andric       {CSKY::Fixups::fixup_csky_addr32, {"fixup_csky_addr32", 0, 32, 0}},
33*349cc55cSDimitry Andric       {CSKY::Fixups::fixup_csky_addr_hi16, {"fixup_csky_addr_hi16", 0, 32, 0}},
34*349cc55cSDimitry Andric       {CSKY::Fixups::fixup_csky_addr_lo16, {"fixup_csky_addr_lo16", 0, 32, 0}},
35fe6060f1SDimitry Andric       {CSKY::Fixups::fixup_csky_pcrel_imm16_scale2,
36fe6060f1SDimitry Andric        {"fixup_csky_pcrel_imm16_scale2", 0, 32, MCFixupKindInfo::FKF_IsPCRel}},
37fe6060f1SDimitry Andric       {CSKY::Fixups::fixup_csky_pcrel_uimm16_scale4,
38*349cc55cSDimitry Andric        {"fixup_csky_pcrel_uimm16_scale4", 0, 32,
39*349cc55cSDimitry Andric         MCFixupKindInfo::FKF_IsPCRel |
40*349cc55cSDimitry Andric             MCFixupKindInfo::FKF_IsAlignedDownTo32Bits}},
41*349cc55cSDimitry Andric       {CSKY::Fixups::fixup_csky_pcrel_uimm8_scale4,
42*349cc55cSDimitry Andric        {"fixup_csky_pcrel_uimm8_scale4", 0, 32,
43*349cc55cSDimitry Andric         MCFixupKindInfo::FKF_IsPCRel |
44*349cc55cSDimitry Andric             MCFixupKindInfo::FKF_IsAlignedDownTo32Bits}},
45fe6060f1SDimitry Andric       {CSKY::Fixups::fixup_csky_pcrel_imm26_scale2,
46fe6060f1SDimitry Andric        {"fixup_csky_pcrel_imm26_scale2", 0, 32, MCFixupKindInfo::FKF_IsPCRel}},
47fe6060f1SDimitry Andric       {CSKY::Fixups::fixup_csky_pcrel_imm18_scale2,
48*349cc55cSDimitry Andric        {"fixup_csky_pcrel_imm18_scale2", 0, 32, MCFixupKindInfo::FKF_IsPCRel}},
49*349cc55cSDimitry Andric       {CSKY::Fixups::fixup_csky_got32, {"fixup_csky_got32", 0, 32, 0}},
50*349cc55cSDimitry Andric       {CSKY::Fixups::fixup_csky_got_imm18_scale4,
51*349cc55cSDimitry Andric        {"fixup_csky_got_imm18_scale4", 0, 32, 0}},
52*349cc55cSDimitry Andric       {CSKY::Fixups::fixup_csky_gotoff, {"fixup_csky_gotoff", 0, 32, 0}},
53*349cc55cSDimitry Andric       {CSKY::Fixups::fixup_csky_gotpc,
54*349cc55cSDimitry Andric        {"fixup_csky_gotpc", 0, 32, MCFixupKindInfo::FKF_IsPCRel}},
55*349cc55cSDimitry Andric       {CSKY::Fixups::fixup_csky_plt32, {"fixup_csky_plt32", 0, 32, 0}},
56*349cc55cSDimitry Andric       {CSKY::Fixups::fixup_csky_plt_imm18_scale4,
57*349cc55cSDimitry Andric        {"fixup_csky_plt_imm18_scale4", 0, 32, 0}},
58*349cc55cSDimitry Andric       {CSKY::Fixups::fixup_csky_pcrel_imm10_scale2,
59*349cc55cSDimitry Andric        {"fixup_csky_pcrel_imm10_scale2", 0, 16, MCFixupKindInfo::FKF_IsPCRel}},
60*349cc55cSDimitry Andric       {CSKY::Fixups::fixup_csky_pcrel_uimm7_scale4,
61*349cc55cSDimitry Andric        {"fixup_csky_pcrel_uimm7_scale4", 0, 16,
62*349cc55cSDimitry Andric         MCFixupKindInfo::FKF_IsPCRel |
63*349cc55cSDimitry Andric             MCFixupKindInfo::FKF_IsAlignedDownTo32Bits}},
64*349cc55cSDimitry Andric       {CSKY::Fixups::fixup_csky_doffset_imm18,
65*349cc55cSDimitry Andric        {"fixup_csky_doffset_imm18", 0, 18, 0}},
66*349cc55cSDimitry Andric       {CSKY::Fixups::fixup_csky_doffset_imm18_scale2,
67*349cc55cSDimitry Andric        {"fixup_csky_doffset_imm18_scale2", 0, 18, 0}},
68*349cc55cSDimitry Andric       {CSKY::Fixups::fixup_csky_doffset_imm18_scale4,
69*349cc55cSDimitry Andric        {"fixup_csky_doffset_imm18_scale4", 0, 18, 0}}};
70*349cc55cSDimitry Andric 
71fe6060f1SDimitry Andric   assert(Infos.size() == CSKY::NumTargetFixupKinds &&
72fe6060f1SDimitry Andric          "Not all fixup kinds added to Infos array");
73fe6060f1SDimitry Andric 
74*349cc55cSDimitry Andric   if (FirstTargetFixupKind <= Kind && Kind < FirstLiteralRelocationKind) {
75fe6060f1SDimitry Andric     assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() &&
76fe6060f1SDimitry Andric            "Invalid kind!");
77*349cc55cSDimitry Andric 
78fe6060f1SDimitry Andric     return Infos[Kind];
79*349cc55cSDimitry Andric   } else if (Kind < FirstTargetFixupKind) {
80fe6060f1SDimitry Andric     return MCAsmBackend::getFixupKindInfo(Kind);
81*349cc55cSDimitry Andric   } else {
82fe6060f1SDimitry Andric     return MCAsmBackend::getFixupKindInfo(FK_NONE);
83fe6060f1SDimitry Andric   }
84*349cc55cSDimitry Andric }
85fe6060f1SDimitry Andric 
86fe6060f1SDimitry Andric static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
87fe6060f1SDimitry Andric                                  MCContext &Ctx) {
88fe6060f1SDimitry Andric   switch (Fixup.getTargetKind()) {
89fe6060f1SDimitry Andric   default:
90fe6060f1SDimitry Andric     llvm_unreachable("Unknown fixup kind!");
91fe6060f1SDimitry Andric   case FK_Data_1:
92fe6060f1SDimitry Andric   case FK_Data_2:
93fe6060f1SDimitry Andric   case FK_Data_4:
94fe6060f1SDimitry Andric   case FK_Data_8:
95fe6060f1SDimitry Andric     return Value;
96fe6060f1SDimitry Andric   case CSKY::fixup_csky_addr32:
97fe6060f1SDimitry Andric     return Value & 0xffffffff;
98fe6060f1SDimitry Andric   case CSKY::fixup_csky_pcrel_imm16_scale2:
99fe6060f1SDimitry Andric     if (!isIntN(17, Value))
100fe6060f1SDimitry Andric       Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value.");
101fe6060f1SDimitry Andric     if (Value & 0x1)
102fe6060f1SDimitry Andric       Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned.");
103fe6060f1SDimitry Andric 
104fe6060f1SDimitry Andric     return (Value >> 1) & 0xffff;
105fe6060f1SDimitry Andric   case CSKY::fixup_csky_pcrel_uimm16_scale4:
106fe6060f1SDimitry Andric     if (!isUIntN(18, Value))
107fe6060f1SDimitry Andric       Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value.");
108fe6060f1SDimitry Andric     if (Value & 0x3)
109fe6060f1SDimitry Andric       Ctx.reportError(Fixup.getLoc(), "fixup value must be 4-byte aligned.");
110fe6060f1SDimitry Andric 
111fe6060f1SDimitry Andric     return (Value >> 2) & 0xffff;
112fe6060f1SDimitry Andric   case CSKY::fixup_csky_pcrel_imm26_scale2:
113fe6060f1SDimitry Andric     if (!isIntN(27, Value))
114fe6060f1SDimitry Andric       Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value.");
115fe6060f1SDimitry Andric     if (Value & 0x1)
116fe6060f1SDimitry Andric       Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned.");
117fe6060f1SDimitry Andric 
118fe6060f1SDimitry Andric     return (Value >> 1) & 0x3ffffff;
119fe6060f1SDimitry Andric   case CSKY::fixup_csky_pcrel_imm18_scale2:
120fe6060f1SDimitry Andric     if (!isIntN(19, Value))
121fe6060f1SDimitry Andric       Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value.");
122fe6060f1SDimitry Andric     if (Value & 0x1)
123fe6060f1SDimitry Andric       Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned.");
124fe6060f1SDimitry Andric 
125fe6060f1SDimitry Andric     return (Value >> 1) & 0x3ffff;
126fe6060f1SDimitry Andric   }
127fe6060f1SDimitry Andric }
128e8d8bef9SDimitry Andric 
129e8d8bef9SDimitry Andric void CSKYAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
130e8d8bef9SDimitry Andric                                 const MCValue &Target,
131e8d8bef9SDimitry Andric                                 MutableArrayRef<char> Data, uint64_t Value,
132e8d8bef9SDimitry Andric                                 bool IsResolved,
133e8d8bef9SDimitry Andric                                 const MCSubtargetInfo *STI) const {
134fe6060f1SDimitry Andric   MCFixupKind Kind = Fixup.getKind();
135fe6060f1SDimitry Andric   if (Kind >= FirstLiteralRelocationKind)
136e8d8bef9SDimitry Andric     return;
137fe6060f1SDimitry Andric   MCContext &Ctx = Asm.getContext();
138fe6060f1SDimitry Andric   MCFixupKindInfo Info = getFixupKindInfo(Kind);
139fe6060f1SDimitry Andric   if (!Value)
140fe6060f1SDimitry Andric     return; // Doesn't change encoding.
141fe6060f1SDimitry Andric   // Apply any target-specific value adjustments.
142fe6060f1SDimitry Andric   Value = adjustFixupValue(Fixup, Value, Ctx);
143fe6060f1SDimitry Andric 
144fe6060f1SDimitry Andric   // Shift the value into position.
145fe6060f1SDimitry Andric   Value <<= Info.TargetOffset;
146fe6060f1SDimitry Andric 
147fe6060f1SDimitry Andric   unsigned Offset = Fixup.getOffset();
148fe6060f1SDimitry Andric   unsigned NumBytes = alignTo(Info.TargetSize + Info.TargetOffset, 8) / 8;
149fe6060f1SDimitry Andric 
150fe6060f1SDimitry Andric   assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!");
151fe6060f1SDimitry Andric 
152fe6060f1SDimitry Andric   // For each byte of the fragment that the fixup touches, mask in the
153fe6060f1SDimitry Andric   // bits from the fixup value.
154fe6060f1SDimitry Andric   bool IsLittleEndian = (Endian == support::little);
155fe6060f1SDimitry Andric 
156fe6060f1SDimitry Andric   if (IsLittleEndian && (NumBytes == 4)) {
157fe6060f1SDimitry Andric     Data[Offset + 0] |= uint8_t((Value >> 16) & 0xff);
158fe6060f1SDimitry Andric     Data[Offset + 1] |= uint8_t((Value >> 24) & 0xff);
159fe6060f1SDimitry Andric     Data[Offset + 2] |= uint8_t(Value & 0xff);
160fe6060f1SDimitry Andric     Data[Offset + 3] |= uint8_t((Value >> 8) & 0xff);
161fe6060f1SDimitry Andric   } else {
162fe6060f1SDimitry Andric     for (unsigned I = 0; I != NumBytes; I++) {
163fe6060f1SDimitry Andric       unsigned Idx = IsLittleEndian ? I : (NumBytes - 1 - I);
164fe6060f1SDimitry Andric       Data[Offset + Idx] |= uint8_t((Value >> (I * 8)) & 0xff);
165fe6060f1SDimitry Andric     }
166fe6060f1SDimitry Andric   }
167e8d8bef9SDimitry Andric }
168e8d8bef9SDimitry Andric 
169e8d8bef9SDimitry Andric bool CSKYAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
170e8d8bef9SDimitry Andric                                           const MCRelaxableFragment *DF,
171e8d8bef9SDimitry Andric                                           const MCAsmLayout &Layout) const {
172e8d8bef9SDimitry Andric   return false;
173e8d8bef9SDimitry Andric }
174e8d8bef9SDimitry Andric 
175e8d8bef9SDimitry Andric void CSKYAsmBackend::relaxInstruction(MCInst &Inst,
176e8d8bef9SDimitry Andric                                       const MCSubtargetInfo &STI) const {
177e8d8bef9SDimitry Andric   llvm_unreachable("CSKYAsmBackend::relaxInstruction() unimplemented");
178e8d8bef9SDimitry Andric }
179e8d8bef9SDimitry Andric 
180*349cc55cSDimitry Andric bool CSKYAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,
181*349cc55cSDimitry Andric                                   const MCSubtargetInfo *STI) const {
182e8d8bef9SDimitry Andric   if (Count % 2)
183e8d8bef9SDimitry Andric     return false;
184e8d8bef9SDimitry Andric 
185e8d8bef9SDimitry Andric   // MOV32 r0, r0
186e8d8bef9SDimitry Andric   while (Count >= 4) {
187e8d8bef9SDimitry Andric     OS.write("\xc4\x00\x48\x20", 4);
188e8d8bef9SDimitry Andric     Count -= 4;
189e8d8bef9SDimitry Andric   }
190e8d8bef9SDimitry Andric   // MOV16 r0, r0
191e8d8bef9SDimitry Andric   if (Count)
192e8d8bef9SDimitry Andric     OS.write("\x6c\x03", 2);
193e8d8bef9SDimitry Andric 
194e8d8bef9SDimitry Andric   return true;
195e8d8bef9SDimitry Andric }
196e8d8bef9SDimitry Andric 
197e8d8bef9SDimitry Andric MCAsmBackend *llvm::createCSKYAsmBackend(const Target &T,
198e8d8bef9SDimitry Andric                                          const MCSubtargetInfo &STI,
199e8d8bef9SDimitry Andric                                          const MCRegisterInfo &MRI,
200e8d8bef9SDimitry Andric                                          const MCTargetOptions &Options) {
201e8d8bef9SDimitry Andric   return new CSKYAsmBackend(STI, Options);
202e8d8bef9SDimitry Andric }
203