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