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