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 }; 68 69 if (Kind < FirstTargetFixupKind) 70 return MCAsmBackend::getFixupKindInfo(Kind); 71 72 assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() && 73 "Invalid kind!"); 74 return Infos[Kind - FirstTargetFixupKind]; 75 } 76 77 bool mayNeedRelaxation(const MCInst &Inst) const override { return false; } 78 79 void relaxInstruction(const MCInst &Inst, const MCSubtargetInfo &STI, 80 MCInst &Res) const override { 81 82 report_fatal_error("RISCVAsmBackend::relaxInstruction() unimplemented"); 83 } 84 85 bool writeNopData(uint64_t Count, MCObjectWriter *OW) const override; 86 }; 87 88 bool RISCVAsmBackend::writeNopData(uint64_t Count, MCObjectWriter *OW) const { 89 // Once support for the compressed instruction set is added, we will be able 90 // to conditionally support 16-bit NOPs 91 if ((Count % 4) != 0) 92 return false; 93 94 // The canonical nop on RISC-V is addi x0, x0, 0 95 for (uint64_t i = 0; i < Count; i += 4) 96 OW->write32(0x13); 97 98 return true; 99 } 100 101 static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value, 102 MCContext &Ctx) { 103 unsigned Kind = Fixup.getKind(); 104 switch (Kind) { 105 default: 106 llvm_unreachable("Unknown fixup kind!"); 107 case FK_Data_1: 108 case FK_Data_2: 109 case FK_Data_4: 110 case FK_Data_8: 111 return Value; 112 case RISCV::fixup_riscv_lo12_i: 113 return Value & 0xfff; 114 case RISCV::fixup_riscv_lo12_s: 115 return (((Value >> 5) & 0x7f) << 25) | ((Value & 0x1f) << 7); 116 case RISCV::fixup_riscv_hi20: 117 case RISCV::fixup_riscv_pcrel_hi20: 118 // Add 1 if bit 11 is 1, to compensate for low 12 bits being negative. 119 return ((Value + 0x800) >> 12) & 0xfffff; 120 case RISCV::fixup_riscv_jal: { 121 if (!isInt<21>(Value)) 122 Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); 123 if (Value & 0x1) 124 Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned"); 125 // Need to produce imm[19|10:1|11|19:12] from the 21-bit Value. 126 unsigned Sbit = (Value >> 20) & 0x1; 127 unsigned Hi8 = (Value >> 12) & 0xff; 128 unsigned Mid1 = (Value >> 11) & 0x1; 129 unsigned Lo10 = (Value >> 1) & 0x3ff; 130 // Inst{31} = Sbit; 131 // Inst{30-21} = Lo10; 132 // Inst{20} = Mid1; 133 // Inst{19-12} = Hi8; 134 Value = (Sbit << 19) | (Lo10 << 9) | (Mid1 << 8) | Hi8; 135 return Value; 136 } 137 case RISCV::fixup_riscv_branch: { 138 if (!isInt<13>(Value)) 139 Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); 140 if (Value & 0x1) 141 Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned"); 142 // Need to extract imm[12], imm[10:5], imm[4:1], imm[11] from the 13-bit 143 // Value. 144 unsigned Sbit = (Value >> 12) & 0x1; 145 unsigned Hi1 = (Value >> 11) & 0x1; 146 unsigned Mid6 = (Value >> 5) & 0x3f; 147 unsigned Lo4 = (Value >> 1) & 0xf; 148 // Inst{31} = Sbit; 149 // Inst{30-25} = Mid6; 150 // Inst{11-8} = Lo4; 151 // Inst{7} = Hi1; 152 Value = (Sbit << 31) | (Mid6 << 25) | (Lo4 << 8) | (Hi1 << 7); 153 return Value; 154 } 155 156 } 157 } 158 159 void RISCVAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, 160 const MCValue &Target, 161 MutableArrayRef<char> Data, uint64_t Value, 162 bool IsResolved) const { 163 MCContext &Ctx = Asm.getContext(); 164 MCFixupKind Kind = Fixup.getKind(); 165 unsigned NumBytes = (getFixupKindInfo(Kind).TargetSize + 7) / 8; 166 if (!Value) 167 return; // Doesn't change encoding. 168 MCFixupKindInfo Info = getFixupKindInfo(Fixup.getKind()); 169 // Apply any target-specific value adjustments. 170 Value = adjustFixupValue(Fixup, Value, Ctx); 171 172 // Shift the value into position. 173 Value <<= Info.TargetOffset; 174 175 unsigned Offset = Fixup.getOffset(); 176 assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!"); 177 178 // For each byte of the fragment that the fixup touches, mask in the 179 // bits from the fixup value. 180 for (unsigned i = 0; i != 4; ++i) { 181 Data[Offset + i] |= uint8_t((Value >> (i * 8)) & 0xff); 182 } 183 return; 184 } 185 186 std::unique_ptr<MCObjectWriter> 187 RISCVAsmBackend::createObjectWriter(raw_pwrite_stream &OS) const { 188 return createRISCVELFObjectWriter(OS, OSABI, Is64Bit); 189 } 190 191 } // end anonymous namespace 192 193 MCAsmBackend *llvm::createRISCVAsmBackend(const Target &T, 194 const MCRegisterInfo &MRI, 195 const Triple &TT, StringRef CPU, 196 const MCTargetOptions &Options) { 197 uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TT.getOS()); 198 return new RISCVAsmBackend(OSABI, TT.isArch64Bit()); 199 } 200