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_pcrel_imm16_scale2,
34        {"fixup_csky_pcrel_imm16_scale2", 0, 32, MCFixupKindInfo::FKF_IsPCRel}},
35       {CSKY::Fixups::fixup_csky_pcrel_uimm16_scale4,
36        {"fixup_csky_pcrel_uimm16_scale4", 0, 32, MCFixupKindInfo::FKF_IsPCRel}},
37       {CSKY::Fixups::fixup_csky_pcrel_imm26_scale2,
38        {"fixup_csky_pcrel_imm26_scale2", 0, 32, MCFixupKindInfo::FKF_IsPCRel}},
39       {CSKY::Fixups::fixup_csky_pcrel_imm18_scale2,
40        {"fixup_csky_pcrel_imm18_scale2", 0, 32, MCFixupKindInfo::FKF_IsPCRel}}};
41   assert(Infos.size() == CSKY::NumTargetFixupKinds &&
42          "Not all fixup kinds added to Infos array");
43 
44   assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() &&
45          "Invalid kind!");
46   if (FirstTargetFixupKind <= Kind && Kind < FirstLiteralRelocationKind)
47     return Infos[Kind];
48   else if (Kind < FirstTargetFixupKind)
49     return MCAsmBackend::getFixupKindInfo(Kind);
50   else
51     return MCAsmBackend::getFixupKindInfo(FK_NONE);
52 }
53 
54 static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
55                                  MCContext &Ctx) {
56   switch (Fixup.getTargetKind()) {
57   default:
58     llvm_unreachable("Unknown fixup kind!");
59   case FK_Data_1:
60   case FK_Data_2:
61   case FK_Data_4:
62   case FK_Data_8:
63     return Value;
64   case CSKY::fixup_csky_addr32:
65     return Value & 0xffffffff;
66   case CSKY::fixup_csky_pcrel_imm16_scale2:
67     if (!isIntN(17, Value))
68       Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value.");
69     if (Value & 0x1)
70       Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned.");
71 
72     return (Value >> 1) & 0xffff;
73   case CSKY::fixup_csky_pcrel_uimm16_scale4:
74     if (!isUIntN(18, Value))
75       Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value.");
76     if (Value & 0x3)
77       Ctx.reportError(Fixup.getLoc(), "fixup value must be 4-byte aligned.");
78 
79     return (Value >> 2) & 0xffff;
80   case CSKY::fixup_csky_pcrel_imm26_scale2:
81     if (!isIntN(27, Value))
82       Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value.");
83     if (Value & 0x1)
84       Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned.");
85 
86     return (Value >> 1) & 0x3ffffff;
87   case CSKY::fixup_csky_pcrel_imm18_scale2:
88     if (!isIntN(19, Value))
89       Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value.");
90     if (Value & 0x1)
91       Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned.");
92 
93     return (Value >> 1) & 0x3ffff;
94   }
95 }
96 
97 void CSKYAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
98                                 const MCValue &Target,
99                                 MutableArrayRef<char> Data, uint64_t Value,
100                                 bool IsResolved,
101                                 const MCSubtargetInfo *STI) const {
102   MCFixupKind Kind = Fixup.getKind();
103   if (Kind >= FirstLiteralRelocationKind)
104     return;
105   MCContext &Ctx = Asm.getContext();
106   MCFixupKindInfo Info = getFixupKindInfo(Kind);
107   if (!Value)
108     return; // Doesn't change encoding.
109   // Apply any target-specific value adjustments.
110   Value = adjustFixupValue(Fixup, Value, Ctx);
111 
112   // Shift the value into position.
113   Value <<= Info.TargetOffset;
114 
115   unsigned Offset = Fixup.getOffset();
116   unsigned NumBytes = alignTo(Info.TargetSize + Info.TargetOffset, 8) / 8;
117 
118   assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!");
119 
120   // For each byte of the fragment that the fixup touches, mask in the
121   // bits from the fixup value.
122   bool IsLittleEndian = (Endian == support::little);
123 
124   if (IsLittleEndian && (NumBytes == 4)) {
125     Data[Offset + 0] |= uint8_t((Value >> 16) & 0xff);
126     Data[Offset + 1] |= uint8_t((Value >> 24) & 0xff);
127     Data[Offset + 2] |= uint8_t(Value & 0xff);
128     Data[Offset + 3] |= uint8_t((Value >> 8) & 0xff);
129   } else {
130     for (unsigned I = 0; I != NumBytes; I++) {
131       unsigned Idx = IsLittleEndian ? I : (NumBytes - 1 - I);
132       Data[Offset + Idx] |= uint8_t((Value >> (I * 8)) & 0xff);
133     }
134   }
135 }
136 
137 bool CSKYAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
138                                           const MCRelaxableFragment *DF,
139                                           const MCAsmLayout &Layout) const {
140   return false;
141 }
142 
143 void CSKYAsmBackend::relaxInstruction(MCInst &Inst,
144                                       const MCSubtargetInfo &STI) const {
145   llvm_unreachable("CSKYAsmBackend::relaxInstruction() unimplemented");
146 }
147 
148 bool CSKYAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count) const {
149   if (Count % 2)
150     return false;
151 
152   // MOV32 r0, r0
153   while (Count >= 4) {
154     OS.write("\xc4\x00\x48\x20", 4);
155     Count -= 4;
156   }
157   // MOV16 r0, r0
158   if (Count)
159     OS.write("\x6c\x03", 2);
160 
161   return true;
162 }
163 
164 MCAsmBackend *llvm::createCSKYAsmBackend(const Target &T,
165                                          const MCSubtargetInfo &STI,
166                                          const MCRegisterInfo &MRI,
167                                          const MCTargetOptions &Options) {
168   return new CSKYAsmBackend(STI, Options);
169 }
170