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/MCAssembler.h"
17#include "llvm/MC/MCContext.h"
18#include "llvm/MC/MCFixupKindInfo.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
26using namespace llvm;
27using namespace llvm::AMDGPU;
28
29namespace {
30
31class AMDGPUAsmBackend : public MCAsmBackend {
32public:
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(const MCInst &Inst,
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
57void AMDGPUAsmBackend::relaxInstruction(MCInst &Inst,
58 const MCSubtargetInfo &STI) const {
59 MCInst Res;
60 unsigned RelaxedOpcode = AMDGPU::getSOPPWithRelaxation(Opcode: Inst.getOpcode());
61 Res.setOpcode(RelaxedOpcode);
62 Res.addOperand(Op: Inst.getOperand(i: 0));
63 Inst = std::move(Res);
64}
65
66bool 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
74bool AMDGPUAsmBackend::mayNeedRelaxation(const MCInst &Inst,
75 const MCSubtargetInfo &STI) const {
76 if (!STI.hasFeature(Feature: AMDGPU::FeatureOffset3fBug))
77 return false;
78
79 if (AMDGPU::getSOPPWithRelaxation(Opcode: Inst.getOpcode()) >= 0)
80 return true;
81
82 return false;
83}
84
85static unsigned getFixupKindNumBytes(unsigned Kind) {
86 switch (Kind) {
87 case AMDGPU::fixup_si_sopp_br:
88 return 2;
89 case FK_SecRel_1:
90 case FK_Data_1:
91 return 1;
92 case FK_SecRel_2:
93 case FK_Data_2:
94 return 2;
95 case FK_SecRel_4:
96 case FK_Data_4:
97 case FK_PCRel_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
107static 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.getTargetKind()) {
112 case AMDGPU::fixup_si_sopp_br: {
113 int64_t BrImm = (SignedValue - 4) / 4;
114
115 if (Ctx && !isInt<16>(x: BrImm))
116 Ctx->reportError(L: Fixup.getLoc(), Msg: "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_PCRel_4:
125 case FK_SecRel_4:
126 return Value;
127 default:
128 llvm_unreachable("unhandled fixup kind");
129 }
130}
131
132void AMDGPUAsmBackend::applyFixup(const MCFragment &F, const MCFixup &Fixup,
133 const MCValue &Target,
134 MutableArrayRef<char> Data, uint64_t Value,
135 bool IsResolved) {
136 if (Target.getSpecifier())
137 IsResolved = false;
138 maybeAddReloc(F, Fixup, Target, Value, IsResolved);
139 if (mc::isRelocation(FixupKind: Fixup.getKind()))
140 return;
141
142 Value = adjustFixupValue(Fixup, Value, Ctx: &getContext());
143 if (!Value)
144 return; // Doesn't change encoding.
145
146 MCFixupKindInfo Info = getFixupKindInfo(Kind: Fixup.getKind());
147
148 // Shift the value into position.
149 Value <<= Info.TargetOffset;
150
151 unsigned NumBytes = getFixupKindNumBytes(Kind: Fixup.getKind());
152 uint32_t Offset = Fixup.getOffset();
153 assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!");
154
155 // For each byte of the fragment that the fixup touches, mask in the bits from
156 // the fixup value.
157 for (unsigned i = 0; i != NumBytes; ++i)
158 Data[Offset + i] |= static_cast<uint8_t>((Value >> (i * 8)) & 0xff);
159}
160
161std::optional<MCFixupKind>
162AMDGPUAsmBackend::getFixupKind(StringRef Name) const {
163 auto Type = StringSwitch<unsigned>(Name)
164#define ELF_RELOC(Name, Value) .Case(#Name, Value)
165#include "llvm/BinaryFormat/ELFRelocs/AMDGPU.def"
166#undef ELF_RELOC
167 .Case(S: "BFD_RELOC_NONE", Value: ELF::R_AMDGPU_NONE)
168 .Case(S: "BFD_RELOC_32", Value: ELF::R_AMDGPU_ABS32)
169 .Case(S: "BFD_RELOC_64", Value: ELF::R_AMDGPU_ABS64)
170 .Default(Value: -1u);
171 if (Type != -1u)
172 return static_cast<MCFixupKind>(FirstLiteralRelocationKind + Type);
173 return std::nullopt;
174}
175
176MCFixupKindInfo AMDGPUAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
177 const static MCFixupKindInfo Infos[AMDGPU::NumTargetFixupKinds] = {
178 // name offset bits flags
179 { .Name: "fixup_si_sopp_br", .TargetOffset: 0, .TargetSize: 16, .Flags: MCFixupKindInfo::FKF_IsPCRel },
180 };
181
182 if (mc::isRelocation(FixupKind: Kind))
183 return MCAsmBackend::getFixupKindInfo(Kind: FK_NONE);
184
185 if (Kind < FirstTargetFixupKind)
186 return MCAsmBackend::getFixupKindInfo(Kind);
187
188 assert(unsigned(Kind - FirstTargetFixupKind) < AMDGPU::NumTargetFixupKinds &&
189 "Invalid kind!");
190 return Infos[Kind - FirstTargetFixupKind];
191}
192
193unsigned AMDGPUAsmBackend::getMinimumNopSize() const {
194 return 4;
195}
196
197bool AMDGPUAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,
198 const MCSubtargetInfo *STI) const {
199 // If the count is not 4-byte aligned, we must be writing data into the text
200 // section (otherwise we have unaligned instructions, and thus have far
201 // bigger problems), so just write zeros instead.
202 OS.write_zeros(NumZeros: Count % 4);
203
204 // We are properly aligned, so write NOPs as requested.
205 Count /= 4;
206
207 // FIXME: R600 support.
208 // s_nop 0
209 const uint32_t Encoded_S_NOP_0 = 0xbf800000;
210
211 for (uint64_t I = 0; I != Count; ++I)
212 support::endian::write<uint32_t>(os&: OS, value: Encoded_S_NOP_0, endian: Endian);
213
214 return true;
215}
216
217//===----------------------------------------------------------------------===//
218// ELFAMDGPUAsmBackend class
219//===----------------------------------------------------------------------===//
220
221namespace {
222
223class ELFAMDGPUAsmBackend : public AMDGPUAsmBackend {
224 bool Is64Bit;
225 bool HasRelocationAddend;
226 uint8_t OSABI = ELF::ELFOSABI_NONE;
227
228public:
229 ELFAMDGPUAsmBackend(const Target &T, const Triple &TT)
230 : AMDGPUAsmBackend(T), Is64Bit(TT.isAMDGCN()),
231 HasRelocationAddend(TT.getOS() == Triple::AMDHSA) {
232 switch (TT.getOS()) {
233 case Triple::AMDHSA:
234 OSABI = ELF::ELFOSABI_AMDGPU_HSA;
235 break;
236 case Triple::AMDPAL:
237 OSABI = ELF::ELFOSABI_AMDGPU_PAL;
238 break;
239 case Triple::Mesa3D:
240 OSABI = ELF::ELFOSABI_AMDGPU_MESA3D;
241 break;
242 default:
243 break;
244 }
245 }
246
247 std::unique_ptr<MCObjectTargetWriter>
248 createObjectTargetWriter() const override {
249 return createAMDGPUELFObjectWriter(Is64Bit, OSABI, HasRelocationAddend);
250 }
251};
252
253} // end anonymous namespace
254
255MCAsmBackend *llvm::createAMDGPUAsmBackend(const Target &T,
256 const MCSubtargetInfo &STI,
257 const MCRegisterInfo &MRI,
258 const MCTargetOptions &Options) {
259 return new ELFAMDGPUAsmBackend(T, STI.getTargetTriple());
260}
261