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