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/BinaryFormat/ELF.h"
14 #include "llvm/MC/MCAsmBackend.h"
15 #include "llvm/MC/MCAssembler.h"
16 #include "llvm/MC/MCContext.h"
17 #include "llvm/MC/MCFixupKindInfo.h"
18 #include "llvm/MC/MCObjectWriter.h"
19 #include "llvm/MC/MCSubtargetInfo.h"
20 #include "llvm/MC/TargetRegistry.h"
21 #include "llvm/Support/EndianStream.h"
22 #include "llvm/Support/TargetParser.h"
23 
24 using namespace llvm;
25 using namespace llvm::AMDGPU;
26 
27 namespace {
28 
29 class AMDGPUAsmBackend : public MCAsmBackend {
30 public:
31   AMDGPUAsmBackend(const Target &T) : MCAsmBackend(support::little) {}
32 
33   unsigned getNumFixupKinds() const override { return AMDGPU::NumTargetFixupKinds; };
34 
35   void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
36                   const MCValue &Target, MutableArrayRef<char> Data,
37                   uint64_t Value, bool IsResolved,
38                   const MCSubtargetInfo *STI) const override;
39   bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
40                             const MCRelaxableFragment *DF,
41                             const MCAsmLayout &Layout) const override;
42 
43   void relaxInstruction(MCInst &Inst,
44                         const MCSubtargetInfo &STI) const override;
45 
46   bool mayNeedRelaxation(const MCInst &Inst,
47                          const MCSubtargetInfo &STI) const override;
48 
49   unsigned getMinimumNopSize() const override;
50   bool writeNopData(raw_ostream &OS, uint64_t Count,
51                     const MCSubtargetInfo *STI) const override;
52 
53   const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override;
54 };
55 
56 } //End anonymous namespace
57 
58 void AMDGPUAsmBackend::relaxInstruction(MCInst &Inst,
59                                         const MCSubtargetInfo &STI) const {
60   MCInst Res;
61   unsigned RelaxedOpcode = AMDGPU::getSOPPWithRelaxation(Inst.getOpcode());
62   Res.setOpcode(RelaxedOpcode);
63   Res.addOperand(Inst.getOperand(0));
64   Inst = std::move(Res);
65 }
66 
67 bool AMDGPUAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup,
68                                             uint64_t Value,
69                                             const MCRelaxableFragment *DF,
70                                             const MCAsmLayout &Layout) const {
71   // if the branch target has an offset of x3f this needs to be relaxed to
72   // add a s_nop 0 immediately after branch to effectively increment offset
73   // for hardware workaround in gfx1010
74   return (((int64_t(Value)/4)-1) == 0x3f);
75 }
76 
77 bool AMDGPUAsmBackend::mayNeedRelaxation(const MCInst &Inst,
78                        const MCSubtargetInfo &STI) const {
79   if (!STI.getFeatureBits()[AMDGPU::FeatureOffset3fBug])
80     return false;
81 
82   if (AMDGPU::getSOPPWithRelaxation(Inst.getOpcode()) >= 0)
83     return true;
84 
85   return false;
86 }
87 
88 static unsigned getFixupKindNumBytes(unsigned Kind) {
89   switch (Kind) {
90   case AMDGPU::fixup_si_sopp_br:
91     return 2;
92   case FK_SecRel_1:
93   case FK_Data_1:
94     return 1;
95   case FK_SecRel_2:
96   case FK_Data_2:
97     return 2;
98   case FK_SecRel_4:
99   case FK_Data_4:
100   case FK_PCRel_4:
101     return 4;
102   case FK_SecRel_8:
103   case FK_Data_8:
104     return 8;
105   default:
106     llvm_unreachable("Unknown fixup kind!");
107   }
108 }
109 
110 static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
111                                  MCContext *Ctx) {
112   int64_t SignedValue = static_cast<int64_t>(Value);
113 
114   switch (Fixup.getTargetKind()) {
115   case AMDGPU::fixup_si_sopp_br: {
116     int64_t BrImm = (SignedValue - 4) / 4;
117 
118     if (Ctx && !isInt<16>(BrImm))
119       Ctx->reportError(Fixup.getLoc(), "branch size exceeds simm16");
120 
121     return BrImm;
122   }
123   case FK_Data_1:
124   case FK_Data_2:
125   case FK_Data_4:
126   case FK_Data_8:
127   case FK_PCRel_4:
128   case FK_SecRel_4:
129     return Value;
130   default:
131     llvm_unreachable("unhandled fixup kind");
132   }
133 }
134 
135 void AMDGPUAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
136                                   const MCValue &Target,
137                                   MutableArrayRef<char> Data, uint64_t Value,
138                                   bool IsResolved,
139                                   const MCSubtargetInfo *STI) const {
140   Value = adjustFixupValue(Fixup, Value, &Asm.getContext());
141   if (!Value)
142     return; // Doesn't change encoding.
143 
144   MCFixupKindInfo Info = getFixupKindInfo(Fixup.getKind());
145 
146   // Shift the value into position.
147   Value <<= Info.TargetOffset;
148 
149   unsigned NumBytes = getFixupKindNumBytes(Fixup.getKind());
150   uint32_t Offset = Fixup.getOffset();
151   assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!");
152 
153   // For each byte of the fragment that the fixup touches, mask in the bits from
154   // the fixup value.
155   for (unsigned i = 0; i != NumBytes; ++i)
156     Data[Offset + i] |= static_cast<uint8_t>((Value >> (i * 8)) & 0xff);
157 }
158 
159 const MCFixupKindInfo &AMDGPUAsmBackend::getFixupKindInfo(
160                                                        MCFixupKind Kind) const {
161   const static MCFixupKindInfo Infos[AMDGPU::NumTargetFixupKinds] = {
162     // name                   offset bits  flags
163     { "fixup_si_sopp_br",     0,     16,   MCFixupKindInfo::FKF_IsPCRel },
164   };
165 
166   if (Kind < FirstTargetFixupKind)
167     return MCAsmBackend::getFixupKindInfo(Kind);
168 
169   return Infos[Kind - FirstTargetFixupKind];
170 }
171 
172 unsigned AMDGPUAsmBackend::getMinimumNopSize() const {
173   return 4;
174 }
175 
176 bool AMDGPUAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,
177                                     const MCSubtargetInfo *STI) const {
178   // If the count is not 4-byte aligned, we must be writing data into the text
179   // section (otherwise we have unaligned instructions, and thus have far
180   // bigger problems), so just write zeros instead.
181   OS.write_zeros(Count % 4);
182 
183   // We are properly aligned, so write NOPs as requested.
184   Count /= 4;
185 
186   // FIXME: R600 support.
187   // s_nop 0
188   const uint32_t Encoded_S_NOP_0 = 0xbf800000;
189 
190   for (uint64_t I = 0; I != Count; ++I)
191     support::endian::write<uint32_t>(OS, Encoded_S_NOP_0, Endian);
192 
193   return true;
194 }
195 
196 //===----------------------------------------------------------------------===//
197 // ELFAMDGPUAsmBackend class
198 //===----------------------------------------------------------------------===//
199 
200 namespace {
201 
202 class ELFAMDGPUAsmBackend : public AMDGPUAsmBackend {
203   bool Is64Bit;
204   bool HasRelocationAddend;
205   uint8_t OSABI = ELF::ELFOSABI_NONE;
206   uint8_t ABIVersion = 0;
207 
208 public:
209   ELFAMDGPUAsmBackend(const Target &T, const Triple &TT, uint8_t ABIVersion) :
210       AMDGPUAsmBackend(T), Is64Bit(TT.getArch() == Triple::amdgcn),
211       HasRelocationAddend(TT.getOS() == Triple::AMDHSA),
212       ABIVersion(ABIVersion) {
213     switch (TT.getOS()) {
214     case Triple::AMDHSA:
215       OSABI = ELF::ELFOSABI_AMDGPU_HSA;
216       break;
217     case Triple::AMDPAL:
218       OSABI = ELF::ELFOSABI_AMDGPU_PAL;
219       break;
220     case Triple::Mesa3D:
221       OSABI = ELF::ELFOSABI_AMDGPU_MESA3D;
222       break;
223     default:
224       break;
225     }
226   }
227 
228   std::unique_ptr<MCObjectTargetWriter>
229   createObjectTargetWriter() const override {
230     return createAMDGPUELFObjectWriter(Is64Bit, OSABI, HasRelocationAddend,
231                                        ABIVersion);
232   }
233 };
234 
235 } // end anonymous namespace
236 
237 MCAsmBackend *llvm::createAMDGPUAsmBackend(const Target &T,
238                                            const MCSubtargetInfo &STI,
239                                            const MCRegisterInfo &MRI,
240                                            const MCTargetOptions &Options) {
241   return new ELFAMDGPUAsmBackend(T, STI.getTargetTriple(),
242                                  getHsaAbiVersion(&STI).getValueOr(0));
243 }
244