summaryrefslogtreecommitdiff
path: root/contrib/llvm-project/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUAsmBackend.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUAsmBackend.cpp')
-rw-r--r--contrib/llvm-project/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUAsmBackend.cpp241
1 files changed, 241 insertions, 0 deletions
diff --git a/contrib/llvm-project/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUAsmBackend.cpp b/contrib/llvm-project/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUAsmBackend.cpp
new file mode 100644
index 000000000000..57c0ba26cc3a
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUAsmBackend.cpp
@@ -0,0 +1,241 @@
+//===-- AMDGPUAsmBackend.cpp - AMDGPU Assembler Backend -------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+/// \file
+//===----------------------------------------------------------------------===//
+
+#include "MCTargetDesc/AMDGPUFixupKinds.h"
+#include "MCTargetDesc/AMDGPUMCTargetDesc.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/MC/MCAsmBackend.h"
+#include "llvm/MC/MCAssembler.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCFixupKindInfo.h"
+#include "llvm/MC/MCObjectWriter.h"
+#include "llvm/MC/MCValue.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "Utils/AMDGPUBaseInfo.h"
+
+using namespace llvm;
+using namespace llvm::AMDGPU;
+
+namespace {
+
+class AMDGPUAsmBackend : public MCAsmBackend {
+public:
+ AMDGPUAsmBackend(const Target &T) : MCAsmBackend(support::little) {}
+
+ unsigned getNumFixupKinds() const override { return AMDGPU::NumTargetFixupKinds; };
+
+ void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
+ const MCValue &Target, MutableArrayRef<char> Data,
+ uint64_t Value, bool IsResolved,
+ const MCSubtargetInfo *STI) const override;
+ bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
+ const MCRelaxableFragment *DF,
+ const MCAsmLayout &Layout) const override;
+
+ void relaxInstruction(const MCInst &Inst, const MCSubtargetInfo &STI,
+ MCInst &Res) const override;
+
+ bool mayNeedRelaxation(const MCInst &Inst,
+ const MCSubtargetInfo &STI) const override;
+
+ unsigned getMinimumNopSize() const override;
+ bool writeNopData(raw_ostream &OS, uint64_t Count) const override;
+
+ const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override;
+};
+
+} //End anonymous namespace
+
+void AMDGPUAsmBackend::relaxInstruction(const MCInst &Inst,
+ const MCSubtargetInfo &STI,
+ MCInst &Res) const {
+ unsigned RelaxedOpcode = AMDGPU::getSOPPWithRelaxation(Inst.getOpcode());
+ Res.setOpcode(RelaxedOpcode);
+ Res.addOperand(Inst.getOperand(0));
+ return;
+}
+
+bool AMDGPUAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup,
+ uint64_t Value,
+ const MCRelaxableFragment *DF,
+ const MCAsmLayout &Layout) const {
+ // if the branch target has an offset of x3f this needs to be relaxed to
+ // add a s_nop 0 immediately after branch to effectively increment offset
+ // for hardware workaround in gfx1010
+ return (((int64_t(Value)/4)-1) == 0x3f);
+}
+
+bool AMDGPUAsmBackend::mayNeedRelaxation(const MCInst &Inst,
+ const MCSubtargetInfo &STI) const {
+ if (!STI.getFeatureBits()[AMDGPU::FeatureOffset3fBug])
+ return false;
+
+ if (AMDGPU::getSOPPWithRelaxation(Inst.getOpcode()) >= 0)
+ return true;
+
+ return false;
+}
+
+static unsigned getFixupKindNumBytes(unsigned Kind) {
+ switch (Kind) {
+ case AMDGPU::fixup_si_sopp_br:
+ return 2;
+ case FK_SecRel_1:
+ case FK_Data_1:
+ return 1;
+ case FK_SecRel_2:
+ case FK_Data_2:
+ return 2;
+ case FK_SecRel_4:
+ case FK_Data_4:
+ case FK_PCRel_4:
+ return 4;
+ case FK_SecRel_8:
+ case FK_Data_8:
+ return 8;
+ default:
+ llvm_unreachable("Unknown fixup kind!");
+ }
+}
+
+static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
+ MCContext *Ctx) {
+ int64_t SignedValue = static_cast<int64_t>(Value);
+
+ switch (static_cast<unsigned>(Fixup.getKind())) {
+ case AMDGPU::fixup_si_sopp_br: {
+ int64_t BrImm = (SignedValue - 4) / 4;
+
+ if (Ctx && !isInt<16>(BrImm))
+ Ctx->reportError(Fixup.getLoc(), "branch size exceeds simm16");
+
+ return BrImm;
+ }
+ case FK_Data_1:
+ case FK_Data_2:
+ case FK_Data_4:
+ case FK_Data_8:
+ case FK_PCRel_4:
+ case FK_SecRel_4:
+ return Value;
+ default:
+ llvm_unreachable("unhandled fixup kind");
+ }
+}
+
+void AMDGPUAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
+ const MCValue &Target,
+ MutableArrayRef<char> Data, uint64_t Value,
+ bool IsResolved,
+ const MCSubtargetInfo *STI) const {
+ Value = adjustFixupValue(Fixup, Value, &Asm.getContext());
+ if (!Value)
+ return; // Doesn't change encoding.
+
+ MCFixupKindInfo Info = getFixupKindInfo(Fixup.getKind());
+
+ // Shift the value into position.
+ Value <<= Info.TargetOffset;
+
+ unsigned NumBytes = getFixupKindNumBytes(Fixup.getKind());
+ uint32_t Offset = Fixup.getOffset();
+ assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!");
+
+ // For each byte of the fragment that the fixup touches, mask in the bits from
+ // the fixup value.
+ for (unsigned i = 0; i != NumBytes; ++i)
+ Data[Offset + i] |= static_cast<uint8_t>((Value >> (i * 8)) & 0xff);
+}
+
+const MCFixupKindInfo &AMDGPUAsmBackend::getFixupKindInfo(
+ MCFixupKind Kind) const {
+ const static MCFixupKindInfo Infos[AMDGPU::NumTargetFixupKinds] = {
+ // name offset bits flags
+ { "fixup_si_sopp_br", 0, 16, MCFixupKindInfo::FKF_IsPCRel },
+ };
+
+ if (Kind < FirstTargetFixupKind)
+ return MCAsmBackend::getFixupKindInfo(Kind);
+
+ return Infos[Kind - FirstTargetFixupKind];
+}
+
+unsigned AMDGPUAsmBackend::getMinimumNopSize() const {
+ return 4;
+}
+
+bool AMDGPUAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count) const {
+ // If the count is not 4-byte aligned, we must be writing data into the text
+ // section (otherwise we have unaligned instructions, and thus have far
+ // bigger problems), so just write zeros instead.
+ OS.write_zeros(Count % 4);
+
+ // We are properly aligned, so write NOPs as requested.
+ Count /= 4;
+
+ // FIXME: R600 support.
+ // s_nop 0
+ const uint32_t Encoded_S_NOP_0 = 0xbf800000;
+
+ for (uint64_t I = 0; I != Count; ++I)
+ support::endian::write<uint32_t>(OS, Encoded_S_NOP_0, Endian);
+
+ return true;
+}
+
+//===----------------------------------------------------------------------===//
+// ELFAMDGPUAsmBackend class
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class ELFAMDGPUAsmBackend : public AMDGPUAsmBackend {
+ bool Is64Bit;
+ bool HasRelocationAddend;
+ uint8_t OSABI = ELF::ELFOSABI_NONE;
+ uint8_t ABIVersion = 0;
+
+public:
+ ELFAMDGPUAsmBackend(const Target &T, const Triple &TT, uint8_t ABIVersion) :
+ AMDGPUAsmBackend(T), Is64Bit(TT.getArch() == Triple::amdgcn),
+ HasRelocationAddend(TT.getOS() == Triple::AMDHSA),
+ ABIVersion(ABIVersion) {
+ switch (TT.getOS()) {
+ case Triple::AMDHSA:
+ OSABI = ELF::ELFOSABI_AMDGPU_HSA;
+ break;
+ case Triple::AMDPAL:
+ OSABI = ELF::ELFOSABI_AMDGPU_PAL;
+ break;
+ case Triple::Mesa3D:
+ OSABI = ELF::ELFOSABI_AMDGPU_MESA3D;
+ break;
+ default:
+ break;
+ }
+ }
+
+ std::unique_ptr<MCObjectTargetWriter>
+ createObjectTargetWriter() const override {
+ return createAMDGPUELFObjectWriter(Is64Bit, OSABI, HasRelocationAddend,
+ ABIVersion);
+ }
+};
+
+} // end anonymous namespace
+
+MCAsmBackend *llvm::createAMDGPUAsmBackend(const Target &T,
+ const MCSubtargetInfo &STI,
+ const MCRegisterInfo &MRI,
+ const MCTargetOptions &Options) {
+ // Use 64-bit ELF for amdgcn
+ return new ELFAMDGPUAsmBackend(T, STI.getTargetTriple(),
+ IsaInfo::hasCodeObjectV3(&STI) ? 1 : 0);
+}