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:
AMDGPUAsmBackend(const Target & T)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
relaxInstruction(MCInst & Inst,const MCSubtargetInfo & STI) const57 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
fixupNeedsRelaxation(const MCFixup & Fixup,uint64_t Value) const66 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
mayNeedRelaxation(unsigned Opcode,ArrayRef<MCOperand> Operands,const MCSubtargetInfo & STI) const74 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
getFixupKindNumBytes(unsigned Kind)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
adjustFixupValue(const MCFixup & Fixup,uint64_t Value,MCContext * Ctx)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
applyFixup(const MCFragment & F,const MCFixup & Fixup,const MCValue & Target,MutableArrayRef<char> Data,uint64_t Value,bool IsResolved)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>
getFixupKind(StringRef Name) const161 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
getFixupKindInfo(MCFixupKind Kind) const175 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
getMinimumNopSize() const192 unsigned AMDGPUAsmBackend::getMinimumNopSize() const {
193 return 4;
194 }
195
writeNopData(raw_ostream & OS,uint64_t Count,const MCSubtargetInfo * STI) const196 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:
ELFAMDGPUAsmBackend(const Target & T,const Triple & TT)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>
createObjectTargetWriter() const250 createObjectTargetWriter() const override {
251 return createAMDGPUELFObjectWriter(Is64Bit, OSABI, HasRelocationAddend);
252 }
253 };
254
255 } // end anonymous namespace
256
createAMDGPUAsmBackend(const Target & T,const MCSubtargetInfo & STI,const MCRegisterInfo & MRI,const MCTargetOptions & Options)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