/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/clang/lib/Basic/Targets/AMDGPU.h
Line | Count | Source (jump to first uncovered line) |
1 | | //===--- AMDGPU.h - Declare AMDGPU 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 AMDGPU TargetInfo objects. |
10 | | // |
11 | | //===----------------------------------------------------------------------===// |
12 | | |
13 | | #ifndef LLVM_CLANG_LIB_BASIC_TARGETS_AMDGPU_H |
14 | | #define LLVM_CLANG_LIB_BASIC_TARGETS_AMDGPU_H |
15 | | |
16 | | #include "clang/Basic/TargetInfo.h" |
17 | | #include "clang/Basic/TargetOptions.h" |
18 | | #include "llvm/ADT/StringSet.h" |
19 | | #include "llvm/ADT/Triple.h" |
20 | | #include "llvm/Support/Compiler.h" |
21 | | #include "llvm/Support/TargetParser.h" |
22 | | |
23 | | namespace clang { |
24 | | namespace targets { |
25 | | |
26 | | class LLVM_LIBRARY_VISIBILITY AMDGPUTargetInfo final : public TargetInfo { |
27 | | |
28 | | static const Builtin::Info BuiltinInfo[]; |
29 | | static const char *const GCCRegNames[]; |
30 | | |
31 | | enum AddrSpace { |
32 | | Generic = 0, |
33 | | Global = 1, |
34 | | Local = 3, |
35 | | Constant = 4, |
36 | | Private = 5 |
37 | | }; |
38 | | static const LangASMap AMDGPUDefIsGenMap; |
39 | | static const LangASMap AMDGPUDefIsPrivMap; |
40 | | |
41 | | llvm::AMDGPU::GPUKind GPUKind; |
42 | | unsigned GPUFeatures; |
43 | | |
44 | 858 | bool hasFP64() const { |
45 | 858 | return getTriple().getArch() == llvm::Triple::amdgcn || |
46 | 858 | !!(GPUFeatures & llvm::AMDGPU::FEATURE_FP64)197 ; |
47 | 858 | } |
48 | | |
49 | | /// Has fast fma f32 |
50 | 568 | bool hasFastFMAF() const { |
51 | 568 | return !!(GPUFeatures & llvm::AMDGPU::FEATURE_FAST_FMA_F32); |
52 | 568 | } |
53 | | |
54 | | /// Has fast fma f64 |
55 | 287 | bool hasFastFMA() const { |
56 | 287 | return getTriple().getArch() == llvm::Triple::amdgcn; |
57 | 287 | } |
58 | | |
59 | 287 | bool hasFMAF() const { |
60 | 287 | return getTriple().getArch() == llvm::Triple::amdgcn || |
61 | 287 | !!(GPUFeatures & llvm::AMDGPU::FEATURE_FMA)65 ; |
62 | 287 | } |
63 | | |
64 | 176 | bool hasFullRateDenormalsF32() const { |
65 | 176 | return !!(GPUFeatures & llvm::AMDGPU::FEATURE_FAST_DENORMAL_F32); |
66 | 176 | } |
67 | | |
68 | 287 | bool hasLDEXPF() const { |
69 | 287 | return getTriple().getArch() == llvm::Triple::amdgcn || |
70 | 287 | !!(GPUFeatures & llvm::AMDGPU::FEATURE_LDEXP)65 ; |
71 | 287 | } |
72 | | |
73 | 2.47k | static bool isAMDGCN(const llvm::Triple &TT) { |
74 | 2.47k | return TT.getArch() == llvm::Triple::amdgcn; |
75 | 2.47k | } |
76 | | |
77 | 958 | static bool isR600(const llvm::Triple &TT) { |
78 | 958 | return TT.getArch() == llvm::Triple::r600; |
79 | 958 | } |
80 | | |
81 | | public: |
82 | | AMDGPUTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts); |
83 | | |
84 | | void setAddressSpaceMap(bool DefaultIsPrivate); |
85 | | |
86 | | void adjust(LangOptions &Opts) override; |
87 | | |
88 | 958 | uint64_t getPointerWidthV(unsigned AddrSpace) const override { |
89 | 958 | if (isR600(getTriple())) |
90 | 46 | return 32; |
91 | 912 | |
92 | 912 | if (AddrSpace == Private || AddrSpace == Local796 ) |
93 | 518 | return 32; |
94 | 394 | |
95 | 394 | return 64; |
96 | 394 | } |
97 | | |
98 | 468 | uint64_t getPointerAlignV(unsigned AddrSpace) const override { |
99 | 468 | return getPointerWidthV(AddrSpace); |
100 | 468 | } |
101 | | |
102 | 2.11k | uint64_t getMaxPointerWidth() const override { |
103 | 2.11k | return getTriple().getArch() == llvm::Triple::amdgcn ? 641.89k : 32214 ; |
104 | 2.11k | } |
105 | | |
106 | 4 | const char *getClobbers() const override { return ""; } |
107 | | |
108 | | ArrayRef<const char *> getGCCRegNames() const override; |
109 | | |
110 | 6 | ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { |
111 | 6 | return None; |
112 | 6 | } |
113 | | |
114 | | /// Accepted register names: (n, m is unsigned integer, n < m) |
115 | | /// v |
116 | | /// s |
117 | | /// {vn}, {v[n]} |
118 | | /// {sn}, {s[n]} |
119 | | /// {S} , where S is a special register name |
120 | | ////{v[n:m]} |
121 | | /// {s[n:m]} |
122 | | bool validateAsmConstraint(const char *&Name, |
123 | 60 | TargetInfo::ConstraintInfo &Info) const override { |
124 | 60 | static const ::llvm::StringSet<> SpecialRegs({ |
125 | 60 | "exec", "vcc", "flat_scratch", "m0", "scc", "tba", "tma", |
126 | 60 | "flat_scratch_lo", "flat_scratch_hi", "vcc_lo", "vcc_hi", "exec_lo", |
127 | 60 | "exec_hi", "tma_lo", "tma_hi", "tba_lo", "tba_hi", |
128 | 60 | }); |
129 | 60 | |
130 | 60 | StringRef S(Name); |
131 | 60 | bool HasLeftParen = false; |
132 | 60 | if (S.front() == '{') { |
133 | 45 | HasLeftParen = true; |
134 | 45 | S = S.drop_front(); |
135 | 45 | } |
136 | 60 | if (S.empty()) |
137 | 1 | return false; |
138 | 59 | if (S.front() != 'v' && S.front() != 's'14 ) { |
139 | 8 | if (!HasLeftParen) |
140 | 0 | return false; |
141 | 8 | auto E = S.find('}'); |
142 | 8 | if (!SpecialRegs.count(S.substr(0, E))) |
143 | 5 | return false; |
144 | 3 | S = S.drop_front(E + 1); |
145 | 3 | if (!S.empty()) |
146 | 2 | return false; |
147 | 1 | // Found {S} where S is a special register. |
148 | 1 | Info.setAllowsRegister(); |
149 | 1 | Name = S.data() - 1; |
150 | 1 | return true; |
151 | 1 | } |
152 | 51 | S = S.drop_front(); |
153 | 51 | if (!HasLeftParen) { |
154 | 15 | if (!S.empty()) |
155 | 4 | return false; |
156 | 11 | // Found s or v. |
157 | 11 | Info.setAllowsRegister(); |
158 | 11 | Name = S.data() - 1; |
159 | 11 | return true; |
160 | 11 | } |
161 | 36 | bool HasLeftBracket = false; |
162 | 36 | if (!S.empty() && S.front() == '['35 ) { |
163 | 21 | HasLeftBracket = true; |
164 | 21 | S = S.drop_front(); |
165 | 21 | } |
166 | 36 | unsigned long long N; |
167 | 36 | if (S.empty() || consumeUnsignedInteger(S, 10, N)35 ) |
168 | 4 | return false; |
169 | 32 | if (!S.empty() && S.front() == ':'31 ) { |
170 | 14 | if (!HasLeftBracket) |
171 | 0 | return false; |
172 | 14 | S = S.drop_front(); |
173 | 14 | unsigned long long M; |
174 | 14 | if (consumeUnsignedInteger(S, 10, M) || N >= M12 ) |
175 | 3 | return false; |
176 | 29 | } |
177 | 29 | if (HasLeftBracket) { |
178 | 16 | if (S.empty() || S.front() != ']') |
179 | 2 | return false; |
180 | 14 | S = S.drop_front(); |
181 | 14 | } |
182 | 29 | if (27 S.empty()27 || S.front() != '}'24 ) |
183 | 5 | return false; |
184 | 22 | S = S.drop_front(); |
185 | 22 | if (!S.empty()) |
186 | 2 | return false; |
187 | 20 | // Found {vn}, {sn}, {v[n]}, {s[n]}, {v[n:m]}, or {s[n:m]}. |
188 | 20 | Info.setAllowsRegister(); |
189 | 20 | Name = S.data() - 1; |
190 | 20 | return true; |
191 | 20 | } |
192 | | |
193 | | // \p Constraint will be left pointing at the last character of |
194 | | // the constraint. In practice, it won't be changed unless the |
195 | | // constraint is longer than one character. |
196 | 2 | std::string convertConstraint(const char *&Constraint) const override { |
197 | 2 | const char *Begin = Constraint; |
198 | 2 | TargetInfo::ConstraintInfo Info("", ""); |
199 | 2 | if (validateAsmConstraint(Constraint, Info)) |
200 | 2 | return std::string(Begin).substr(0, Constraint - Begin + 1); |
201 | 0 | |
202 | 0 | Constraint = Begin; |
203 | 0 | return std::string(1, *Constraint); |
204 | 0 | } |
205 | | |
206 | | bool |
207 | | initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, |
208 | | StringRef CPU, |
209 | | const std::vector<std::string> &FeatureVec) const override; |
210 | | |
211 | | void adjustTargetOptions(const CodeGenOptions &CGOpts, |
212 | | TargetOptions &TargetOpts) const override; |
213 | | |
214 | | ArrayRef<Builtin::Info> getTargetBuiltins() const override; |
215 | | |
216 | | void getTargetDefines(const LangOptions &Opts, |
217 | | MacroBuilder &Builder) const override; |
218 | | |
219 | 214 | BuiltinVaListKind getBuiltinVaListKind() const override { |
220 | 214 | return TargetInfo::CharPtrBuiltinVaList; |
221 | 214 | } |
222 | | |
223 | 16 | bool isValidCPUName(StringRef Name) const override { |
224 | 16 | if (getTriple().getArch() == llvm::Triple::amdgcn) |
225 | 16 | return llvm::AMDGPU::parseArchAMDGCN(Name) != llvm::AMDGPU::GK_NONE; |
226 | 0 | return llvm::AMDGPU::parseArchR600(Name) != llvm::AMDGPU::GK_NONE; |
227 | 0 | } |
228 | | |
229 | | void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override; |
230 | | |
231 | 171 | bool setCPU(const std::string &Name) override { |
232 | 171 | if (getTriple().getArch() == llvm::Triple::amdgcn) { |
233 | 110 | GPUKind = llvm::AMDGPU::parseArchAMDGCN(Name); |
234 | 110 | GPUFeatures = llvm::AMDGPU::getArchAttrAMDGCN(GPUKind); |
235 | 110 | } else { |
236 | 61 | GPUKind = llvm::AMDGPU::parseArchR600(Name); |
237 | 61 | GPUFeatures = llvm::AMDGPU::getArchAttrR600(GPUKind); |
238 | 61 | } |
239 | 171 | |
240 | 171 | return GPUKind != llvm::AMDGPU::GK_NONE; |
241 | 171 | } |
242 | | |
243 | 288 | void setSupportedOpenCLOpts() override { |
244 | 288 | auto &Opts = getSupportedOpenCLOpts(); |
245 | 288 | Opts.support("cl_clang_storage_class_specifiers"); |
246 | 288 | Opts.support("cl_khr_icd"); |
247 | 288 | |
248 | 288 | bool IsAMDGCN = isAMDGCN(getTriple()); |
249 | 288 | |
250 | 288 | if (hasFP64()) |
251 | 222 | Opts.support("cl_khr_fp64"); |
252 | 288 | |
253 | 288 | if (IsAMDGCN || GPUKind >= llvm::AMDGPU::GK_CEDAR66 ) { |
254 | 263 | Opts.support("cl_khr_byte_addressable_store"); |
255 | 263 | Opts.support("cl_khr_global_int32_base_atomics"); |
256 | 263 | Opts.support("cl_khr_global_int32_extended_atomics"); |
257 | 263 | Opts.support("cl_khr_local_int32_base_atomics"); |
258 | 263 | Opts.support("cl_khr_local_int32_extended_atomics"); |
259 | 263 | } |
260 | 288 | |
261 | 288 | if (IsAMDGCN) { |
262 | 222 | Opts.support("cl_khr_fp16"); |
263 | 222 | Opts.support("cl_khr_int64_base_atomics"); |
264 | 222 | Opts.support("cl_khr_int64_extended_atomics"); |
265 | 222 | Opts.support("cl_khr_mipmap_image"); |
266 | 222 | Opts.support("cl_khr_subgroups"); |
267 | 222 | Opts.support("cl_khr_3d_image_writes"); |
268 | 222 | Opts.support("cl_amd_media_ops"); |
269 | 222 | Opts.support("cl_amd_media_ops2"); |
270 | 222 | } |
271 | 288 | } |
272 | | |
273 | 40 | LangAS getOpenCLTypeAddrSpace(OpenCLTypeKind TK) const override { |
274 | 40 | switch (TK) { |
275 | 40 | case OCLTK_Image: |
276 | 18 | return LangAS::opencl_constant; |
277 | 40 | |
278 | 40 | case OCLTK_ClkEvent: |
279 | 12 | case OCLTK_Queue: |
280 | 12 | case OCLTK_ReserveID: |
281 | 12 | return LangAS::opencl_global; |
282 | 12 | |
283 | 12 | default: |
284 | 10 | return TargetInfo::getOpenCLTypeAddrSpace(TK); |
285 | 40 | } |
286 | 40 | } |
287 | | |
288 | 75 | LangAS getOpenCLBuiltinAddressSpace(unsigned AS) const override { |
289 | 75 | switch (AS) { |
290 | 75 | case 0: |
291 | 0 | return LangAS::opencl_generic; |
292 | 75 | case 1: |
293 | 0 | return LangAS::opencl_global; |
294 | 75 | case 3: |
295 | 60 | return LangAS::opencl_local; |
296 | 75 | case 4: |
297 | 12 | return LangAS::opencl_constant; |
298 | 75 | case 5: |
299 | 0 | return LangAS::opencl_private; |
300 | 75 | default: |
301 | 3 | return getLangASFromTargetAS(AS); |
302 | 75 | } |
303 | 75 | } |
304 | | |
305 | 6 | LangAS getCUDABuiltinAddressSpace(unsigned AS) const override { |
306 | 6 | return LangAS::Default; |
307 | 6 | } |
308 | | |
309 | 21 | llvm::Optional<LangAS> getConstantAddressSpace() const override { |
310 | 21 | return getLangASFromTargetAS(Constant); |
311 | 21 | } |
312 | | |
313 | | /// \returns Target specific vtbl ptr address space. |
314 | 0 | unsigned getVtblPtrAddressSpace() const override { |
315 | 0 | return static_cast<unsigned>(Constant); |
316 | 0 | } |
317 | | |
318 | | /// \returns If a target requires an address within a target specific address |
319 | | /// space \p AddressSpace to be converted in order to be used, then return the |
320 | | /// corresponding target specific DWARF address space. |
321 | | /// |
322 | | /// \returns Otherwise return None and no conversion will be emitted in the |
323 | | /// DWARF. |
324 | | Optional<unsigned> |
325 | 203 | getDWARFAddressSpace(unsigned AddressSpace) const override { |
326 | 203 | const unsigned DWARF_Private = 1; |
327 | 203 | const unsigned DWARF_Local = 2; |
328 | 203 | if (AddressSpace == Private) { |
329 | 78 | return DWARF_Private; |
330 | 125 | } else if (AddressSpace == Local) { |
331 | 26 | return DWARF_Local; |
332 | 99 | } else { |
333 | 99 | return None; |
334 | 99 | } |
335 | 203 | } |
336 | | |
337 | | CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { |
338 | | switch (CC) { |
339 | | default: |
340 | | return CCCR_Warning; |
341 | | case CC_C: |
342 | | case CC_OpenCLKernel: |
343 | | return CCCR_OK; |
344 | | } |
345 | | } |
346 | | |
347 | | // In amdgcn target the null pointer in global, constant, and generic |
348 | | // address space has value 0 but in private and local address space has |
349 | | // value ~0. |
350 | 2.22k | uint64_t getNullPointerValue(LangAS AS) const override { |
351 | 2.22k | return AS == LangAS::opencl_local ? ~0332 : 01.89k ; |
352 | 2.22k | } |
353 | | |
354 | | void setAuxTarget(const TargetInfo *Aux) override; |
355 | | }; |
356 | | |
357 | | } // namespace targets |
358 | | } // namespace clang |
359 | | |
360 | | #endif // LLVM_CLANG_LIB_BASIC_TARGETS_AMDGPU_H |