109467b48Spatrick //===-- AMDGPUAsmBackend.cpp - AMDGPU Assembler Backend -------------------===//
209467b48Spatrick //
309467b48Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
409467b48Spatrick // See https://llvm.org/LICENSE.txt for license information.
509467b48Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
609467b48Spatrick //
709467b48Spatrick /// \file
809467b48Spatrick //===----------------------------------------------------------------------===//
909467b48Spatrick
1009467b48Spatrick #include "MCTargetDesc/AMDGPUFixupKinds.h"
1109467b48Spatrick #include "MCTargetDesc/AMDGPUMCTargetDesc.h"
1273471bf0Spatrick #include "Utils/AMDGPUBaseInfo.h"
13*d415bd75Srobert #include "llvm/BinaryFormat/ELF.h"
1409467b48Spatrick #include "llvm/MC/MCAsmBackend.h"
1509467b48Spatrick #include "llvm/MC/MCAssembler.h"
1609467b48Spatrick #include "llvm/MC/MCContext.h"
1709467b48Spatrick #include "llvm/MC/MCFixupKindInfo.h"
1809467b48Spatrick #include "llvm/MC/MCObjectWriter.h"
19*d415bd75Srobert #include "llvm/MC/MCSubtargetInfo.h"
20*d415bd75Srobert #include "llvm/MC/TargetRegistry.h"
21097a140dSpatrick #include "llvm/Support/EndianStream.h"
22*d415bd75Srobert #include "llvm/Support/TargetParser.h"
2309467b48Spatrick
2409467b48Spatrick using namespace llvm;
2509467b48Spatrick using namespace llvm::AMDGPU;
2609467b48Spatrick
2709467b48Spatrick namespace {
2809467b48Spatrick
2909467b48Spatrick class AMDGPUAsmBackend : public MCAsmBackend {
3009467b48Spatrick public:
AMDGPUAsmBackend(const Target & T)3109467b48Spatrick AMDGPUAsmBackend(const Target &T) : MCAsmBackend(support::little) {}
3209467b48Spatrick
getNumFixupKinds() const3309467b48Spatrick unsigned getNumFixupKinds() const override { return AMDGPU::NumTargetFixupKinds; };
3409467b48Spatrick
3509467b48Spatrick void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
3609467b48Spatrick const MCValue &Target, MutableArrayRef<char> Data,
3709467b48Spatrick uint64_t Value, bool IsResolved,
3809467b48Spatrick const MCSubtargetInfo *STI) const override;
3909467b48Spatrick bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
4009467b48Spatrick const MCRelaxableFragment *DF,
4109467b48Spatrick const MCAsmLayout &Layout) const override;
4209467b48Spatrick
43097a140dSpatrick void relaxInstruction(MCInst &Inst,
44097a140dSpatrick const MCSubtargetInfo &STI) const override;
4509467b48Spatrick
4609467b48Spatrick bool mayNeedRelaxation(const MCInst &Inst,
4709467b48Spatrick const MCSubtargetInfo &STI) const override;
4809467b48Spatrick
4909467b48Spatrick unsigned getMinimumNopSize() const override;
50*d415bd75Srobert bool writeNopData(raw_ostream &OS, uint64_t Count,
51*d415bd75Srobert const MCSubtargetInfo *STI) const override;
5209467b48Spatrick
53*d415bd75Srobert std::optional<MCFixupKind> getFixupKind(StringRef Name) const override;
5409467b48Spatrick const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override;
55*d415bd75Srobert bool shouldForceRelocation(const MCAssembler &Asm, const MCFixup &Fixup,
56*d415bd75Srobert const MCValue &Target) override;
5709467b48Spatrick };
5809467b48Spatrick
5909467b48Spatrick } //End anonymous namespace
6009467b48Spatrick
relaxInstruction(MCInst & Inst,const MCSubtargetInfo & STI) const61097a140dSpatrick void AMDGPUAsmBackend::relaxInstruction(MCInst &Inst,
62097a140dSpatrick const MCSubtargetInfo &STI) const {
63097a140dSpatrick MCInst Res;
6409467b48Spatrick unsigned RelaxedOpcode = AMDGPU::getSOPPWithRelaxation(Inst.getOpcode());
6509467b48Spatrick Res.setOpcode(RelaxedOpcode);
6609467b48Spatrick Res.addOperand(Inst.getOperand(0));
67097a140dSpatrick Inst = std::move(Res);
6809467b48Spatrick }
6909467b48Spatrick
fixupNeedsRelaxation(const MCFixup & Fixup,uint64_t Value,const MCRelaxableFragment * DF,const MCAsmLayout & Layout) const7009467b48Spatrick bool AMDGPUAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup,
7109467b48Spatrick uint64_t Value,
7209467b48Spatrick const MCRelaxableFragment *DF,
7309467b48Spatrick const MCAsmLayout &Layout) const {
7409467b48Spatrick // if the branch target has an offset of x3f this needs to be relaxed to
7509467b48Spatrick // add a s_nop 0 immediately after branch to effectively increment offset
7609467b48Spatrick // for hardware workaround in gfx1010
7709467b48Spatrick return (((int64_t(Value)/4)-1) == 0x3f);
7809467b48Spatrick }
7909467b48Spatrick
mayNeedRelaxation(const MCInst & Inst,const MCSubtargetInfo & STI) const8009467b48Spatrick bool AMDGPUAsmBackend::mayNeedRelaxation(const MCInst &Inst,
8109467b48Spatrick const MCSubtargetInfo &STI) const {
8209467b48Spatrick if (!STI.getFeatureBits()[AMDGPU::FeatureOffset3fBug])
8309467b48Spatrick return false;
8409467b48Spatrick
8509467b48Spatrick if (AMDGPU::getSOPPWithRelaxation(Inst.getOpcode()) >= 0)
8609467b48Spatrick return true;
8709467b48Spatrick
8809467b48Spatrick return false;
8909467b48Spatrick }
9009467b48Spatrick
getFixupKindNumBytes(unsigned Kind)9109467b48Spatrick static unsigned getFixupKindNumBytes(unsigned Kind) {
9209467b48Spatrick switch (Kind) {
9309467b48Spatrick case AMDGPU::fixup_si_sopp_br:
9409467b48Spatrick return 2;
9509467b48Spatrick case FK_SecRel_1:
9609467b48Spatrick case FK_Data_1:
9709467b48Spatrick return 1;
9809467b48Spatrick case FK_SecRel_2:
9909467b48Spatrick case FK_Data_2:
10009467b48Spatrick return 2;
10109467b48Spatrick case FK_SecRel_4:
10209467b48Spatrick case FK_Data_4:
10309467b48Spatrick case FK_PCRel_4:
10409467b48Spatrick return 4;
10509467b48Spatrick case FK_SecRel_8:
10609467b48Spatrick case FK_Data_8:
10709467b48Spatrick return 8;
10809467b48Spatrick default:
10909467b48Spatrick llvm_unreachable("Unknown fixup kind!");
11009467b48Spatrick }
11109467b48Spatrick }
11209467b48Spatrick
adjustFixupValue(const MCFixup & Fixup,uint64_t Value,MCContext * Ctx)11309467b48Spatrick static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
11409467b48Spatrick MCContext *Ctx) {
11509467b48Spatrick int64_t SignedValue = static_cast<int64_t>(Value);
11609467b48Spatrick
11709467b48Spatrick switch (Fixup.getTargetKind()) {
11809467b48Spatrick case AMDGPU::fixup_si_sopp_br: {
11909467b48Spatrick int64_t BrImm = (SignedValue - 4) / 4;
12009467b48Spatrick
12109467b48Spatrick if (Ctx && !isInt<16>(BrImm))
12209467b48Spatrick Ctx->reportError(Fixup.getLoc(), "branch size exceeds simm16");
12309467b48Spatrick
12409467b48Spatrick return BrImm;
12509467b48Spatrick }
12609467b48Spatrick case FK_Data_1:
12709467b48Spatrick case FK_Data_2:
12809467b48Spatrick case FK_Data_4:
12909467b48Spatrick case FK_Data_8:
13009467b48Spatrick case FK_PCRel_4:
13109467b48Spatrick case FK_SecRel_4:
13209467b48Spatrick return Value;
13309467b48Spatrick default:
13409467b48Spatrick llvm_unreachable("unhandled fixup kind");
13509467b48Spatrick }
13609467b48Spatrick }
13709467b48Spatrick
applyFixup(const MCAssembler & Asm,const MCFixup & Fixup,const MCValue & Target,MutableArrayRef<char> Data,uint64_t Value,bool IsResolved,const MCSubtargetInfo * STI) const13809467b48Spatrick void AMDGPUAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
13909467b48Spatrick const MCValue &Target,
14009467b48Spatrick MutableArrayRef<char> Data, uint64_t Value,
14109467b48Spatrick bool IsResolved,
14209467b48Spatrick const MCSubtargetInfo *STI) const {
143*d415bd75Srobert if (Fixup.getKind() >= FirstLiteralRelocationKind)
144*d415bd75Srobert return;
145*d415bd75Srobert
14609467b48Spatrick Value = adjustFixupValue(Fixup, Value, &Asm.getContext());
14709467b48Spatrick if (!Value)
14809467b48Spatrick return; // Doesn't change encoding.
14909467b48Spatrick
15009467b48Spatrick MCFixupKindInfo Info = getFixupKindInfo(Fixup.getKind());
15109467b48Spatrick
15209467b48Spatrick // Shift the value into position.
15309467b48Spatrick Value <<= Info.TargetOffset;
15409467b48Spatrick
15509467b48Spatrick unsigned NumBytes = getFixupKindNumBytes(Fixup.getKind());
15609467b48Spatrick uint32_t Offset = Fixup.getOffset();
15709467b48Spatrick assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!");
15809467b48Spatrick
15909467b48Spatrick // For each byte of the fragment that the fixup touches, mask in the bits from
16009467b48Spatrick // the fixup value.
16109467b48Spatrick for (unsigned i = 0; i != NumBytes; ++i)
16209467b48Spatrick Data[Offset + i] |= static_cast<uint8_t>((Value >> (i * 8)) & 0xff);
16309467b48Spatrick }
16409467b48Spatrick
165*d415bd75Srobert std::optional<MCFixupKind>
getFixupKind(StringRef Name) const166*d415bd75Srobert AMDGPUAsmBackend::getFixupKind(StringRef Name) const {
167*d415bd75Srobert return StringSwitch<std::optional<MCFixupKind>>(Name)
168*d415bd75Srobert #define ELF_RELOC(Name, Value) \
169*d415bd75Srobert .Case(#Name, MCFixupKind(FirstLiteralRelocationKind + Value))
170*d415bd75Srobert #include "llvm/BinaryFormat/ELFRelocs/AMDGPU.def"
171*d415bd75Srobert #undef ELF_RELOC
172*d415bd75Srobert .Default(std::nullopt);
173*d415bd75Srobert }
174*d415bd75Srobert
getFixupKindInfo(MCFixupKind Kind) const17509467b48Spatrick const MCFixupKindInfo &AMDGPUAsmBackend::getFixupKindInfo(
17609467b48Spatrick MCFixupKind Kind) const {
17709467b48Spatrick const static MCFixupKindInfo Infos[AMDGPU::NumTargetFixupKinds] = {
17809467b48Spatrick // name offset bits flags
17909467b48Spatrick { "fixup_si_sopp_br", 0, 16, MCFixupKindInfo::FKF_IsPCRel },
18009467b48Spatrick };
18109467b48Spatrick
182*d415bd75Srobert if (Kind >= FirstLiteralRelocationKind)
183*d415bd75Srobert return MCAsmBackend::getFixupKindInfo(FK_NONE);
184*d415bd75Srobert
18509467b48Spatrick if (Kind < FirstTargetFixupKind)
18609467b48Spatrick return MCAsmBackend::getFixupKindInfo(Kind);
18709467b48Spatrick
18809467b48Spatrick return Infos[Kind - FirstTargetFixupKind];
18909467b48Spatrick }
19009467b48Spatrick
shouldForceRelocation(const MCAssembler &,const MCFixup & Fixup,const MCValue &)191*d415bd75Srobert bool AMDGPUAsmBackend::shouldForceRelocation(const MCAssembler &,
192*d415bd75Srobert const MCFixup &Fixup,
193*d415bd75Srobert const MCValue &) {
194*d415bd75Srobert return Fixup.getKind() >= FirstLiteralRelocationKind;
195*d415bd75Srobert }
196*d415bd75Srobert
getMinimumNopSize() const19709467b48Spatrick unsigned AMDGPUAsmBackend::getMinimumNopSize() const {
19809467b48Spatrick return 4;
19909467b48Spatrick }
20009467b48Spatrick
writeNopData(raw_ostream & OS,uint64_t Count,const MCSubtargetInfo * STI) const201*d415bd75Srobert bool AMDGPUAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,
202*d415bd75Srobert const MCSubtargetInfo *STI) const {
20309467b48Spatrick // If the count is not 4-byte aligned, we must be writing data into the text
20409467b48Spatrick // section (otherwise we have unaligned instructions, and thus have far
20509467b48Spatrick // bigger problems), so just write zeros instead.
20609467b48Spatrick OS.write_zeros(Count % 4);
20709467b48Spatrick
20809467b48Spatrick // We are properly aligned, so write NOPs as requested.
20909467b48Spatrick Count /= 4;
21009467b48Spatrick
21109467b48Spatrick // FIXME: R600 support.
21209467b48Spatrick // s_nop 0
21309467b48Spatrick const uint32_t Encoded_S_NOP_0 = 0xbf800000;
21409467b48Spatrick
21509467b48Spatrick for (uint64_t I = 0; I != Count; ++I)
21609467b48Spatrick support::endian::write<uint32_t>(OS, Encoded_S_NOP_0, Endian);
21709467b48Spatrick
21809467b48Spatrick return true;
21909467b48Spatrick }
22009467b48Spatrick
22109467b48Spatrick //===----------------------------------------------------------------------===//
22209467b48Spatrick // ELFAMDGPUAsmBackend class
22309467b48Spatrick //===----------------------------------------------------------------------===//
22409467b48Spatrick
22509467b48Spatrick namespace {
22609467b48Spatrick
22709467b48Spatrick class ELFAMDGPUAsmBackend : public AMDGPUAsmBackend {
22809467b48Spatrick bool Is64Bit;
22909467b48Spatrick bool HasRelocationAddend;
23009467b48Spatrick uint8_t OSABI = ELF::ELFOSABI_NONE;
23109467b48Spatrick uint8_t ABIVersion = 0;
23209467b48Spatrick
23309467b48Spatrick public:
ELFAMDGPUAsmBackend(const Target & T,const Triple & TT,uint8_t ABIVersion)23409467b48Spatrick ELFAMDGPUAsmBackend(const Target &T, const Triple &TT, uint8_t ABIVersion) :
23509467b48Spatrick AMDGPUAsmBackend(T), Is64Bit(TT.getArch() == Triple::amdgcn),
23609467b48Spatrick HasRelocationAddend(TT.getOS() == Triple::AMDHSA),
23709467b48Spatrick ABIVersion(ABIVersion) {
23809467b48Spatrick switch (TT.getOS()) {
23909467b48Spatrick case Triple::AMDHSA:
24009467b48Spatrick OSABI = ELF::ELFOSABI_AMDGPU_HSA;
24109467b48Spatrick break;
24209467b48Spatrick case Triple::AMDPAL:
24309467b48Spatrick OSABI = ELF::ELFOSABI_AMDGPU_PAL;
24409467b48Spatrick break;
24509467b48Spatrick case Triple::Mesa3D:
24609467b48Spatrick OSABI = ELF::ELFOSABI_AMDGPU_MESA3D;
24709467b48Spatrick break;
24809467b48Spatrick default:
24909467b48Spatrick break;
25009467b48Spatrick }
25109467b48Spatrick }
25209467b48Spatrick
25309467b48Spatrick std::unique_ptr<MCObjectTargetWriter>
createObjectTargetWriter() const25409467b48Spatrick createObjectTargetWriter() const override {
25509467b48Spatrick return createAMDGPUELFObjectWriter(Is64Bit, OSABI, HasRelocationAddend,
25609467b48Spatrick ABIVersion);
25709467b48Spatrick }
25809467b48Spatrick };
25909467b48Spatrick
26009467b48Spatrick } // end anonymous namespace
26109467b48Spatrick
createAMDGPUAsmBackend(const Target & T,const MCSubtargetInfo & STI,const MCRegisterInfo & MRI,const MCTargetOptions & Options)26209467b48Spatrick MCAsmBackend *llvm::createAMDGPUAsmBackend(const Target &T,
26309467b48Spatrick const MCSubtargetInfo &STI,
26409467b48Spatrick const MCRegisterInfo &MRI,
26509467b48Spatrick const MCTargetOptions &Options) {
26609467b48Spatrick return new ELFAMDGPUAsmBackend(T, STI.getTargetTriple(),
267*d415bd75Srobert getHsaAbiVersion(&STI).value_or(0));
26809467b48Spatrick }
269