10b57cec5SDimitry Andric //===-- AMDGPUAsmBackend.cpp - AMDGPU Assembler Backend -------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric /// \file 80b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 90b57cec5SDimitry Andric 100b57cec5SDimitry Andric #include "MCTargetDesc/AMDGPUFixupKinds.h" 110b57cec5SDimitry Andric #include "MCTargetDesc/AMDGPUMCTargetDesc.h" 12e8d8bef9SDimitry Andric #include "Utils/AMDGPUBaseInfo.h" 13*0fca6ea1SDimitry Andric #include "llvm/ADT/StringSwitch.h" 1481ad6265SDimitry Andric #include "llvm/BinaryFormat/ELF.h" 150b57cec5SDimitry Andric #include "llvm/MC/MCAsmBackend.h" 160b57cec5SDimitry Andric #include "llvm/MC/MCAssembler.h" 170b57cec5SDimitry Andric #include "llvm/MC/MCContext.h" 180b57cec5SDimitry Andric #include "llvm/MC/MCFixupKindInfo.h" 190b57cec5SDimitry Andric #include "llvm/MC/MCObjectWriter.h" 2081ad6265SDimitry Andric #include "llvm/MC/MCSubtargetInfo.h" 21349cc55cSDimitry Andric #include "llvm/MC/TargetRegistry.h" 225ffd83dbSDimitry Andric #include "llvm/Support/EndianStream.h" 2306c3fb27SDimitry Andric #include "llvm/TargetParser/TargetParser.h" 240b57cec5SDimitry Andric 250b57cec5SDimitry Andric using namespace llvm; 260b57cec5SDimitry Andric using namespace llvm::AMDGPU; 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric namespace { 290b57cec5SDimitry Andric 300b57cec5SDimitry Andric class AMDGPUAsmBackend : public MCAsmBackend { 310b57cec5SDimitry Andric public: 325f757f3fSDimitry Andric AMDGPUAsmBackend(const Target &T) : MCAsmBackend(llvm::endianness::little) {} 330b57cec5SDimitry Andric 340b57cec5SDimitry Andric unsigned getNumFixupKinds() const override { return AMDGPU::NumTargetFixupKinds; }; 350b57cec5SDimitry Andric 360b57cec5SDimitry Andric void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, 370b57cec5SDimitry Andric const MCValue &Target, MutableArrayRef<char> Data, 380b57cec5SDimitry Andric uint64_t Value, bool IsResolved, 390b57cec5SDimitry Andric const MCSubtargetInfo *STI) const override; 40*0fca6ea1SDimitry Andric bool fixupNeedsRelaxation(const MCFixup &Fixup, 41*0fca6ea1SDimitry Andric uint64_t Value) const override; 420b57cec5SDimitry Andric 435ffd83dbSDimitry Andric void relaxInstruction(MCInst &Inst, 445ffd83dbSDimitry Andric const MCSubtargetInfo &STI) const override; 450b57cec5SDimitry Andric 460b57cec5SDimitry Andric bool mayNeedRelaxation(const MCInst &Inst, 470b57cec5SDimitry Andric const MCSubtargetInfo &STI) const override; 480b57cec5SDimitry Andric 490b57cec5SDimitry Andric unsigned getMinimumNopSize() const override; 50349cc55cSDimitry Andric bool writeNopData(raw_ostream &OS, uint64_t Count, 51349cc55cSDimitry Andric const MCSubtargetInfo *STI) const override; 520b57cec5SDimitry Andric 53bdd1243dSDimitry Andric std::optional<MCFixupKind> getFixupKind(StringRef Name) const override; 540b57cec5SDimitry Andric const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override; 5581ad6265SDimitry Andric bool shouldForceRelocation(const MCAssembler &Asm, const MCFixup &Fixup, 565f757f3fSDimitry Andric const MCValue &Target, 575f757f3fSDimitry Andric const MCSubtargetInfo *STI) override; 580b57cec5SDimitry Andric }; 590b57cec5SDimitry Andric 600b57cec5SDimitry Andric } //End anonymous namespace 610b57cec5SDimitry Andric 625ffd83dbSDimitry Andric void AMDGPUAsmBackend::relaxInstruction(MCInst &Inst, 635ffd83dbSDimitry Andric const MCSubtargetInfo &STI) const { 645ffd83dbSDimitry Andric MCInst Res; 650b57cec5SDimitry Andric unsigned RelaxedOpcode = AMDGPU::getSOPPWithRelaxation(Inst.getOpcode()); 660b57cec5SDimitry Andric Res.setOpcode(RelaxedOpcode); 670b57cec5SDimitry Andric Res.addOperand(Inst.getOperand(0)); 685ffd83dbSDimitry Andric Inst = std::move(Res); 690b57cec5SDimitry Andric } 700b57cec5SDimitry Andric 710b57cec5SDimitry Andric bool AMDGPUAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup, 72*0fca6ea1SDimitry Andric uint64_t Value) const { 730b57cec5SDimitry Andric // if the branch target has an offset of x3f this needs to be relaxed to 740b57cec5SDimitry Andric // add a s_nop 0 immediately after branch to effectively increment offset 750b57cec5SDimitry Andric // for hardware workaround in gfx1010 760b57cec5SDimitry Andric return (((int64_t(Value)/4)-1) == 0x3f); 770b57cec5SDimitry Andric } 780b57cec5SDimitry Andric 790b57cec5SDimitry Andric bool AMDGPUAsmBackend::mayNeedRelaxation(const MCInst &Inst, 800b57cec5SDimitry Andric const MCSubtargetInfo &STI) const { 8106c3fb27SDimitry Andric if (!STI.hasFeature(AMDGPU::FeatureOffset3fBug)) 820b57cec5SDimitry Andric return false; 830b57cec5SDimitry Andric 840b57cec5SDimitry Andric if (AMDGPU::getSOPPWithRelaxation(Inst.getOpcode()) >= 0) 850b57cec5SDimitry Andric return true; 860b57cec5SDimitry Andric 870b57cec5SDimitry Andric return false; 880b57cec5SDimitry Andric } 890b57cec5SDimitry Andric 900b57cec5SDimitry Andric static unsigned getFixupKindNumBytes(unsigned Kind) { 910b57cec5SDimitry Andric switch (Kind) { 920b57cec5SDimitry Andric case AMDGPU::fixup_si_sopp_br: 930b57cec5SDimitry Andric return 2; 940b57cec5SDimitry Andric case FK_SecRel_1: 950b57cec5SDimitry Andric case FK_Data_1: 960b57cec5SDimitry Andric return 1; 970b57cec5SDimitry Andric case FK_SecRel_2: 980b57cec5SDimitry Andric case FK_Data_2: 990b57cec5SDimitry Andric return 2; 1000b57cec5SDimitry Andric case FK_SecRel_4: 1010b57cec5SDimitry Andric case FK_Data_4: 1020b57cec5SDimitry Andric case FK_PCRel_4: 1030b57cec5SDimitry Andric return 4; 1040b57cec5SDimitry Andric case FK_SecRel_8: 1050b57cec5SDimitry Andric case FK_Data_8: 1060b57cec5SDimitry Andric return 8; 1070b57cec5SDimitry Andric default: 1080b57cec5SDimitry Andric llvm_unreachable("Unknown fixup kind!"); 1090b57cec5SDimitry Andric } 1100b57cec5SDimitry Andric } 1110b57cec5SDimitry Andric 1120b57cec5SDimitry Andric static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value, 1130b57cec5SDimitry Andric MCContext *Ctx) { 1140b57cec5SDimitry Andric int64_t SignedValue = static_cast<int64_t>(Value); 1150b57cec5SDimitry Andric 1168bcb0991SDimitry Andric switch (Fixup.getTargetKind()) { 1170b57cec5SDimitry Andric case AMDGPU::fixup_si_sopp_br: { 1180b57cec5SDimitry Andric int64_t BrImm = (SignedValue - 4) / 4; 1190b57cec5SDimitry Andric 1200b57cec5SDimitry Andric if (Ctx && !isInt<16>(BrImm)) 1210b57cec5SDimitry Andric Ctx->reportError(Fixup.getLoc(), "branch size exceeds simm16"); 1220b57cec5SDimitry Andric 1230b57cec5SDimitry Andric return BrImm; 1240b57cec5SDimitry Andric } 1250b57cec5SDimitry Andric case FK_Data_1: 1260b57cec5SDimitry Andric case FK_Data_2: 1270b57cec5SDimitry Andric case FK_Data_4: 1280b57cec5SDimitry Andric case FK_Data_8: 1290b57cec5SDimitry Andric case FK_PCRel_4: 1300b57cec5SDimitry Andric case FK_SecRel_4: 1310b57cec5SDimitry Andric return Value; 1320b57cec5SDimitry Andric default: 1330b57cec5SDimitry Andric llvm_unreachable("unhandled fixup kind"); 1340b57cec5SDimitry Andric } 1350b57cec5SDimitry Andric } 1360b57cec5SDimitry Andric 1370b57cec5SDimitry Andric void AMDGPUAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, 1380b57cec5SDimitry Andric const MCValue &Target, 1390b57cec5SDimitry Andric MutableArrayRef<char> Data, uint64_t Value, 1400b57cec5SDimitry Andric bool IsResolved, 1410b57cec5SDimitry Andric const MCSubtargetInfo *STI) const { 14281ad6265SDimitry Andric if (Fixup.getKind() >= FirstLiteralRelocationKind) 14381ad6265SDimitry Andric return; 14481ad6265SDimitry Andric 1450b57cec5SDimitry Andric Value = adjustFixupValue(Fixup, Value, &Asm.getContext()); 1460b57cec5SDimitry Andric if (!Value) 1470b57cec5SDimitry Andric return; // Doesn't change encoding. 1480b57cec5SDimitry Andric 1490b57cec5SDimitry Andric MCFixupKindInfo Info = getFixupKindInfo(Fixup.getKind()); 1500b57cec5SDimitry Andric 1510b57cec5SDimitry Andric // Shift the value into position. 1520b57cec5SDimitry Andric Value <<= Info.TargetOffset; 1530b57cec5SDimitry Andric 1540b57cec5SDimitry Andric unsigned NumBytes = getFixupKindNumBytes(Fixup.getKind()); 1550b57cec5SDimitry Andric uint32_t Offset = Fixup.getOffset(); 1560b57cec5SDimitry Andric assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!"); 1570b57cec5SDimitry Andric 1580b57cec5SDimitry Andric // For each byte of the fragment that the fixup touches, mask in the bits from 1590b57cec5SDimitry Andric // the fixup value. 1600b57cec5SDimitry Andric for (unsigned i = 0; i != NumBytes; ++i) 1610b57cec5SDimitry Andric Data[Offset + i] |= static_cast<uint8_t>((Value >> (i * 8)) & 0xff); 1620b57cec5SDimitry Andric } 1630b57cec5SDimitry Andric 164bdd1243dSDimitry Andric std::optional<MCFixupKind> 165bdd1243dSDimitry Andric AMDGPUAsmBackend::getFixupKind(StringRef Name) const { 166bdd1243dSDimitry Andric return StringSwitch<std::optional<MCFixupKind>>(Name) 16781ad6265SDimitry Andric #define ELF_RELOC(Name, Value) \ 16881ad6265SDimitry Andric .Case(#Name, MCFixupKind(FirstLiteralRelocationKind + Value)) 16981ad6265SDimitry Andric #include "llvm/BinaryFormat/ELFRelocs/AMDGPU.def" 17081ad6265SDimitry Andric #undef ELF_RELOC 171bdd1243dSDimitry Andric .Default(std::nullopt); 17281ad6265SDimitry Andric } 17381ad6265SDimitry Andric 1740b57cec5SDimitry Andric const MCFixupKindInfo &AMDGPUAsmBackend::getFixupKindInfo( 1750b57cec5SDimitry Andric MCFixupKind Kind) const { 1760b57cec5SDimitry Andric const static MCFixupKindInfo Infos[AMDGPU::NumTargetFixupKinds] = { 1770b57cec5SDimitry Andric // name offset bits flags 1780b57cec5SDimitry Andric { "fixup_si_sopp_br", 0, 16, MCFixupKindInfo::FKF_IsPCRel }, 1790b57cec5SDimitry Andric }; 1800b57cec5SDimitry Andric 18181ad6265SDimitry Andric if (Kind >= FirstLiteralRelocationKind) 18281ad6265SDimitry Andric return MCAsmBackend::getFixupKindInfo(FK_NONE); 18381ad6265SDimitry Andric 1840b57cec5SDimitry Andric if (Kind < FirstTargetFixupKind) 1850b57cec5SDimitry Andric return MCAsmBackend::getFixupKindInfo(Kind); 1860b57cec5SDimitry Andric 1875f757f3fSDimitry Andric assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() && 1885f757f3fSDimitry Andric "Invalid kind!"); 1890b57cec5SDimitry Andric return Infos[Kind - FirstTargetFixupKind]; 1900b57cec5SDimitry Andric } 1910b57cec5SDimitry Andric 19281ad6265SDimitry Andric bool AMDGPUAsmBackend::shouldForceRelocation(const MCAssembler &, 19381ad6265SDimitry Andric const MCFixup &Fixup, 1945f757f3fSDimitry Andric const MCValue &, 1955f757f3fSDimitry Andric const MCSubtargetInfo *STI) { 19681ad6265SDimitry Andric return Fixup.getKind() >= FirstLiteralRelocationKind; 19781ad6265SDimitry Andric } 19881ad6265SDimitry Andric 1990b57cec5SDimitry Andric unsigned AMDGPUAsmBackend::getMinimumNopSize() const { 2000b57cec5SDimitry Andric return 4; 2010b57cec5SDimitry Andric } 2020b57cec5SDimitry Andric 203349cc55cSDimitry Andric bool AMDGPUAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count, 204349cc55cSDimitry Andric const MCSubtargetInfo *STI) const { 2050b57cec5SDimitry Andric // If the count is not 4-byte aligned, we must be writing data into the text 2060b57cec5SDimitry Andric // section (otherwise we have unaligned instructions, and thus have far 2070b57cec5SDimitry Andric // bigger problems), so just write zeros instead. 2080b57cec5SDimitry Andric OS.write_zeros(Count % 4); 2090b57cec5SDimitry Andric 2100b57cec5SDimitry Andric // We are properly aligned, so write NOPs as requested. 2110b57cec5SDimitry Andric Count /= 4; 2120b57cec5SDimitry Andric 2130b57cec5SDimitry Andric // FIXME: R600 support. 2140b57cec5SDimitry Andric // s_nop 0 2150b57cec5SDimitry Andric const uint32_t Encoded_S_NOP_0 = 0xbf800000; 2160b57cec5SDimitry Andric 2170b57cec5SDimitry Andric for (uint64_t I = 0; I != Count; ++I) 2180b57cec5SDimitry Andric support::endian::write<uint32_t>(OS, Encoded_S_NOP_0, Endian); 2190b57cec5SDimitry Andric 2200b57cec5SDimitry Andric return true; 2210b57cec5SDimitry Andric } 2220b57cec5SDimitry Andric 2230b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 2240b57cec5SDimitry Andric // ELFAMDGPUAsmBackend class 2250b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 2260b57cec5SDimitry Andric 2270b57cec5SDimitry Andric namespace { 2280b57cec5SDimitry Andric 2290b57cec5SDimitry Andric class ELFAMDGPUAsmBackend : public AMDGPUAsmBackend { 2300b57cec5SDimitry Andric bool Is64Bit; 2310b57cec5SDimitry Andric bool HasRelocationAddend; 2320b57cec5SDimitry Andric uint8_t OSABI = ELF::ELFOSABI_NONE; 2330b57cec5SDimitry Andric 2340b57cec5SDimitry Andric public: 2357a6dacacSDimitry Andric ELFAMDGPUAsmBackend(const Target &T, const Triple &TT) 2367a6dacacSDimitry Andric : AMDGPUAsmBackend(T), Is64Bit(TT.getArch() == Triple::amdgcn), 2377a6dacacSDimitry Andric HasRelocationAddend(TT.getOS() == Triple::AMDHSA) { 2380b57cec5SDimitry Andric switch (TT.getOS()) { 2390b57cec5SDimitry Andric case Triple::AMDHSA: 2400b57cec5SDimitry Andric OSABI = ELF::ELFOSABI_AMDGPU_HSA; 2410b57cec5SDimitry Andric break; 2420b57cec5SDimitry Andric case Triple::AMDPAL: 2430b57cec5SDimitry Andric OSABI = ELF::ELFOSABI_AMDGPU_PAL; 2440b57cec5SDimitry Andric break; 2450b57cec5SDimitry Andric case Triple::Mesa3D: 2460b57cec5SDimitry Andric OSABI = ELF::ELFOSABI_AMDGPU_MESA3D; 2470b57cec5SDimitry Andric break; 2480b57cec5SDimitry Andric default: 2490b57cec5SDimitry Andric break; 2500b57cec5SDimitry Andric } 2510b57cec5SDimitry Andric } 2520b57cec5SDimitry Andric 2530b57cec5SDimitry Andric std::unique_ptr<MCObjectTargetWriter> 2540b57cec5SDimitry Andric createObjectTargetWriter() const override { 2557a6dacacSDimitry Andric return createAMDGPUELFObjectWriter(Is64Bit, OSABI, HasRelocationAddend); 2560b57cec5SDimitry Andric } 2570b57cec5SDimitry Andric }; 2580b57cec5SDimitry Andric 2590b57cec5SDimitry Andric } // end anonymous namespace 2600b57cec5SDimitry Andric 2610b57cec5SDimitry Andric MCAsmBackend *llvm::createAMDGPUAsmBackend(const Target &T, 2620b57cec5SDimitry Andric const MCSubtargetInfo &STI, 2630b57cec5SDimitry Andric const MCRegisterInfo &MRI, 2640b57cec5SDimitry Andric const MCTargetOptions &Options) { 2657a6dacacSDimitry Andric return new ELFAMDGPUAsmBackend(T, STI.getTargetTriple()); 2660b57cec5SDimitry Andric } 267