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