1 | //===--- SPIR.cpp - Implement SPIR and SPIR-V target feature support ------===// |
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 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file implements SPIR and SPIR-V TargetInfo objects. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "SPIR.h" |
14 | #include "AMDGPU.h" |
15 | #include "Targets.h" |
16 | #include "llvm/TargetParser/TargetParser.h" |
17 | |
18 | using namespace clang; |
19 | using namespace clang::targets; |
20 | |
21 | void SPIRTargetInfo::getTargetDefines(const LangOptions &Opts, |
22 | MacroBuilder &Builder) const { |
23 | DefineStd(Builder, MacroName: "SPIR" , Opts); |
24 | } |
25 | |
26 | void SPIR32TargetInfo::getTargetDefines(const LangOptions &Opts, |
27 | MacroBuilder &Builder) const { |
28 | SPIRTargetInfo::getTargetDefines(Opts, Builder); |
29 | DefineStd(Builder, MacroName: "SPIR32" , Opts); |
30 | } |
31 | |
32 | void SPIR64TargetInfo::getTargetDefines(const LangOptions &Opts, |
33 | MacroBuilder &Builder) const { |
34 | SPIRTargetInfo::getTargetDefines(Opts, Builder); |
35 | DefineStd(Builder, MacroName: "SPIR64" , Opts); |
36 | } |
37 | |
38 | void BaseSPIRVTargetInfo::getTargetDefines(const LangOptions &Opts, |
39 | MacroBuilder &Builder) const { |
40 | DefineStd(Builder, MacroName: "SPIRV" , Opts); |
41 | } |
42 | |
43 | void SPIRVTargetInfo::getTargetDefines(const LangOptions &Opts, |
44 | MacroBuilder &Builder) const { |
45 | BaseSPIRVTargetInfo::getTargetDefines(Opts, Builder); |
46 | } |
47 | |
48 | void SPIRV32TargetInfo::getTargetDefines(const LangOptions &Opts, |
49 | MacroBuilder &Builder) const { |
50 | BaseSPIRVTargetInfo::getTargetDefines(Opts, Builder); |
51 | DefineStd(Builder, MacroName: "SPIRV32" , Opts); |
52 | } |
53 | |
54 | void SPIRV64TargetInfo::getTargetDefines(const LangOptions &Opts, |
55 | MacroBuilder &Builder) const { |
56 | BaseSPIRVTargetInfo::getTargetDefines(Opts, Builder); |
57 | DefineStd(Builder, MacroName: "SPIRV64" , Opts); |
58 | } |
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(GPU: {}, T: getTriple(), Features); |
70 | |
71 | return TargetInfo::initFeatureMap(Features, Diags, CPU: {}, 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, MacroName: "SPIRV64" , Opts); |
92 | |
93 | Builder.defineMacro(Name: "__AMD__" ); |
94 | Builder.defineMacro(Name: "__AMDGPU__" ); |
95 | Builder.defineMacro(Name: "__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 | } |
132 | |