xref: /freebsd/contrib/llvm-project/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUAsmBackend.cpp (revision 770cf0a5f02dc8983a89c6568d741fbc25baa999)
1 //===-- AMDGPUAsmBackend.cpp - AMDGPU Assembler Backend -------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 /// \file
8 //===----------------------------------------------------------------------===//
9 
10 #include "MCTargetDesc/AMDGPUFixupKinds.h"
11 #include "MCTargetDesc/AMDGPUMCTargetDesc.h"
12 #include "Utils/AMDGPUBaseInfo.h"
13 #include "llvm/ADT/StringSwitch.h"
14 #include "llvm/BinaryFormat/ELF.h"
15 #include "llvm/MC/MCAsmBackend.h"
16 #include "llvm/MC/MCAsmInfo.h"
17 #include "llvm/MC/MCAssembler.h"
18 #include "llvm/MC/MCContext.h"
19 #include "llvm/MC/MCObjectWriter.h"
20 #include "llvm/MC/MCSubtargetInfo.h"
21 #include "llvm/MC/MCValue.h"
22 #include "llvm/MC/TargetRegistry.h"
23 #include "llvm/Support/EndianStream.h"
24 #include "llvm/TargetParser/TargetParser.h"
25 
26 using namespace llvm;
27 using namespace llvm::AMDGPU;
28 
29 namespace {
30 
31 class AMDGPUAsmBackend : public MCAsmBackend {
32 public:
33   AMDGPUAsmBackend(const Target &T) : MCAsmBackend(llvm::endianness::little) {}
34 
35   void applyFixup(const MCFragment &, const MCFixup &, const MCValue &Target,
36                   MutableArrayRef<char> Data, uint64_t Value,
37                   bool IsResolved) override;
38   bool fixupNeedsRelaxation(const MCFixup &Fixup,
39                             uint64_t Value) const override;
40 
41   void relaxInstruction(MCInst &Inst,
42                         const MCSubtargetInfo &STI) const override;
43 
44   bool mayNeedRelaxation(unsigned Opcode, ArrayRef<MCOperand> Operands,
45                          const MCSubtargetInfo &STI) const override;
46 
47   unsigned getMinimumNopSize() const override;
48   bool writeNopData(raw_ostream &OS, uint64_t Count,
49                     const MCSubtargetInfo *STI) const override;
50 
51   std::optional<MCFixupKind> getFixupKind(StringRef Name) const override;
52   MCFixupKindInfo getFixupKindInfo(MCFixupKind Kind) const override;
53 };
54 
55 } //End anonymous namespace
56 
57 void AMDGPUAsmBackend::relaxInstruction(MCInst &Inst,
58                                         const MCSubtargetInfo &STI) const {
59   MCInst Res;
60   unsigned RelaxedOpcode = AMDGPU::getSOPPWithRelaxation(Inst.getOpcode());
61   Res.setOpcode(RelaxedOpcode);
62   Res.addOperand(Inst.getOperand(0));
63   Inst = std::move(Res);
64 }
65 
66 bool AMDGPUAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup,
67                                             uint64_t Value) const {
68   // if the branch target has an offset of x3f this needs to be relaxed to
69   // add a s_nop 0 immediately after branch to effectively increment offset
70   // for hardware workaround in gfx1010
71   return (((int64_t(Value)/4)-1) == 0x3f);
72 }
73 
74 bool AMDGPUAsmBackend::mayNeedRelaxation(unsigned Opcode,
75                                          ArrayRef<MCOperand> Operands,
76                                          const MCSubtargetInfo &STI) const {
77   if (!STI.hasFeature(AMDGPU::FeatureOffset3fBug))
78     return false;
79 
80   if (AMDGPU::getSOPPWithRelaxation(Opcode) >= 0)
81     return true;
82 
83   return false;
84 }
85 
86 static unsigned getFixupKindNumBytes(unsigned Kind) {
87   switch (Kind) {
88   case AMDGPU::fixup_si_sopp_br:
89     return 2;
90   case FK_SecRel_1:
91   case FK_Data_1:
92     return 1;
93   case FK_SecRel_2:
94   case FK_Data_2:
95     return 2;
96   case FK_SecRel_4:
97   case FK_Data_4:
98     return 4;
99   case FK_SecRel_8:
100   case FK_Data_8:
101     return 8;
102   default:
103     llvm_unreachable("Unknown fixup kind!");
104   }
105 }
106 
107 static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
108                                  MCContext *Ctx) {
109   int64_t SignedValue = static_cast<int64_t>(Value);
110 
111   switch (Fixup.getKind()) {
112   case AMDGPU::fixup_si_sopp_br: {
113     int64_t BrImm = (SignedValue - 4) / 4;
114 
115     if (Ctx && !isInt<16>(BrImm))
116       Ctx->reportError(Fixup.getLoc(), "branch size exceeds simm16");
117 
118     return BrImm;
119   }
120   case FK_Data_1:
121   case FK_Data_2:
122   case FK_Data_4:
123   case FK_Data_8:
124   case FK_SecRel_4:
125     return Value;
126   default:
127     llvm_unreachable("unhandled fixup kind");
128   }
129 }
130 
131 void AMDGPUAsmBackend::applyFixup(const MCFragment &F, const MCFixup &Fixup,
132                                   const MCValue &Target,
133                                   MutableArrayRef<char> Data, uint64_t Value,
134                                   bool IsResolved) {
135   if (Target.getSpecifier())
136     IsResolved = false;
137   maybeAddReloc(F, Fixup, Target, Value, IsResolved);
138   if (mc::isRelocation(Fixup.getKind()))
139     return;
140 
141   Value = adjustFixupValue(Fixup, Value, &getContext());
142   if (!Value)
143     return; // Doesn't change encoding.
144 
145   MCFixupKindInfo Info = getFixupKindInfo(Fixup.getKind());
146 
147   // Shift the value into position.
148   Value <<= Info.TargetOffset;
149 
150   unsigned NumBytes = getFixupKindNumBytes(Fixup.getKind());
151   uint32_t Offset = Fixup.getOffset();
152   assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!");
153 
154   // For each byte of the fragment that the fixup touches, mask in the bits from
155   // the fixup value.
156   for (unsigned i = 0; i != NumBytes; ++i)
157     Data[Offset + i] |= static_cast<uint8_t>((Value >> (i * 8)) & 0xff);
158 }
159 
160 std::optional<MCFixupKind>
161 AMDGPUAsmBackend::getFixupKind(StringRef Name) const {
162   auto Type = StringSwitch<unsigned>(Name)
163 #define ELF_RELOC(Name, Value) .Case(#Name, Value)
164 #include "llvm/BinaryFormat/ELFRelocs/AMDGPU.def"
165 #undef ELF_RELOC
166                   .Case("BFD_RELOC_NONE", ELF::R_AMDGPU_NONE)
167                   .Case("BFD_RELOC_32", ELF::R_AMDGPU_ABS32)
168                   .Case("BFD_RELOC_64", ELF::R_AMDGPU_ABS64)
169                   .Default(-1u);
170   if (Type != -1u)
171     return static_cast<MCFixupKind>(FirstLiteralRelocationKind + Type);
172   return std::nullopt;
173 }
174 
175 MCFixupKindInfo AMDGPUAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
176   const static MCFixupKindInfo Infos[AMDGPU::NumTargetFixupKinds] = {
177       // name                   offset bits  flags
178       {"fixup_si_sopp_br", 0, 16, 0},
179   };
180 
181   if (mc::isRelocation(Kind))
182     return {};
183 
184   if (Kind < FirstTargetFixupKind)
185     return MCAsmBackend::getFixupKindInfo(Kind);
186 
187   assert(unsigned(Kind - FirstTargetFixupKind) < AMDGPU::NumTargetFixupKinds &&
188          "Invalid kind!");
189   return Infos[Kind - FirstTargetFixupKind];
190 }
191 
192 unsigned AMDGPUAsmBackend::getMinimumNopSize() const {
193   return 4;
194 }
195 
196 bool AMDGPUAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,
197                                     const MCSubtargetInfo *STI) const {
198   // If the count is not aligned to the minimum instruction alignment, we must
199   // be writing data into the text section (otherwise we have unaligned
200   // instructions, and thus have far bigger problems), so just write zeros
201   // instead.
202   unsigned MinInstAlignment = getContext().getAsmInfo()->getMinInstAlignment();
203   OS.write_zeros(Count % MinInstAlignment);
204 
205   // We are properly aligned, so write NOPs as requested.
206   Count /= MinInstAlignment;
207 
208   // FIXME: R600 support.
209   // s_nop 0
210   const uint32_t Encoded_S_NOP_0 = 0xbf800000;
211 
212   assert(MinInstAlignment == sizeof(Encoded_S_NOP_0));
213   for (uint64_t I = 0; I != Count; ++I)
214     support::endian::write<uint32_t>(OS, Encoded_S_NOP_0, Endian);
215 
216   return true;
217 }
218 
219 //===----------------------------------------------------------------------===//
220 // ELFAMDGPUAsmBackend class
221 //===----------------------------------------------------------------------===//
222 
223 namespace {
224 
225 class ELFAMDGPUAsmBackend : public AMDGPUAsmBackend {
226   bool Is64Bit;
227   bool HasRelocationAddend;
228   uint8_t OSABI = ELF::ELFOSABI_NONE;
229 
230 public:
231   ELFAMDGPUAsmBackend(const Target &T, const Triple &TT)
232       : AMDGPUAsmBackend(T), Is64Bit(TT.isAMDGCN()),
233         HasRelocationAddend(TT.getOS() == Triple::AMDHSA) {
234     switch (TT.getOS()) {
235     case Triple::AMDHSA:
236       OSABI = ELF::ELFOSABI_AMDGPU_HSA;
237       break;
238     case Triple::AMDPAL:
239       OSABI = ELF::ELFOSABI_AMDGPU_PAL;
240       break;
241     case Triple::Mesa3D:
242       OSABI = ELF::ELFOSABI_AMDGPU_MESA3D;
243       break;
244     default:
245       break;
246     }
247   }
248 
249   std::unique_ptr<MCObjectTargetWriter>
250   createObjectTargetWriter() const override {
251     return createAMDGPUELFObjectWriter(Is64Bit, OSABI, HasRelocationAddend);
252   }
253 };
254 
255 } // end anonymous namespace
256 
257 MCAsmBackend *llvm::createAMDGPUAsmBackend(const Target &T,
258                                            const MCSubtargetInfo &STI,
259                                            const MCRegisterInfo &MRI,
260                                            const MCTargetOptions &Options) {
261   return new ELFAMDGPUAsmBackend(T, STI.getTargetTriple());
262 }
263