xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUAsmBackend.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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