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