xref: /openbsd-src/gnu/llvm/lld/ELF/Arch/AMDGPU.cpp (revision dfe94b169149f14cc1aee2cf6dad58a8d9a1860c)
1ece8a530Spatrick //===- AMDGPU.cpp ---------------------------------------------------------===//
2ece8a530Spatrick //
3ece8a530Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4ece8a530Spatrick // See https://llvm.org/LICENSE.txt for license information.
5ece8a530Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ece8a530Spatrick //
7ece8a530Spatrick //===----------------------------------------------------------------------===//
8ece8a530Spatrick 
9ece8a530Spatrick #include "InputFiles.h"
10ece8a530Spatrick #include "Symbols.h"
11ece8a530Spatrick #include "Target.h"
12ece8a530Spatrick #include "lld/Common/ErrorHandler.h"
13*dfe94b16Srobert #include "llvm/BinaryFormat/ELF.h"
14ece8a530Spatrick #include "llvm/Support/Endian.h"
15ece8a530Spatrick 
16ece8a530Spatrick using namespace llvm;
17ece8a530Spatrick using namespace llvm::object;
18ece8a530Spatrick using namespace llvm::support::endian;
19ece8a530Spatrick using namespace llvm::ELF;
20bb684c34Spatrick using namespace lld;
21bb684c34Spatrick using namespace lld::elf;
22ece8a530Spatrick 
23ece8a530Spatrick namespace {
24ece8a530Spatrick class AMDGPU final : public TargetInfo {
251cf9926bSpatrick private:
261cf9926bSpatrick   uint32_t calcEFlagsV3() const;
271cf9926bSpatrick   uint32_t calcEFlagsV4() const;
281cf9926bSpatrick 
29ece8a530Spatrick public:
30ece8a530Spatrick   AMDGPU();
31ece8a530Spatrick   uint32_t calcEFlags() const override;
32bb684c34Spatrick   void relocate(uint8_t *loc, const Relocation &rel,
33bb684c34Spatrick                 uint64_t val) const override;
34ece8a530Spatrick   RelExpr getRelExpr(RelType type, const Symbol &s,
35ece8a530Spatrick                      const uint8_t *loc) const override;
36ece8a530Spatrick   RelType getDynRel(RelType type) const override;
37ece8a530Spatrick };
38ece8a530Spatrick } // namespace
39ece8a530Spatrick 
AMDGPU()40ece8a530Spatrick AMDGPU::AMDGPU() {
41ece8a530Spatrick   relativeRel = R_AMDGPU_RELATIVE64;
42ece8a530Spatrick   gotRel = R_AMDGPU_ABS64;
43ece8a530Spatrick   symbolicRel = R_AMDGPU_ABS64;
44ece8a530Spatrick }
45ece8a530Spatrick 
getEFlags(InputFile * file)46ece8a530Spatrick static uint32_t getEFlags(InputFile *file) {
471cf9926bSpatrick   return cast<ObjFile<ELF64LE>>(file)->getObj().getHeader().e_flags;
48ece8a530Spatrick }
49ece8a530Spatrick 
calcEFlagsV3() const501cf9926bSpatrick uint32_t AMDGPU::calcEFlagsV3() const {
51*dfe94b16Srobert   uint32_t ret = getEFlags(ctx.objectFiles[0]);
52ece8a530Spatrick 
53ece8a530Spatrick   // Verify that all input files have the same e_flags.
54*dfe94b16Srobert   for (InputFile *f : ArrayRef(ctx.objectFiles).slice(1)) {
55ece8a530Spatrick     if (ret == getEFlags(f))
56ece8a530Spatrick       continue;
57ece8a530Spatrick     error("incompatible e_flags: " + toString(f));
58ece8a530Spatrick     return 0;
59ece8a530Spatrick   }
60ece8a530Spatrick   return ret;
61ece8a530Spatrick }
62ece8a530Spatrick 
calcEFlagsV4() const631cf9926bSpatrick uint32_t AMDGPU::calcEFlagsV4() const {
64*dfe94b16Srobert   uint32_t retMach = getEFlags(ctx.objectFiles[0]) & EF_AMDGPU_MACH;
65*dfe94b16Srobert   uint32_t retXnack =
66*dfe94b16Srobert       getEFlags(ctx.objectFiles[0]) & EF_AMDGPU_FEATURE_XNACK_V4;
671cf9926bSpatrick   uint32_t retSramEcc =
68*dfe94b16Srobert       getEFlags(ctx.objectFiles[0]) & EF_AMDGPU_FEATURE_SRAMECC_V4;
691cf9926bSpatrick 
701cf9926bSpatrick   // Verify that all input files have compatible e_flags (same mach, all
711cf9926bSpatrick   // features in the same category are either ANY, ANY and ON, or ANY and OFF).
72*dfe94b16Srobert   for (InputFile *f : ArrayRef(ctx.objectFiles).slice(1)) {
731cf9926bSpatrick     if (retMach != (getEFlags(f) & EF_AMDGPU_MACH)) {
741cf9926bSpatrick       error("incompatible mach: " + toString(f));
751cf9926bSpatrick       return 0;
761cf9926bSpatrick     }
771cf9926bSpatrick 
781cf9926bSpatrick     if (retXnack == EF_AMDGPU_FEATURE_XNACK_UNSUPPORTED_V4 ||
791cf9926bSpatrick         (retXnack != EF_AMDGPU_FEATURE_XNACK_ANY_V4 &&
801cf9926bSpatrick             (getEFlags(f) & EF_AMDGPU_FEATURE_XNACK_V4)
811cf9926bSpatrick                 != EF_AMDGPU_FEATURE_XNACK_ANY_V4)) {
821cf9926bSpatrick       if (retXnack != (getEFlags(f) & EF_AMDGPU_FEATURE_XNACK_V4)) {
831cf9926bSpatrick         error("incompatible xnack: " + toString(f));
841cf9926bSpatrick         return 0;
851cf9926bSpatrick       }
861cf9926bSpatrick     } else {
871cf9926bSpatrick       if (retXnack == EF_AMDGPU_FEATURE_XNACK_ANY_V4)
881cf9926bSpatrick         retXnack = getEFlags(f) & EF_AMDGPU_FEATURE_XNACK_V4;
891cf9926bSpatrick     }
901cf9926bSpatrick 
911cf9926bSpatrick     if (retSramEcc == EF_AMDGPU_FEATURE_SRAMECC_UNSUPPORTED_V4 ||
921cf9926bSpatrick         (retSramEcc != EF_AMDGPU_FEATURE_SRAMECC_ANY_V4 &&
931cf9926bSpatrick             (getEFlags(f) & EF_AMDGPU_FEATURE_SRAMECC_V4) !=
941cf9926bSpatrick                 EF_AMDGPU_FEATURE_SRAMECC_ANY_V4)) {
951cf9926bSpatrick       if (retSramEcc != (getEFlags(f) & EF_AMDGPU_FEATURE_SRAMECC_V4)) {
961cf9926bSpatrick         error("incompatible sramecc: " + toString(f));
971cf9926bSpatrick         return 0;
981cf9926bSpatrick       }
991cf9926bSpatrick     } else {
1001cf9926bSpatrick       if (retSramEcc == EF_AMDGPU_FEATURE_SRAMECC_ANY_V4)
1011cf9926bSpatrick         retSramEcc = getEFlags(f) & EF_AMDGPU_FEATURE_SRAMECC_V4;
1021cf9926bSpatrick     }
1031cf9926bSpatrick   }
1041cf9926bSpatrick 
1051cf9926bSpatrick   return retMach | retXnack | retSramEcc;
1061cf9926bSpatrick }
1071cf9926bSpatrick 
calcEFlags() const1081cf9926bSpatrick uint32_t AMDGPU::calcEFlags() const {
109*dfe94b16Srobert   if (ctx.objectFiles.empty())
110*dfe94b16Srobert     return 0;
1111cf9926bSpatrick 
112*dfe94b16Srobert   uint8_t abiVersion = cast<ObjFile<ELF64LE>>(ctx.objectFiles[0])
113*dfe94b16Srobert                            ->getObj()
114*dfe94b16Srobert                            .getHeader()
115*dfe94b16Srobert                            .e_ident[EI_ABIVERSION];
1161cf9926bSpatrick   switch (abiVersion) {
1171cf9926bSpatrick   case ELFABIVERSION_AMDGPU_HSA_V2:
1181cf9926bSpatrick   case ELFABIVERSION_AMDGPU_HSA_V3:
1191cf9926bSpatrick     return calcEFlagsV3();
1201cf9926bSpatrick   case ELFABIVERSION_AMDGPU_HSA_V4:
121*dfe94b16Srobert   case ELFABIVERSION_AMDGPU_HSA_V5:
1221cf9926bSpatrick     return calcEFlagsV4();
1231cf9926bSpatrick   default:
1241cf9926bSpatrick     error("unknown abi version: " + Twine(abiVersion));
1251cf9926bSpatrick     return 0;
1261cf9926bSpatrick   }
1271cf9926bSpatrick }
1281cf9926bSpatrick 
relocate(uint8_t * loc,const Relocation & rel,uint64_t val) const129bb684c34Spatrick void AMDGPU::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
130bb684c34Spatrick   switch (rel.type) {
131ece8a530Spatrick   case R_AMDGPU_ABS32:
132ece8a530Spatrick   case R_AMDGPU_GOTPCREL:
133ece8a530Spatrick   case R_AMDGPU_GOTPCREL32_LO:
134ece8a530Spatrick   case R_AMDGPU_REL32:
135ece8a530Spatrick   case R_AMDGPU_REL32_LO:
136ece8a530Spatrick     write32le(loc, val);
137ece8a530Spatrick     break;
138ece8a530Spatrick   case R_AMDGPU_ABS64:
139ece8a530Spatrick   case R_AMDGPU_REL64:
140ece8a530Spatrick     write64le(loc, val);
141ece8a530Spatrick     break;
142ece8a530Spatrick   case R_AMDGPU_GOTPCREL32_HI:
143ece8a530Spatrick   case R_AMDGPU_REL32_HI:
144ece8a530Spatrick     write32le(loc, val >> 32);
145ece8a530Spatrick     break;
1461cf9926bSpatrick   case R_AMDGPU_REL16: {
1471cf9926bSpatrick     int64_t simm = (static_cast<int64_t>(val) - 4) / 4;
1481cf9926bSpatrick     checkInt(loc, simm, 16, rel);
1491cf9926bSpatrick     write16le(loc, simm);
1501cf9926bSpatrick     break;
1511cf9926bSpatrick   }
152ece8a530Spatrick   default:
153ece8a530Spatrick     llvm_unreachable("unknown relocation");
154ece8a530Spatrick   }
155ece8a530Spatrick }
156ece8a530Spatrick 
getRelExpr(RelType type,const Symbol & s,const uint8_t * loc) const157ece8a530Spatrick RelExpr AMDGPU::getRelExpr(RelType type, const Symbol &s,
158ece8a530Spatrick                            const uint8_t *loc) const {
159ece8a530Spatrick   switch (type) {
160ece8a530Spatrick   case R_AMDGPU_ABS32:
161ece8a530Spatrick   case R_AMDGPU_ABS64:
162ece8a530Spatrick     return R_ABS;
163ece8a530Spatrick   case R_AMDGPU_REL32:
164ece8a530Spatrick   case R_AMDGPU_REL32_LO:
165ece8a530Spatrick   case R_AMDGPU_REL32_HI:
166ece8a530Spatrick   case R_AMDGPU_REL64:
1671cf9926bSpatrick   case R_AMDGPU_REL16:
168ece8a530Spatrick     return R_PC;
169ece8a530Spatrick   case R_AMDGPU_GOTPCREL:
170ece8a530Spatrick   case R_AMDGPU_GOTPCREL32_LO:
171ece8a530Spatrick   case R_AMDGPU_GOTPCREL32_HI:
172ece8a530Spatrick     return R_GOT_PC;
173ece8a530Spatrick   default:
174ece8a530Spatrick     error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) +
175ece8a530Spatrick           ") against symbol " + toString(s));
176ece8a530Spatrick     return R_NONE;
177ece8a530Spatrick   }
178ece8a530Spatrick }
179ece8a530Spatrick 
getDynRel(RelType type) const180ece8a530Spatrick RelType AMDGPU::getDynRel(RelType type) const {
181ece8a530Spatrick   if (type == R_AMDGPU_ABS64)
182ece8a530Spatrick     return type;
183ece8a530Spatrick   return R_AMDGPU_NONE;
184ece8a530Spatrick }
185ece8a530Spatrick 
getAMDGPUTargetInfo()186bb684c34Spatrick TargetInfo *elf::getAMDGPUTargetInfo() {
187ece8a530Spatrick   static AMDGPU target;
188ece8a530Spatrick   return &target;
189ece8a530Spatrick }
190