1//===--- NVPTX.h - Declare NVPTX target feature support ---------*- C++ -*-===//
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 declares NVPTX TargetInfo objects.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_NVPTX_H
14#define LLVM_CLANG_LIB_BASIC_TARGETS_NVPTX_H
15
16#include "clang/Basic/Cuda.h"
17#include "clang/Basic/TargetInfo.h"
18#include "clang/Basic/TargetOptions.h"
19#include "llvm/Support/Compiler.h"
20#include "llvm/Support/NVPTXAddrSpace.h"
21#include "llvm/TargetParser/Triple.h"
22#include <optional>
23
24namespace clang {
25namespace targets {
26
27static constexpr LangASMap NVPTXAddrSpaceMap = {
28 {LangAS::opencl_global, 1},
29 {LangAS::opencl_local, 3},
30 {LangAS::opencl_constant, 4},
31 // FIXME: generic has to be added to the target
32 {LangAS::opencl_generic, 0},
33 {LangAS::opencl_global_device, 1},
34 {LangAS::opencl_global_host, 1},
35 {LangAS::cuda_device, 1},
36 {LangAS::cuda_constant, 4},
37 {LangAS::cuda_shared, 3},
38 {LangAS::sycl_global, 1},
39 {LangAS::sycl_global_device, 1},
40 {LangAS::sycl_global_host, 1},
41 {LangAS::sycl_local, 3},
42 {LangAS::sycl_private, 0},
43 {LangAS::sycl_generic, 0},
44 {LangAS::sycl_constant, 4},
45};
46
47/// The DWARF address class. Taken from
48/// https://docs.nvidia.com/cuda/archive/10.0/ptx-writers-guide-to-interoperability/index.html#cuda-specific-dwarf
49static const int NVPTXDWARFAddrSpaceMap[] = {
50 -1, // Default, opencl_private or opencl_generic - not defined
51 5, // opencl_global
52 -1,
53 8, // opencl_local or cuda_shared
54 4, // opencl_constant or cuda_constant
55};
56
57class LLVM_LIBRARY_VISIBILITY NVPTXTargetInfo : public TargetInfo {
58 static const char *const GCCRegNames[];
59 OffloadArch GPU;
60 uint32_t PTXVersion;
61 std::unique_ptr<TargetInfo> HostTarget;
62
63public:
64 NVPTXTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts,
65 unsigned TargetPointerWidth);
66
67 void getTargetDefines(const LangOptions &Opts,
68 MacroBuilder &Builder) const override;
69
70 llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override;
71
72 bool isCLZForZeroUndef() const override { return false; }
73
74 bool
75 initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags,
76 StringRef CPU,
77 const std::vector<std::string> &FeaturesVec) const override {
78 if (!GPU.isUnused())
79 Features[OffloadArchToString(A: GPU)] = true;
80 // Only add PTX feature if explicitly requested. Otherwise, let the backend
81 // use the minimum required PTX version for the target SM.
82 if (PTXVersion != 0)
83 Features["ptx" + std::to_string(val: PTXVersion)] = true;
84 return TargetInfo::initFeatureMap(Features, Diags, CPU, FeatureVec: FeaturesVec);
85 }
86
87 bool hasFeature(StringRef Feature) const override;
88
89 bool setABI(const std::string &Name) override;
90
91 virtual bool isAddressSpaceSupersetOf(LangAS A, LangAS B) const override {
92 // The generic address space AS(0) is a superset of all the other address
93 // spaces used by the backend target.
94 return A == B ||
95 ((A == LangAS::Default ||
96 (isTargetAddressSpace(AS: A) &&
97 toTargetAddressSpace(AS: A) ==
98 llvm::NVPTXAS::ADDRESS_SPACE_GENERIC)) &&
99 isTargetAddressSpace(AS: B) &&
100 toTargetAddressSpace(AS: B) >= llvm::NVPTXAS::ADDRESS_SPACE_GENERIC &&
101 toTargetAddressSpace(AS: B) <= llvm::NVPTXAS::ADDRESS_SPACE_LOCAL &&
102 toTargetAddressSpace(AS: B) != 2);
103 }
104
105 ArrayRef<const char *> getGCCRegNames() const override;
106
107 ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
108 // No aliases.
109 return {};
110 }
111
112 bool validateAsmConstraint(const char *&Name,
113 TargetInfo::ConstraintInfo &Info) const override {
114 switch (*Name) {
115 default:
116 return false;
117 case 'c':
118 case 'h':
119 case 'r':
120 case 'l':
121 case 'f':
122 case 'd':
123 case 'q':
124 Info.setAllowsRegister();
125 return true;
126 }
127 }
128
129 std::string_view getClobbers() const override {
130 // FIXME: Is this really right?
131 return "";
132 }
133
134 BuiltinVaListKind getBuiltinVaListKind() const override {
135 return TargetInfo::CharPtrBuiltinVaList;
136 }
137
138 // StringToOffloadArch also recognizes other vendors' GPUs, so accept only an
139 // NVPTX one.
140 bool isValidCPUName(StringRef Name) const override {
141 return StringToOffloadArch(S: Name).isNVPTX();
142 }
143
144 void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override {
145#define NVPTX_GPU(NAME, KIND, VIRTUAL, SM_ID, MIN_VER, MAX_VER, SUFFIX) \
146 Values.push_back(NAME);
147#include "llvm/TargetParser/NVPTXTargetParser.def"
148 }
149
150 bool setCPU(StringRef Name) override {
151 GPU = StringToOffloadArch(S: Name);
152 return GPU.isNVPTX();
153 }
154 void adjust(DiagnosticsEngine &Diags, LangOptions &Opts,
155 const TargetInfo *Aux) override;
156
157 void setSupportedOpenCLOpts() override {
158 auto &Opts = getSupportedOpenCLOpts();
159 Opts["cl_clang_storage_class_specifiers"] = true;
160 Opts["__cl_clang_function_pointers"] = true;
161 Opts["__cl_clang_variadic_functions"] = true;
162 Opts["__cl_clang_function_scope_local_variables"] = true;
163 Opts["__cl_clang_non_portable_kernel_param_types"] = true;
164 Opts["__cl_clang_bitfields"] = true;
165
166 Opts["cl_khr_fp64"] = true;
167 Opts["__opencl_c_fp64"] = true;
168 Opts["cl_khr_byte_addressable_store"] = true;
169 Opts["cl_khr_global_int32_base_atomics"] = true;
170 Opts["cl_khr_global_int32_extended_atomics"] = true;
171 Opts["cl_khr_local_int32_base_atomics"] = true;
172 Opts["cl_khr_local_int32_extended_atomics"] = true;
173
174 Opts["__opencl_c_images"] = true;
175 Opts["__opencl_c_3d_image_writes"] = true;
176 Opts["cl_khr_3d_image_writes"] = true;
177
178 Opts["__opencl_c_generic_address_space"] = true;
179 }
180
181 const llvm::omp::GV &getGridValue() const override {
182 return llvm::omp::NVPTXGridValues;
183 }
184
185 /// \returns If a target requires an address within a target specific address
186 /// space \p AddressSpace to be converted in order to be used, then return the
187 /// corresponding target specific DWARF address space.
188 ///
189 /// \returns Otherwise return std::nullopt and no conversion will be emitted
190 /// in the DWARF.
191 std::optional<unsigned>
192 getDWARFAddressSpace(unsigned AddressSpace) const override {
193 if (AddressSpace >= std::size(NVPTXDWARFAddrSpaceMap) ||
194 NVPTXDWARFAddrSpaceMap[AddressSpace] < 0)
195 return std::nullopt;
196 return NVPTXDWARFAddrSpaceMap[AddressSpace];
197 }
198
199 CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
200 // CUDA compilations support all of the host's calling conventions.
201 //
202 // TODO: We should warn if you apply a non-default CC to anything other than
203 // a host function.
204 if (HostTarget)
205 return HostTarget->checkCallingConvention(CC);
206 return CC == CC_DeviceKernel ? CCCR_OK : CCCR_Warning;
207 }
208
209 bool hasBitIntType() const override { return true; }
210 bool hasBFloat16Type() const override { return true; }
211
212 OffloadArch getGPU() const { return GPU; }
213};
214} // namespace targets
215} // namespace clang
216#endif // LLVM_CLANG_LIB_BASIC_TARGETS_NVPTX_H
217