1 //===-- AMDGPUAsmBackend.cpp - AMDGPU 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 /// \file 8 //===----------------------------------------------------------------------===// 9 10 #include "MCTargetDesc/AMDGPUFixupKinds.h" 11 #include "MCTargetDesc/AMDGPUMCTargetDesc.h" 12 #include "Utils/AMDGPUBaseInfo.h" 13 #include "llvm/ADT/StringSwitch.h" 14 #include "llvm/BinaryFormat/ELF.h" 15 #include "llvm/MC/MCAsmBackend.h" 16 #include "llvm/MC/MCAsmInfo.h" 17 #include "llvm/MC/MCAssembler.h" 18 #include "llvm/MC/MCContext.h" 19 #include "llvm/MC/MCObjectWriter.h" 20 #include "llvm/MC/MCSubtargetInfo.h" 21 #include "llvm/MC/MCValue.h" 22 #include "llvm/MC/TargetRegistry.h" 23 #include "llvm/Support/EndianStream.h" 24 #include "llvm/TargetParser/TargetParser.h" 25 26 using namespace llvm; 27 using namespace llvm::AMDGPU; 28 29 namespace { 30 31 class AMDGPUAsmBackend : public MCAsmBackend { 32 public: 33 AMDGPUAsmBackend(const Target &T) : MCAsmBackend(llvm::endianness::little) {} 34 35 void applyFixup(const MCFragment &, const MCFixup &, const MCValue &Target, 36 MutableArrayRef<char> Data, uint64_t Value, 37 bool IsResolved) override; 38 bool fixupNeedsRelaxation(const MCFixup &Fixup, 39 uint64_t Value) const override; 40 41 void relaxInstruction(MCInst &Inst, 42 const MCSubtargetInfo &STI) const override; 43 44 bool mayNeedRelaxation(unsigned Opcode, ArrayRef<MCOperand> Operands, 45 const MCSubtargetInfo &STI) const override; 46 47 unsigned getMinimumNopSize() const override; 48 bool writeNopData(raw_ostream &OS, uint64_t Count, 49 const MCSubtargetInfo *STI) const override; 50 51 std::optional<MCFixupKind> getFixupKind(StringRef Name) const override; 52 MCFixupKindInfo getFixupKindInfo(MCFixupKind Kind) const override; 53 }; 54 55 } //End anonymous namespace 56 57 void AMDGPUAsmBackend::relaxInstruction(MCInst &Inst, 58 const MCSubtargetInfo &STI) const { 59 MCInst Res; 60 unsigned RelaxedOpcode = AMDGPU::getSOPPWithRelaxation(Inst.getOpcode()); 61 Res.setOpcode(RelaxedOpcode); 62 Res.addOperand(Inst.getOperand(0)); 63 Inst = std::move(Res); 64 } 65 66 bool AMDGPUAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup, 67 uint64_t Value) const { 68 // if the branch target has an offset of x3f this needs to be relaxed to 69 // add a s_nop 0 immediately after branch to effectively increment offset 70 // for hardware workaround in gfx1010 71 return (((int64_t(Value)/4)-1) == 0x3f); 72 } 73 74 bool AMDGPUAsmBackend::mayNeedRelaxation(unsigned Opcode, 75 ArrayRef<MCOperand> Operands, 76 const MCSubtargetInfo &STI) const { 77 if (!STI.hasFeature(AMDGPU::FeatureOffset3fBug)) 78 return false; 79 80 if (AMDGPU::getSOPPWithRelaxation(Opcode) >= 0) 81 return true; 82 83 return false; 84 } 85 86 static unsigned getFixupKindNumBytes(unsigned Kind) { 87 switch (Kind) { 88 case AMDGPU::fixup_si_sopp_br: 89 return 2; 90 case FK_SecRel_1: 91 case FK_Data_1: 92 return 1; 93 case FK_SecRel_2: 94 case FK_Data_2: 95 return 2; 96 case FK_SecRel_4: 97 case FK_Data_4: 98 return 4; 99 case FK_SecRel_8: 100 case FK_Data_8: 101 return 8; 102 default: 103 llvm_unreachable("Unknown fixup kind!"); 104 } 105 } 106 107 static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value, 108 MCContext *Ctx) { 109 int64_t SignedValue = static_cast<int64_t>(Value); 110 111 switch (Fixup.getKind()) { 112 case AMDGPU::fixup_si_sopp_br: { 113 int64_t BrImm = (SignedValue - 4) / 4; 114 115 if (Ctx && !isInt<16>(BrImm)) 116 Ctx->reportError(Fixup.getLoc(), "branch size exceeds simm16"); 117 118 return BrImm; 119 } 120 case FK_Data_1: 121 case FK_Data_2: 122 case FK_Data_4: 123 case FK_Data_8: 124 case FK_SecRel_4: 125 return Value; 126 default: 127 llvm_unreachable("unhandled fixup kind"); 128 } 129 } 130 131 void AMDGPUAsmBackend::applyFixup(const MCFragment &F, const MCFixup &Fixup, 132 const MCValue &Target, 133 MutableArrayRef<char> Data, uint64_t Value, 134 bool IsResolved) { 135 if (Target.getSpecifier()) 136 IsResolved = false; 137 maybeAddReloc(F, Fixup, Target, Value, IsResolved); 138 if (mc::isRelocation(Fixup.getKind())) 139 return; 140 141 Value = adjustFixupValue(Fixup, Value, &getContext()); 142 if (!Value) 143 return; // Doesn't change encoding. 144 145 MCFixupKindInfo Info = getFixupKindInfo(Fixup.getKind()); 146 147 // Shift the value into position. 148 Value <<= Info.TargetOffset; 149 150 unsigned NumBytes = getFixupKindNumBytes(Fixup.getKind()); 151 uint32_t Offset = Fixup.getOffset(); 152 assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!"); 153 154 // For each byte of the fragment that the fixup touches, mask in the bits from 155 // the fixup value. 156 for (unsigned i = 0; i != NumBytes; ++i) 157 Data[Offset + i] |= static_cast<uint8_t>((Value >> (i * 8)) & 0xff); 158 } 159 160 std::optional<MCFixupKind> 161 AMDGPUAsmBackend::getFixupKind(StringRef Name) const { 162 auto Type = StringSwitch<unsigned>(Name) 163 #define ELF_RELOC(Name, Value) .Case(#Name, Value) 164 #include "llvm/BinaryFormat/ELFRelocs/AMDGPU.def" 165 #undef ELF_RELOC 166 .Case("BFD_RELOC_NONE", ELF::R_AMDGPU_NONE) 167 .Case("BFD_RELOC_32", ELF::R_AMDGPU_ABS32) 168 .Case("BFD_RELOC_64", ELF::R_AMDGPU_ABS64) 169 .Default(-1u); 170 if (Type != -1u) 171 return static_cast<MCFixupKind>(FirstLiteralRelocationKind + Type); 172 return std::nullopt; 173 } 174 175 MCFixupKindInfo AMDGPUAsmBackend::getFixupKindInfo(MCFixupKind Kind) const { 176 const static MCFixupKindInfo Infos[AMDGPU::NumTargetFixupKinds] = { 177 // name offset bits flags 178 {"fixup_si_sopp_br", 0, 16, 0}, 179 }; 180 181 if (mc::isRelocation(Kind)) 182 return {}; 183 184 if (Kind < FirstTargetFixupKind) 185 return MCAsmBackend::getFixupKindInfo(Kind); 186 187 assert(unsigned(Kind - FirstTargetFixupKind) < AMDGPU::NumTargetFixupKinds && 188 "Invalid kind!"); 189 return Infos[Kind - FirstTargetFixupKind]; 190 } 191 192 unsigned AMDGPUAsmBackend::getMinimumNopSize() const { 193 return 4; 194 } 195 196 bool AMDGPUAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count, 197 const MCSubtargetInfo *STI) const { 198 // If the count is not aligned to the minimum instruction alignment, we must 199 // be writing data into the text section (otherwise we have unaligned 200 // instructions, and thus have far bigger problems), so just write zeros 201 // instead. 202 unsigned MinInstAlignment = getContext().getAsmInfo()->getMinInstAlignment(); 203 OS.write_zeros(Count % MinInstAlignment); 204 205 // We are properly aligned, so write NOPs as requested. 206 Count /= MinInstAlignment; 207 208 // FIXME: R600 support. 209 // s_nop 0 210 const uint32_t Encoded_S_NOP_0 = 0xbf800000; 211 212 assert(MinInstAlignment == sizeof(Encoded_S_NOP_0)); 213 for (uint64_t I = 0; I != Count; ++I) 214 support::endian::write<uint32_t>(OS, Encoded_S_NOP_0, Endian); 215 216 return true; 217 } 218 219 //===----------------------------------------------------------------------===// 220 // ELFAMDGPUAsmBackend class 221 //===----------------------------------------------------------------------===// 222 223 namespace { 224 225 class ELFAMDGPUAsmBackend : public AMDGPUAsmBackend { 226 bool Is64Bit; 227 bool HasRelocationAddend; 228 uint8_t OSABI = ELF::ELFOSABI_NONE; 229 230 public: 231 ELFAMDGPUAsmBackend(const Target &T, const Triple &TT) 232 : AMDGPUAsmBackend(T), Is64Bit(TT.isAMDGCN()), 233 HasRelocationAddend(TT.getOS() == Triple::AMDHSA) { 234 switch (TT.getOS()) { 235 case Triple::AMDHSA: 236 OSABI = ELF::ELFOSABI_AMDGPU_HSA; 237 break; 238 case Triple::AMDPAL: 239 OSABI = ELF::ELFOSABI_AMDGPU_PAL; 240 break; 241 case Triple::Mesa3D: 242 OSABI = ELF::ELFOSABI_AMDGPU_MESA3D; 243 break; 244 default: 245 break; 246 } 247 } 248 249 std::unique_ptr<MCObjectTargetWriter> 250 createObjectTargetWriter() const override { 251 return createAMDGPUELFObjectWriter(Is64Bit, OSABI, HasRelocationAddend); 252 } 253 }; 254 255 } // end anonymous namespace 256 257 MCAsmBackend *llvm::createAMDGPUAsmBackend(const Target &T, 258 const MCSubtargetInfo &STI, 259 const MCRegisterInfo &MRI, 260 const MCTargetOptions &Options) { 261 return new ELFAMDGPUAsmBackend(T, STI.getTargetTriple()); 262 } 263