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