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