Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / lld / ELF / Arch / AMDGPU.cpp
blob650744db7dee32b271cd8fa171a499c45852d53c
1 //===- AMDGPU.cpp ---------------------------------------------------------===//
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 //===----------------------------------------------------------------------===//
9 #include "InputFiles.h"
10 #include "Symbols.h"
11 #include "Target.h"
12 #include "lld/Common/ErrorHandler.h"
13 #include "llvm/BinaryFormat/ELF.h"
14 #include "llvm/Support/Endian.h"
16 using namespace llvm;
17 using namespace llvm::object;
18 using namespace llvm::support::endian;
19 using namespace llvm::ELF;
20 using namespace lld;
21 using namespace lld::elf;
23 namespace {
24 class AMDGPU final : public TargetInfo {
25 private:
26 uint32_t calcEFlagsV3() const;
27 uint32_t calcEFlagsV4() const;
29 public:
30 AMDGPU();
31 uint32_t calcEFlags() const override;
32 void relocate(uint8_t *loc, const Relocation &rel,
33 uint64_t val) const override;
34 RelExpr getRelExpr(RelType type, const Symbol &s,
35 const uint8_t *loc) const override;
36 RelType getDynRel(RelType type) const override;
37 int64_t getImplicitAddend(const uint8_t *buf, RelType type) const override;
39 } // namespace
41 AMDGPU::AMDGPU() {
42 relativeRel = R_AMDGPU_RELATIVE64;
43 gotRel = R_AMDGPU_ABS64;
44 symbolicRel = R_AMDGPU_ABS64;
47 static uint32_t getEFlags(InputFile *file) {
48 return cast<ObjFile<ELF64LE>>(file)->getObj().getHeader().e_flags;
51 uint32_t AMDGPU::calcEFlagsV3() const {
52 uint32_t ret = getEFlags(ctx.objectFiles[0]);
54 // Verify that all input files have the same e_flags.
55 for (InputFile *f : ArrayRef(ctx.objectFiles).slice(1)) {
56 if (ret == getEFlags(f))
57 continue;
58 error("incompatible e_flags: " + toString(f));
59 return 0;
61 return ret;
64 uint32_t AMDGPU::calcEFlagsV4() const {
65 uint32_t retMach = getEFlags(ctx.objectFiles[0]) & EF_AMDGPU_MACH;
66 uint32_t retXnack =
67 getEFlags(ctx.objectFiles[0]) & EF_AMDGPU_FEATURE_XNACK_V4;
68 uint32_t retSramEcc =
69 getEFlags(ctx.objectFiles[0]) & EF_AMDGPU_FEATURE_SRAMECC_V4;
71 // Verify that all input files have compatible e_flags (same mach, all
72 // features in the same category are either ANY, ANY and ON, or ANY and OFF).
73 for (InputFile *f : ArrayRef(ctx.objectFiles).slice(1)) {
74 if (retMach != (getEFlags(f) & EF_AMDGPU_MACH)) {
75 error("incompatible mach: " + toString(f));
76 return 0;
79 if (retXnack == EF_AMDGPU_FEATURE_XNACK_UNSUPPORTED_V4 ||
80 (retXnack != EF_AMDGPU_FEATURE_XNACK_ANY_V4 &&
81 (getEFlags(f) & EF_AMDGPU_FEATURE_XNACK_V4)
82 != EF_AMDGPU_FEATURE_XNACK_ANY_V4)) {
83 if (retXnack != (getEFlags(f) & EF_AMDGPU_FEATURE_XNACK_V4)) {
84 error("incompatible xnack: " + toString(f));
85 return 0;
87 } else {
88 if (retXnack == EF_AMDGPU_FEATURE_XNACK_ANY_V4)
89 retXnack = getEFlags(f) & EF_AMDGPU_FEATURE_XNACK_V4;
92 if (retSramEcc == EF_AMDGPU_FEATURE_SRAMECC_UNSUPPORTED_V4 ||
93 (retSramEcc != EF_AMDGPU_FEATURE_SRAMECC_ANY_V4 &&
94 (getEFlags(f) & EF_AMDGPU_FEATURE_SRAMECC_V4) !=
95 EF_AMDGPU_FEATURE_SRAMECC_ANY_V4)) {
96 if (retSramEcc != (getEFlags(f) & EF_AMDGPU_FEATURE_SRAMECC_V4)) {
97 error("incompatible sramecc: " + toString(f));
98 return 0;
100 } else {
101 if (retSramEcc == EF_AMDGPU_FEATURE_SRAMECC_ANY_V4)
102 retSramEcc = getEFlags(f) & EF_AMDGPU_FEATURE_SRAMECC_V4;
106 return retMach | retXnack | retSramEcc;
109 uint32_t AMDGPU::calcEFlags() const {
110 if (ctx.objectFiles.empty())
111 return 0;
113 uint8_t abiVersion = cast<ObjFile<ELF64LE>>(ctx.objectFiles[0])
114 ->getObj()
115 .getHeader()
116 .e_ident[EI_ABIVERSION];
117 switch (abiVersion) {
118 case ELFABIVERSION_AMDGPU_HSA_V2:
119 case ELFABIVERSION_AMDGPU_HSA_V3:
120 return calcEFlagsV3();
121 case ELFABIVERSION_AMDGPU_HSA_V4:
122 case ELFABIVERSION_AMDGPU_HSA_V5:
123 return calcEFlagsV4();
124 default:
125 error("unknown abi version: " + Twine(abiVersion));
126 return 0;
130 void AMDGPU::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
131 switch (rel.type) {
132 case R_AMDGPU_ABS32:
133 case R_AMDGPU_GOTPCREL:
134 case R_AMDGPU_GOTPCREL32_LO:
135 case R_AMDGPU_REL32:
136 case R_AMDGPU_REL32_LO:
137 write32le(loc, val);
138 break;
139 case R_AMDGPU_ABS64:
140 case R_AMDGPU_REL64:
141 write64le(loc, val);
142 break;
143 case R_AMDGPU_GOTPCREL32_HI:
144 case R_AMDGPU_REL32_HI:
145 write32le(loc, val >> 32);
146 break;
147 case R_AMDGPU_REL16: {
148 int64_t simm = (static_cast<int64_t>(val) - 4) / 4;
149 checkInt(loc, simm, 16, rel);
150 write16le(loc, simm);
151 break;
153 default:
154 llvm_unreachable("unknown relocation");
158 RelExpr AMDGPU::getRelExpr(RelType type, const Symbol &s,
159 const uint8_t *loc) const {
160 switch (type) {
161 case R_AMDGPU_ABS32:
162 case R_AMDGPU_ABS64:
163 return R_ABS;
164 case R_AMDGPU_REL32:
165 case R_AMDGPU_REL32_LO:
166 case R_AMDGPU_REL32_HI:
167 case R_AMDGPU_REL64:
168 case R_AMDGPU_REL16:
169 return R_PC;
170 case R_AMDGPU_GOTPCREL:
171 case R_AMDGPU_GOTPCREL32_LO:
172 case R_AMDGPU_GOTPCREL32_HI:
173 return R_GOT_PC;
174 default:
175 error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) +
176 ") against symbol " + toString(s));
177 return R_NONE;
181 RelType AMDGPU::getDynRel(RelType type) const {
182 if (type == R_AMDGPU_ABS64)
183 return type;
184 return R_AMDGPU_NONE;
187 int64_t AMDGPU::getImplicitAddend(const uint8_t *buf, RelType type) const {
188 switch (type) {
189 case R_AMDGPU_NONE:
190 return 0;
191 case R_AMDGPU_ABS64:
192 case R_AMDGPU_RELATIVE64:
193 return read64(buf);
194 default:
195 internalLinkerError(getErrorLocation(buf),
196 "cannot read addend for relocation " + toString(type));
197 return 0;
201 TargetInfo *elf::getAMDGPUTargetInfo() {
202 static AMDGPU target;
203 return &target;