1 //===-- RISCVAsmBackend.cpp - RISCV Assembler Backend ---------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "MCTargetDesc/RISCVFixupKinds.h" 11 #include "MCTargetDesc/RISCVMCTargetDesc.h" 12 #include "llvm/ADT/APInt.h" 13 #include "llvm/MC/MCAsmBackend.h" 14 #include "llvm/MC/MCAssembler.h" 15 #include "llvm/MC/MCContext.h" 16 #include "llvm/MC/MCDirectives.h" 17 #include "llvm/MC/MCELFObjectWriter.h" 18 #include "llvm/MC/MCExpr.h" 19 #include "llvm/MC/MCFixupKindInfo.h" 20 #include "llvm/MC/MCObjectWriter.h" 21 #include "llvm/MC/MCSubtargetInfo.h" 22 #include "llvm/MC/MCSymbol.h" 23 #include "llvm/Support/ErrorHandling.h" 24 #include "llvm/Support/raw_ostream.h" 25 26 using namespace llvm; 27 28 namespace { 29 class RISCVAsmBackend : public MCAsmBackend { 30 const MCSubtargetInfo &STI; 31 uint8_t OSABI; 32 bool Is64Bit; 33 34 public: 35 RISCVAsmBackend(const MCSubtargetInfo &STI, uint8_t OSABI, bool Is64Bit) 36 : MCAsmBackend(), STI(STI), OSABI(OSABI), Is64Bit(Is64Bit) {} 37 ~RISCVAsmBackend() override {} 38 39 void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, 40 const MCValue &Target, MutableArrayRef<char> Data, 41 uint64_t Value, bool IsResolved) const override; 42 43 std::unique_ptr<MCObjectWriter> 44 createObjectWriter(raw_pwrite_stream &OS) const override; 45 46 bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value, 47 const MCRelaxableFragment *DF, 48 const MCAsmLayout &Layout) const override { 49 return false; 50 } 51 52 unsigned getNumFixupKinds() const override { 53 return RISCV::NumTargetFixupKinds; 54 } 55 56 const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override { 57 const static MCFixupKindInfo Infos[RISCV::NumTargetFixupKinds] = { 58 // This table *must* be in the order that the fixup_* kinds are defined in 59 // RISCVFixupKinds.h. 60 // 61 // name offset bits flags 62 { "fixup_riscv_hi20", 12, 20, 0 }, 63 { "fixup_riscv_lo12_i", 20, 12, 0 }, 64 { "fixup_riscv_lo12_s", 0, 32, 0 }, 65 { "fixup_riscv_pcrel_hi20", 12, 20, MCFixupKindInfo::FKF_IsPCRel }, 66 { "fixup_riscv_pcrel_lo12_i", 20, 12, MCFixupKindInfo::FKF_IsPCRel }, 67 { "fixup_riscv_pcrel_lo12_s", 0, 32, MCFixupKindInfo::FKF_IsPCRel }, 68 { "fixup_riscv_jal", 12, 20, MCFixupKindInfo::FKF_IsPCRel }, 69 { "fixup_riscv_branch", 0, 32, MCFixupKindInfo::FKF_IsPCRel }, 70 { "fixup_riscv_rvc_jump", 2, 11, MCFixupKindInfo::FKF_IsPCRel }, 71 { "fixup_riscv_rvc_branch", 0, 16, MCFixupKindInfo::FKF_IsPCRel } 72 }; 73 74 if (Kind < FirstTargetFixupKind) 75 return MCAsmBackend::getFixupKindInfo(Kind); 76 77 assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() && 78 "Invalid kind!"); 79 return Infos[Kind - FirstTargetFixupKind]; 80 } 81 82 bool mayNeedRelaxation(const MCInst &Inst) const override { return false; } 83 84 void relaxInstruction(const MCInst &Inst, const MCSubtargetInfo &STI, 85 MCInst &Res) const override { 86 87 report_fatal_error("RISCVAsmBackend::relaxInstruction() unimplemented"); 88 } 89 90 bool writeNopData(uint64_t Count, MCObjectWriter *OW) const override; 91 }; 92 93 bool RISCVAsmBackend::writeNopData(uint64_t Count, MCObjectWriter *OW) const { 94 bool HasStdExtC = STI.getFeatureBits()[RISCV::FeatureStdExtC]; 95 unsigned MinNopLen = HasStdExtC ? 2 : 4; 96 97 if ((Count % MinNopLen) != 0) 98 return false; 99 100 // The canonical nop on RISC-V is addi x0, x0, 0. 101 uint64_t Nop32Count = Count / 4; 102 for (uint64_t i = Nop32Count; i != 0; --i) 103 OW->write32(0x13); 104 105 // The canonical nop on RVC is c.nop. 106 if (HasStdExtC) { 107 uint64_t Nop16Count = (Count - Nop32Count * 4) / 2; 108 for (uint64_t i = Nop16Count; i != 0; --i) 109 OW->write16(0x01); 110 } 111 112 return true; 113 } 114 115 static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value, 116 MCContext &Ctx) { 117 unsigned Kind = Fixup.getKind(); 118 switch (Kind) { 119 default: 120 llvm_unreachable("Unknown fixup kind!"); 121 case FK_Data_1: 122 case FK_Data_2: 123 case FK_Data_4: 124 case FK_Data_8: 125 return Value; 126 case RISCV::fixup_riscv_lo12_i: 127 case RISCV::fixup_riscv_pcrel_lo12_i: 128 return Value & 0xfff; 129 case RISCV::fixup_riscv_lo12_s: 130 case RISCV::fixup_riscv_pcrel_lo12_s: 131 return (((Value >> 5) & 0x7f) << 25) | ((Value & 0x1f) << 7); 132 case RISCV::fixup_riscv_hi20: 133 case RISCV::fixup_riscv_pcrel_hi20: 134 // Add 1 if bit 11 is 1, to compensate for low 12 bits being negative. 135 return ((Value + 0x800) >> 12) & 0xfffff; 136 case RISCV::fixup_riscv_jal: { 137 if (!isInt<21>(Value)) 138 Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); 139 if (Value & 0x1) 140 Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned"); 141 // Need to produce imm[19|10:1|11|19:12] from the 21-bit Value. 142 unsigned Sbit = (Value >> 20) & 0x1; 143 unsigned Hi8 = (Value >> 12) & 0xff; 144 unsigned Mid1 = (Value >> 11) & 0x1; 145 unsigned Lo10 = (Value >> 1) & 0x3ff; 146 // Inst{31} = Sbit; 147 // Inst{30-21} = Lo10; 148 // Inst{20} = Mid1; 149 // Inst{19-12} = Hi8; 150 Value = (Sbit << 19) | (Lo10 << 9) | (Mid1 << 8) | Hi8; 151 return Value; 152 } 153 case RISCV::fixup_riscv_branch: { 154 if (!isInt<13>(Value)) 155 Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); 156 if (Value & 0x1) 157 Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned"); 158 // Need to extract imm[12], imm[10:5], imm[4:1], imm[11] from the 13-bit 159 // Value. 160 unsigned Sbit = (Value >> 12) & 0x1; 161 unsigned Hi1 = (Value >> 11) & 0x1; 162 unsigned Mid6 = (Value >> 5) & 0x3f; 163 unsigned Lo4 = (Value >> 1) & 0xf; 164 // Inst{31} = Sbit; 165 // Inst{30-25} = Mid6; 166 // Inst{11-8} = Lo4; 167 // Inst{7} = Hi1; 168 Value = (Sbit << 31) | (Mid6 << 25) | (Lo4 << 8) | (Hi1 << 7); 169 return Value; 170 } 171 case RISCV::fixup_riscv_rvc_jump: { 172 // Need to produce offset[11|4|9:8|10|6|7|3:1|5] from the 11-bit Value. 173 unsigned Bit11 = (Value >> 11) & 0x1; 174 unsigned Bit4 = (Value >> 4) & 0x1; 175 unsigned Bit9_8 = (Value >> 8) & 0x3; 176 unsigned Bit10 = (Value >> 10) & 0x1; 177 unsigned Bit6 = (Value >> 6) & 0x1; 178 unsigned Bit7 = (Value >> 7) & 0x1; 179 unsigned Bit3_1 = (Value >> 1) & 0x7; 180 unsigned Bit5 = (Value >> 5) & 0x1; 181 Value = (Bit11 << 10) | (Bit4 << 9) | (Bit9_8 << 7) | (Bit10 << 6) | 182 (Bit6 << 5) | (Bit7 << 4) | (Bit3_1 << 1) | Bit5; 183 return Value; 184 } 185 case RISCV::fixup_riscv_rvc_branch: { 186 // Need to produce offset[8|4:3], [reg 3 bit], offset[7:6|2:1|5] 187 unsigned Bit8 = (Value >> 8) & 0x1; 188 unsigned Bit7_6 = (Value >> 6) & 0x3; 189 unsigned Bit5 = (Value >> 5) & 0x1; 190 unsigned Bit4_3 = (Value >> 3) & 0x3; 191 unsigned Bit2_1 = (Value >> 1) & 0x3; 192 Value = (Bit8 << 12) | (Bit4_3 << 10) | (Bit7_6 << 5) | (Bit2_1 << 3) | 193 (Bit5 << 2); 194 return Value; 195 } 196 197 } 198 } 199 200 static unsigned getSize(unsigned Kind) { 201 switch (Kind) { 202 default: 203 return 4; 204 case RISCV::fixup_riscv_rvc_jump: 205 case RISCV::fixup_riscv_rvc_branch: 206 return 2; 207 } 208 } 209 210 void RISCVAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, 211 const MCValue &Target, 212 MutableArrayRef<char> Data, uint64_t Value, 213 bool IsResolved) const { 214 MCContext &Ctx = Asm.getContext(); 215 MCFixupKindInfo Info = getFixupKindInfo(Fixup.getKind()); 216 if (!Value) 217 return; // Doesn't change encoding. 218 // Apply any target-specific value adjustments. 219 Value = adjustFixupValue(Fixup, Value, Ctx); 220 221 // Shift the value into position. 222 Value <<= Info.TargetOffset; 223 224 unsigned Offset = Fixup.getOffset(); 225 unsigned FullSize = getSize(Fixup.getKind()); 226 227 #ifndef NDEBUG 228 unsigned NumBytes = (Info.TargetSize + 7) / 8; 229 assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!"); 230 #endif 231 232 // For each byte of the fragment that the fixup touches, mask in the 233 // bits from the fixup value. 234 for (unsigned i = 0; i != FullSize; ++i) { 235 Data[Offset + i] |= uint8_t((Value >> (i * 8)) & 0xff); 236 } 237 } 238 239 std::unique_ptr<MCObjectWriter> 240 RISCVAsmBackend::createObjectWriter(raw_pwrite_stream &OS) const { 241 return createRISCVELFObjectWriter(OS, OSABI, Is64Bit); 242 } 243 244 } // end anonymous namespace 245 246 MCAsmBackend *llvm::createRISCVAsmBackend(const Target &T, 247 const MCSubtargetInfo &STI, 248 const MCRegisterInfo &MRI, 249 const MCTargetOptions &Options) { 250 const Triple &TT = STI.getTargetTriple(); 251 uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TT.getOS()); 252 return new RISCVAsmBackend(STI, OSABI, TT.isArch64Bit()); 253 } 254