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