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:
AMDGPUAsmBackend(const Target & T)325f757f3fSDimitry Andric AMDGPUAsmBackend(const Target &T) : MCAsmBackend(llvm::endianness::little) {}
330b57cec5SDimitry Andric
getNumFixupKinds() const340b57cec5SDimitry 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
relaxInstruction(MCInst & Inst,const MCSubtargetInfo & STI) const625ffd83dbSDimitry 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
fixupNeedsRelaxation(const MCFixup & Fixup,uint64_t Value) const710b57cec5SDimitry 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
mayNeedRelaxation(const MCInst & Inst,const MCSubtargetInfo & STI) const790b57cec5SDimitry 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
getFixupKindNumBytes(unsigned Kind)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
adjustFixupValue(const MCFixup & Fixup,uint64_t Value,MCContext * Ctx)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
applyFixup(const MCAssembler & Asm,const MCFixup & Fixup,const MCValue & Target,MutableArrayRef<char> Data,uint64_t Value,bool IsResolved,const MCSubtargetInfo * STI) const1370b57cec5SDimitry 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>
getFixupKind(StringRef Name) const165bdd1243dSDimitry 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
getFixupKindInfo(MCFixupKind Kind) const1740b57cec5SDimitry 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
shouldForceRelocation(const MCAssembler &,const MCFixup & Fixup,const MCValue &,const MCSubtargetInfo * STI)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
getMinimumNopSize() const1990b57cec5SDimitry Andric unsigned AMDGPUAsmBackend::getMinimumNopSize() const {
2000b57cec5SDimitry Andric return 4;
2010b57cec5SDimitry Andric }
2020b57cec5SDimitry Andric
writeNopData(raw_ostream & OS,uint64_t Count,const MCSubtargetInfo * STI) const203349cc55cSDimitry 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:
ELFAMDGPUAsmBackend(const Target & T,const Triple & TT)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>
createObjectTargetWriter() const2540b57cec5SDimitry Andric createObjectTargetWriter() const override {
2557a6dacacSDimitry Andric return createAMDGPUELFObjectWriter(Is64Bit, OSABI, HasRelocationAddend);
2560b57cec5SDimitry Andric }
2570b57cec5SDimitry Andric };
2580b57cec5SDimitry Andric
2590b57cec5SDimitry Andric } // end anonymous namespace
2600b57cec5SDimitry Andric
createAMDGPUAsmBackend(const Target & T,const MCSubtargetInfo & STI,const MCRegisterInfo & MRI,const MCTargetOptions & Options)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