Skip to content

Commit 88e2bb4

Browse files
authored
[clang][SPIR-V] Add support for AMDGCN flavoured SPIRV (#89796)
This change seeks to add support for vendor flavoured SPIRV - more specifically, AMDGCN flavoured SPIRV. The aim is to generate SPIRV that carries some extra bits of information that are only usable by AMDGCN targets, forfeiting absolute genericity to obtain greater expressiveness for target features: - AMDGCN inline ASM is allowed/supported, under the assumption that the [SPV_INTEL_inline_assembly](https://github.com/intel/llvm/blob/sycl/sycl/doc/design/spirv-extensions/SPV_INTEL_inline_assembly.asciidoc) extension is enabled/used - AMDGCN target specific builtins are allowed/supported, under the assumption that e.g. the `--spirv-allow-unknown-intrinsics` option is enabled when using the downstream translator - the featureset matches the union of AMDGCN targets' features - the datalayout string is overspecified to affix both the program address space and the alloca address space, the latter under the assumption that the [SPV_INTEL_function_pointers](https://github.com/intel/llvm/blob/sycl/sycl/doc/design/spirv-extensions/SPV_INTEL_function_pointers.asciidoc) extension is enabled/used, case in which the extant SPIRV datalayout string would lead to pointers to function pointing to the private address space, which would be wrong. Existing AMDGCN tests are extended to cover this new target. It is currently dormant / will require some additional changes, but I thought I'd rather put it up for review to get feedback as early as possible. I will note that an alternative option is to place this under AMDGPU, but that seems slightly less natural, since this is still SPIRV, albeit relaxed in terms of preconditions & constrained in terms of postconditions, and only guaranteed to be usable on AMDGCN targets (it is still possible to obtain pristine portable SPIRV through usage of the flavoured target, though).
1 parent 6fe5428 commit 88e2bb4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1298
-230
lines changed

clang/lib/Basic/Targets.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -673,8 +673,11 @@ std::unique_ptr<TargetInfo> AllocateTarget(const llvm::Triple &Triple,
673673
}
674674
case llvm::Triple::spirv64: {
675675
if (os != llvm::Triple::UnknownOS ||
676-
Triple.getEnvironment() != llvm::Triple::UnknownEnvironment)
676+
Triple.getEnvironment() != llvm::Triple::UnknownEnvironment) {
677+
if (os == llvm::Triple::OSType::AMDHSA)
678+
return std::make_unique<SPIRV64AMDGCNTargetInfo>(Triple, Opts);
677679
return nullptr;
680+
}
678681
return std::make_unique<SPIRV64TargetInfo>(Triple, Opts);
679682
}
680683
case llvm::Triple::wasm32:

clang/lib/Basic/Targets/SPIR.cpp

+75
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "SPIR.h"
14+
#include "AMDGPU.h"
1415
#include "Targets.h"
16+
#include "llvm/TargetParser/TargetParser.h"
1517

1618
using namespace clang;
1719
using namespace clang::targets;
@@ -54,3 +56,76 @@ void SPIRV64TargetInfo::getTargetDefines(const LangOptions &Opts,
5456
BaseSPIRVTargetInfo::getTargetDefines(Opts, Builder);
5557
DefineStd(Builder, "SPIRV64", Opts);
5658
}
59+
60+
static const AMDGPUTargetInfo AMDGPUTI(llvm::Triple("amdgcn-amd-amdhsa"), {});
61+
62+
ArrayRef<const char *> SPIRV64AMDGCNTargetInfo::getGCCRegNames() const {
63+
return AMDGPUTI.getGCCRegNames();
64+
}
65+
66+
bool SPIRV64AMDGCNTargetInfo::initFeatureMap(
67+
llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef,
68+
const std::vector<std::string> &FeatureVec) const {
69+
llvm::AMDGPU::fillAMDGPUFeatureMap({}, getTriple(), Features);
70+
71+
return TargetInfo::initFeatureMap(Features, Diags, {}, FeatureVec);
72+
}
73+
74+
bool SPIRV64AMDGCNTargetInfo::validateAsmConstraint(
75+
const char *&Name, TargetInfo::ConstraintInfo &Info) const {
76+
return AMDGPUTI.validateAsmConstraint(Name, Info);
77+
}
78+
79+
std::string
80+
SPIRV64AMDGCNTargetInfo::convertConstraint(const char *&Constraint) const {
81+
return AMDGPUTI.convertConstraint(Constraint);
82+
}
83+
84+
ArrayRef<Builtin::Info> SPIRV64AMDGCNTargetInfo::getTargetBuiltins() const {
85+
return AMDGPUTI.getTargetBuiltins();
86+
}
87+
88+
void SPIRV64AMDGCNTargetInfo::getTargetDefines(const LangOptions &Opts,
89+
MacroBuilder &Builder) const {
90+
BaseSPIRVTargetInfo::getTargetDefines(Opts, Builder);
91+
DefineStd(Builder, "SPIRV64", Opts);
92+
93+
Builder.defineMacro("__AMD__");
94+
Builder.defineMacro("__AMDGPU__");
95+
Builder.defineMacro("__AMDGCN__");
96+
}
97+
98+
void SPIRV64AMDGCNTargetInfo::setAuxTarget(const TargetInfo *Aux) {
99+
assert(Aux && "Cannot invoke setAuxTarget without a valid auxiliary target!");
100+
101+
// This is a 1:1 copy of AMDGPUTargetInfo::setAuxTarget()
102+
assert(HalfFormat == Aux->HalfFormat);
103+
assert(FloatFormat == Aux->FloatFormat);
104+
assert(DoubleFormat == Aux->DoubleFormat);
105+
106+
// On x86_64 long double is 80-bit extended precision format, which is
107+
// not supported by AMDGPU. 128-bit floating point format is also not
108+
// supported by AMDGPU. Therefore keep its own format for these two types.
109+
auto SaveLongDoubleFormat = LongDoubleFormat;
110+
auto SaveFloat128Format = Float128Format;
111+
auto SaveLongDoubleWidth = LongDoubleWidth;
112+
auto SaveLongDoubleAlign = LongDoubleAlign;
113+
copyAuxTarget(Aux);
114+
LongDoubleFormat = SaveLongDoubleFormat;
115+
Float128Format = SaveFloat128Format;
116+
LongDoubleWidth = SaveLongDoubleWidth;
117+
LongDoubleAlign = SaveLongDoubleAlign;
118+
// For certain builtin types support on the host target, claim they are
119+
// supported to pass the compilation of the host code during the device-side
120+
// compilation.
121+
// FIXME: As the side effect, we also accept `__float128` uses in the device
122+
// code. To reject these builtin types supported in the host target but not in
123+
// the device target, one approach would support `device_builtin` attribute
124+
// so that we could tell the device builtin types from the host ones. This
125+
// also solves the different representations of the same builtin type, such
126+
// as `size_t` in the MSVC environment.
127+
if (Aux->hasFloat128Type()) {
128+
HasFloat128 = true;
129+
Float128Format = DoubleFormat;
130+
}
131+
}

clang/lib/Basic/Targets/SPIR.h

+51
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,57 @@ class LLVM_LIBRARY_VISIBILITY SPIRV64TargetInfo : public BaseSPIRVTargetInfo {
364364
MacroBuilder &Builder) const override;
365365
};
366366

367+
class LLVM_LIBRARY_VISIBILITY SPIRV64AMDGCNTargetInfo final
368+
: public BaseSPIRVTargetInfo {
369+
public:
370+
SPIRV64AMDGCNTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
371+
: BaseSPIRVTargetInfo(Triple, Opts) {
372+
assert(Triple.getArch() == llvm::Triple::spirv64 &&
373+
"Invalid architecture for 64-bit AMDGCN SPIR-V.");
374+
assert(Triple.getVendor() == llvm::Triple::VendorType::AMD &&
375+
"64-bit AMDGCN SPIR-V target must use AMD vendor");
376+
assert(getTriple().getOS() == llvm::Triple::OSType::AMDHSA &&
377+
"64-bit AMDGCN SPIR-V target must use AMDHSA OS");
378+
assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment &&
379+
"64-bit SPIR-V target must use unknown environment type");
380+
PointerWidth = PointerAlign = 64;
381+
SizeType = TargetInfo::UnsignedLong;
382+
PtrDiffType = IntPtrType = TargetInfo::SignedLong;
383+
384+
resetDataLayout("e-i64:64-v16:16-v24:32-v32:32-v48:64-"
385+
"v96:128-v192:256-v256:256-v512:512-v1024:1024-G1-P4-A0");
386+
387+
BFloat16Width = BFloat16Align = 16;
388+
BFloat16Format = &llvm::APFloat::BFloat();
389+
390+
HasLegalHalfType = true;
391+
HasFloat16 = true;
392+
HalfArgsAndReturns = true;
393+
}
394+
395+
bool hasBFloat16Type() const override { return true; }
396+
397+
ArrayRef<const char *> getGCCRegNames() const override;
398+
399+
bool initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags,
400+
StringRef,
401+
const std::vector<std::string> &) const override;
402+
403+
bool validateAsmConstraint(const char *&Name,
404+
TargetInfo::ConstraintInfo &Info) const override;
405+
406+
std::string convertConstraint(const char *&Constraint) const override;
407+
408+
ArrayRef<Builtin::Info> getTargetBuiltins() const override;
409+
410+
void getTargetDefines(const LangOptions &Opts,
411+
MacroBuilder &Builder) const override;
412+
413+
void setAuxTarget(const TargetInfo *Aux) override;
414+
415+
bool hasInt128Type() const override { return TargetInfo::hasInt128Type(); }
416+
};
417+
367418
} // namespace targets
368419
} // namespace clang
369420
#endif // LLVM_CLANG_LIB_BASIC_TARGETS_SPIR_H

clang/lib/CodeGen/CGBuiltin.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -6012,6 +6012,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
60126012
llvm::Triple::getArchTypePrefix(getTarget().getTriple().getArch());
60136013
if (!Prefix.empty()) {
60146014
IntrinsicID = Intrinsic::getIntrinsicForClangBuiltin(Prefix.data(), Name);
6015+
if (IntrinsicID == Intrinsic::not_intrinsic && Prefix == "spv" &&
6016+
getTarget().getTriple().getOS() == llvm::Triple::OSType::AMDHSA)
6017+
IntrinsicID = Intrinsic::getIntrinsicForClangBuiltin("amdgcn", Name);
60156018
// NOTE we don't need to perform a compatibility flag check here since the
60166019
// intrinsics are declared in Builtins*.def via LANGBUILTIN which filter the
60176020
// MS builtins via ALL_MS_LANGUAGES and are filtered earlier.
@@ -6182,6 +6185,10 @@ static Value *EmitTargetArchBuiltinExpr(CodeGenFunction *CGF,
61826185
case llvm::Triple::riscv32:
61836186
case llvm::Triple::riscv64:
61846187
return CGF->EmitRISCVBuiltinExpr(BuiltinID, E, ReturnValue);
6188+
case llvm::Triple::spirv64:
6189+
if (CGF->getTarget().getTriple().getOS() != llvm::Triple::OSType::AMDHSA)
6190+
return nullptr;
6191+
return CGF->EmitAMDGPUBuiltinExpr(BuiltinID, E);
61856192
default:
61866193
return nullptr;
61876194
}

clang/test/CodeGen/target-data.c

+4
Original file line numberDiff line numberDiff line change
@@ -268,3 +268,7 @@
268268
// RUN: %clang_cc1 -triple ve -o - -emit-llvm %s | \
269269
// RUN: FileCheck %s -check-prefix=VE
270270
// VE: target datalayout = "e-m:e-i64:64-n32:64-S128-v64:64:64-v128:64:64-v256:64:64-v512:64:64-v1024:64:64-v2048:64:64-v4096:64:64-v8192:64:64-v16384:64:64"
271+
272+
// RUN: %clang_cc1 -triple spirv64-amd -o - -emit-llvm %s | \
273+
// RUN: FileCheck %s -check-prefix=SPIR64
274+
// AMDGPUSPIRV64: target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-G1-P4-A0"

0 commit comments

Comments
 (0)