blob: ddbfc8e07ff588fa51f237f9715c782fc8ca3b67 [file] [log] [blame]
alan-bakerfec0a472018-11-08 18:09:40 -05001// Copyright 2018 The Clspv Authors. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "clang/AST/RecordLayout.h"
16#include "clang/AST/RecursiveASTVisitor.h"
17#include "clang/Basic/TargetInfo.h"
18#include "clang/CodeGen/CodeGenAction.h"
19#include "clang/Frontend/CompilerInstance.h"
20#include "clang/Frontend/FrontendPluginRegistry.h"
21#include "clang/Frontend/TextDiagnosticPrinter.h"
22
23#include "clspv/Option.h"
24
25#include "FrontendPlugin.h"
26
Kévin Petit0fc88042019-04-09 23:25:02 +010027#include <unordered_set>
28
alan-bakerfec0a472018-11-08 18:09:40 -050029using namespace clang;
30
31namespace {
32struct ExtraValidationConsumer final : public ASTConsumer {
33private:
34 CompilerInstance &Instance;
35 llvm::StringRef InFile;
36
alan-baker9bb09792019-03-25 11:25:13 -040037 enum Layout {
38 UBO,
39 SSBO
40 };
41
alan-bakerfec0a472018-11-08 18:09:40 -050042 enum CustomDiagnosticType {
43 CustomDiagnosticVectorsMoreThan4Elements = 0,
44 CustomDiagnosticVoidPointer = 1,
alan-baker9bb09792019-03-25 11:25:13 -040045 CustomDiagnosticUnalignedScalar = 2,
46 CustomDiagnosticUnalignedVec2 = 3,
47 CustomDiagnosticUnalignedVec4 = 4,
alan-bakerfec0a472018-11-08 18:09:40 -050048 CustomDiagnosticUBOUnalignedArray = 5,
49 CustomDiagnosticUBOUnalignedStruct = 6,
alan-baker9bb09792019-03-25 11:25:13 -040050 CustomDiagnosticSmallStraddle = 7,
51 CustomDiagnosticLargeStraddle = 8,
52 CustomDiagnosticUnalignedStructMember = 9,
alan-bakerfec0a472018-11-08 18:09:40 -050053 CustomDiagnosticUBORestrictedSize = 10,
54 CustomDiagnosticUBORestrictedStruct = 11,
alan-baker3d9e2012019-01-11 14:55:30 -050055 CustomDiagnosticUBOArrayStride = 12,
56 CustomDiagnosticLocationInfo = 13,
alan-baker9bb09792019-03-25 11:25:13 -040057 CustomDiagnosticSSBOUnalignedArray = 14,
58 CustomDiagnosticSSBOUnalignedStruct = 15,
Kévin Petit0fc88042019-04-09 23:25:02 +010059 CustomDiagnosticOverloadedKernel = 16,
alan-bakerfec0a472018-11-08 18:09:40 -050060 CustomDiagnosticTotal
61 };
62 std::vector<unsigned> CustomDiagnosticsIDMap;
63
64 bool IsSupportedType(QualType QT, SourceRange SR) {
65 auto *Ty = QT.getTypePtr();
66
67 // First check if we have a pointer type.
68 if (Ty->isPointerType()) {
69 const Type *pointeeTy = Ty->getPointeeType().getTypePtr();
70 if (pointeeTy && pointeeTy->isVoidType()) {
71 // We don't support void pointers.
72 Instance.getDiagnostics().Report(
73 SR.getBegin(), CustomDiagnosticsIDMap[CustomDiagnosticVoidPointer]);
74 return false;
75 }
76 // Otherwise check recursively.
77 return IsSupportedType(Ty->getPointeeType(), SR);
78 }
79
80 const auto &canonicalType = QT.getCanonicalType();
81 if (auto *VT = llvm::dyn_cast<ExtVectorType>(canonicalType)) {
82 // We don't support vectors with more than 4 elements.
83 if (4 < VT->getNumElements()) {
84 Instance.getDiagnostics().Report(
85 SR.getBegin(),
86 CustomDiagnosticsIDMap[CustomDiagnosticVectorsMoreThan4Elements]);
87 return false;
88 }
89 }
90
91 return true;
92 }
93
alan-baker3d9e2012019-01-11 14:55:30 -050094 // Report a diagnostic using |diag|. If |arg_range| and |specific_range|
95 // differ, also issue a note with the specific location of the error.
96 void Report(const CustomDiagnosticType &diag, SourceRange arg_range,
97 SourceRange specific_range) {
98 Instance.getDiagnostics().Report(arg_range.getBegin(),
99 CustomDiagnosticsIDMap[diag]);
100 if (arg_range != specific_range) {
101 Instance.getDiagnostics().Report(
102 specific_range.getBegin(),
103 CustomDiagnosticsIDMap[CustomDiagnosticLocationInfo]);
104 }
105 }
106
alan-baker9bb09792019-03-25 11:25:13 -0400107 // Returns the alignment of |QT| to satisfy |layout|'s rules.
108 uint64_t GetAlignment(const QualType QT, const Layout &layout,
109 const ASTContext &context) const {
alan-bakerfec0a472018-11-08 18:09:40 -0500110 const auto canonical = QT.getCanonicalType();
111 uint64_t alignment = context.getTypeAlignInChars(canonical).getQuantity();
alan-baker9bb09792019-03-25 11:25:13 -0400112 if (layout == UBO &&
113 (canonical->isRecordType() || canonical->isArrayType())) {
alan-bakerfec0a472018-11-08 18:09:40 -0500114 return llvm::alignTo(alignment, 16);
115 }
116 return alignment;
117 }
118
119 // Returns true if |QT| is a valid layout for a Uniform buffer. Refer to
120 // 14.5.4 in the Vulkan specification.
alan-baker9bb09792019-03-25 11:25:13 -0400121 bool IsSupportedLayout(QualType QT, uint64_t offset, const Layout &layout,
122 ASTContext &context, SourceRange arg_range,
123 SourceRange specific_range) {
alan-bakerfec0a472018-11-08 18:09:40 -0500124 const auto canonical = QT.getCanonicalType();
125 if (canonical->isScalarType()) {
alan-baker9bb09792019-03-25 11:25:13 -0400126 if (!IsSupportedScalarLayout(canonical, offset, layout, context,
127 arg_range, specific_range))
alan-bakerfec0a472018-11-08 18:09:40 -0500128 return false;
129 } else if (canonical->isExtVectorType()) {
alan-baker9bb09792019-03-25 11:25:13 -0400130 if (!IsSupportedVectorLayout(canonical, offset, layout, context,
131 arg_range, specific_range))
alan-bakerfec0a472018-11-08 18:09:40 -0500132 return false;
133 } else if (canonical->isArrayType()) {
alan-baker9bb09792019-03-25 11:25:13 -0400134 if (!IsSupportedArrayLayout(canonical, offset, layout, context, arg_range,
135 specific_range))
alan-bakerfec0a472018-11-08 18:09:40 -0500136 return false;
137 } else if (canonical->isRecordType()) {
alan-baker9bb09792019-03-25 11:25:13 -0400138 if (!IsSupportedRecordLayout(canonical, offset, layout, context,
139 arg_range, specific_range))
alan-bakerfec0a472018-11-08 18:09:40 -0500140 return false;
141 }
142
143 // TODO(alan-baker): Find a way to avoid this restriction.
144 // Don't allow padding. This prevents structs like:
145 // struct {
146 // int x[2];
147 // int y __attribute((aligned(16)));
148 // };
149 //
150 // This would map in LLVM to { [2 x i32], [8 x i8], i32, [12 xi8] }.
151 // There is no easy way to manipulate the padding after the array to
152 // satisfy the standard Uniform buffer layout rules in this case. The usual
153 // trick is replacing the i8 arrays with an i32 element, but the i32 would
154 // still be laid out too close to the array.
155 const auto type_size = context.getTypeSizeInChars(canonical).getQuantity();
alan-baker9bb09792019-03-25 11:25:13 -0400156 const auto type_align = GetAlignment(canonical, layout, context);
157 if (layout == UBO && (type_size % type_align != 0)) {
alan-baker3d9e2012019-01-11 14:55:30 -0500158 Report(CustomDiagnosticUBORestrictedSize, arg_range, specific_range);
alan-bakerfec0a472018-11-08 18:09:40 -0500159 return false;
160 }
161
162 return true;
163 }
164
alan-baker9bb09792019-03-25 11:25:13 -0400165 bool IsSupportedScalarLayout(QualType QT, uint64_t offset,
166 const Layout & /*layout*/, ASTContext &context,
167 SourceRange arg_range,
168 SourceRange specific_range) {
alan-bakerfec0a472018-11-08 18:09:40 -0500169 // A scalar type of size N has a base alignment on N.
170 const unsigned type_size = context.getTypeSizeInChars(QT).getQuantity();
171 if (offset % type_size != 0) {
alan-baker9bb09792019-03-25 11:25:13 -0400172 Report(CustomDiagnosticUnalignedScalar, arg_range, specific_range);
alan-bakerfec0a472018-11-08 18:09:40 -0500173 return false;
174 }
175
176 return true;
177 }
178
alan-baker9bb09792019-03-25 11:25:13 -0400179 bool IsSupportedVectorLayout(QualType QT, uint64_t offset,
180 const Layout &layout, ASTContext &context,
181 SourceRange arg_range,
182 SourceRange specific_range) {
alan-bakerfec0a472018-11-08 18:09:40 -0500183 // 2-component vectors have a base alignment of 2 * (size of element).
184 // 3- and 4-component vectors hae a base alignment of 4 * (size of
185 // element).
186 const auto *VT = llvm::cast<VectorType>(QT);
187 const auto ele_size =
188 context.getTypeSizeInChars(VT->getElementType()).getQuantity();
189 if (VT->getNumElements() == 2) {
190 if (offset % (ele_size * 2) != 0) {
alan-baker9bb09792019-03-25 11:25:13 -0400191 Report(CustomDiagnosticUnalignedVec2, arg_range, specific_range);
alan-bakerfec0a472018-11-08 18:09:40 -0500192 return false;
193 }
194 } else if (offset % (ele_size * 4) != 0) {
195 // Other vector sizes cause errors elsewhere.
alan-baker9bb09792019-03-25 11:25:13 -0400196 Report(CustomDiagnosticUnalignedVec4, arg_range, specific_range);
alan-bakerfec0a472018-11-08 18:09:40 -0500197 return false;
198 }
199
200 // Straddling rules:
201 // * If total vector size is less than 16 bytes, the offset must place the
202 // entire vector within the same 16 bytes.
203 // * If total vector size is greater than 16 bytes, the offset must be a
204 // multiple of 16.
205 const auto size = context.getTypeSizeInChars(QT).getQuantity();
206 if (size <= 16 && (offset / 16 != (offset + size - 1) / 16)) {
alan-baker9bb09792019-03-25 11:25:13 -0400207 Report(CustomDiagnosticSmallStraddle, arg_range, specific_range);
alan-bakerfec0a472018-11-08 18:09:40 -0500208 return false;
209 } else if (size > 16 && (offset % 16 != 0)) {
alan-baker9bb09792019-03-25 11:25:13 -0400210 Report(CustomDiagnosticLargeStraddle, arg_range, specific_range);
alan-bakerfec0a472018-11-08 18:09:40 -0500211 return false;
212 }
213
alan-baker9bb09792019-03-25 11:25:13 -0400214 return IsSupportedLayout(VT->getElementType(), offset, layout, context,
215 arg_range, specific_range);
alan-bakerfec0a472018-11-08 18:09:40 -0500216 }
217
alan-baker9bb09792019-03-25 11:25:13 -0400218 bool IsSupportedArrayLayout(QualType QT, uint64_t offset,
219 const Layout &layout, ASTContext &context,
220 SourceRange arg_range,
221 SourceRange specific_range) {
222 // An array has a base alignment of is element type.
223 // If the layout is UBO, the alignment is rounded up to a multiple of 16.
alan-bakerfec0a472018-11-08 18:09:40 -0500224 const auto *AT = llvm::cast<ArrayType>(QT);
alan-baker9bb09792019-03-25 11:25:13 -0400225 const auto element_align = GetAlignment(AT->getElementType(), layout, context);
226 const auto type_align =
227 layout == UBO ? llvm::alignTo(element_align, 16) : element_align;
alan-bakerfec0a472018-11-08 18:09:40 -0500228 if (offset % type_align != 0) {
alan-baker9bb09792019-03-25 11:25:13 -0400229 auto diag_id = layout == UBO ? CustomDiagnosticUBOUnalignedArray
230 : CustomDiagnosticSSBOUnalignedArray;
231 Report(diag_id, arg_range, specific_range);
alan-bakerfec0a472018-11-08 18:09:40 -0500232 return false;
233 }
alan-baker9bb09792019-03-25 11:25:13 -0400234 if (layout == UBO && !clspv::Option::RelaxedUniformBufferLayout()) {
alan-baker3d9e2012019-01-11 14:55:30 -0500235 // The ArrayStride must be a multiple of the base alignment of the array
236 // (i.e. a multiple of 16). This means that the element size must be
237 // restricted to be the base alignment of the array.
238 const auto element_size =
239 context.getTypeSizeInChars(AT->getElementType()).getQuantity();
240 if (element_size % type_align != 0) {
241 Report(CustomDiagnosticUBOArrayStride, arg_range, specific_range);
242 return false;
243 }
244 }
alan-bakerfec0a472018-11-08 18:09:40 -0500245
alan-baker9bb09792019-03-25 11:25:13 -0400246 return IsSupportedLayout(AT->getElementType(), offset, layout, context,
247 arg_range, specific_range);
alan-bakerfec0a472018-11-08 18:09:40 -0500248 }
249
alan-baker9bb09792019-03-25 11:25:13 -0400250 bool IsSupportedRecordLayout(QualType QT, uint64_t offset,
251 const Layout &layout, ASTContext &context,
252 SourceRange arg_range,
253 SourceRange specific_range) {
254 // A structure has a base alignment of its largest member. For UBO layouts,
255 // alignment is rounded up to a multiple of 16.
alan-bakerfec0a472018-11-08 18:09:40 -0500256 const auto *RT = llvm::cast<RecordType>(QT);
alan-baker9bb09792019-03-25 11:25:13 -0400257 auto type_alignment = GetAlignment(QT, layout, context);
258 if (layout == UBO) llvm::alignTo(type_alignment, 16);
alan-bakerfec0a472018-11-08 18:09:40 -0500259 if (offset % type_alignment != 0) {
alan-baker9bb09792019-03-25 11:25:13 -0400260 auto diag_id = layout == UBO ? CustomDiagnosticUBOUnalignedStruct
261 : CustomDiagnosticSSBOUnalignedStruct;
262 Report(diag_id, arg_range, specific_range);
alan-bakerfec0a472018-11-08 18:09:40 -0500263 return false;
264 }
265
alan-baker9bb09792019-03-25 11:25:13 -0400266 const auto &record_layout = context.getASTRecordLayout(RT->getDecl());
alan-bakerfec0a472018-11-08 18:09:40 -0500267 const FieldDecl *prev = nullptr;
268 for (auto field_decl : RT->getDecl()->fields()) {
269 const auto field_type = field_decl->getType();
alan-baker9bb09792019-03-25 11:25:13 -0400270 const auto field_alignment = GetAlignment(field_type, layout, context);
alan-bakerfec0a472018-11-08 18:09:40 -0500271 const unsigned field_no = field_decl->getFieldIndex();
272 const uint64_t field_offset =
alan-baker9bb09792019-03-25 11:25:13 -0400273 record_layout.getFieldOffset(field_no) / context.getCharWidth();
alan-bakerfec0a472018-11-08 18:09:40 -0500274
275 // Rules must be checked recursively.
alan-baker9bb09792019-03-25 11:25:13 -0400276 if (!IsSupportedLayout(field_type, field_offset + offset, layout, context,
277 arg_range, field_decl->getSourceRange())) {
alan-bakerfec0a472018-11-08 18:09:40 -0500278 return false;
279 }
280
281 if (prev) {
282 const auto prev_canonical = prev->getType().getCanonicalType();
283 const uint64_t prev_offset =
alan-baker9bb09792019-03-25 11:25:13 -0400284 record_layout.getFieldOffset(field_no - 1) / context.getCharWidth();
alan-bakerfec0a472018-11-08 18:09:40 -0500285 const auto prev_size =
286 context.getTypeSizeInChars(prev_canonical).getQuantity();
alan-baker9bb09792019-03-25 11:25:13 -0400287 const auto prev_alignment = GetAlignment(prev_canonical, layout, context);
alan-bakerfec0a472018-11-08 18:09:40 -0500288 const auto next_available =
289 prev_offset + llvm::alignTo(prev_size, prev_alignment);
290 if (prev_canonical->isArrayType() || prev_canonical->isRecordType()) {
291 // The next element after an array or struct must be placed on or
292 // after the next multiple of the alignment of that array or
293 // struct.
alan-baker9bb09792019-03-25 11:25:13 -0400294 // For UBO layouts, both arrays and structs must be aligned to a
295 // multiple of 16 bytes.
296 const uint64_t final_align = layout == UBO
297 ? llvm::alignTo(next_available, 16)
298 : next_available;
299 if (final_align > field_offset) {
300 Report(CustomDiagnosticUnalignedStructMember, arg_range,
alan-baker3d9e2012019-01-11 14:55:30 -0500301 field_decl->getSourceRange());
alan-bakerfec0a472018-11-08 18:09:40 -0500302 return false;
303 }
304 }
305 }
306
307 prev = field_decl;
308 }
309
310 return true;
311 }
312
313 // This will be used to check the inside of function bodies.
314 class DeclVisitor : public RecursiveASTVisitor<DeclVisitor> {
315 private:
316 ExtraValidationConsumer &consumer;
317
318 public:
319 explicit DeclVisitor(ExtraValidationConsumer &VC) : consumer(VC) {}
320
321 // Visits a declaration. Emits a diagnostic and returns false if the
322 // declaration represents an unsupported vector value or vector type.
323 // Otherwise returns true.
324 bool VisitDecl(Decl *D) {
325 // Looking at the Decl class hierarchy, it seems ValueDecl and TypeDecl
326 // are the only two that might represent an unsupported vector type.
327 if (auto *VD = dyn_cast<ValueDecl>(D)) {
328 return consumer.IsSupportedType(VD->getType(), D->getSourceRange());
329 } else if (auto *TD = dyn_cast<TypeDecl>(D)) {
330 QualType DefinedType = TD->getASTContext().getTypeDeclType(TD);
331 return consumer.IsSupportedType(DefinedType, TD->getSourceRange());
332 }
333 return true;
334 }
335 };
336
337 DeclVisitor Visitor;
Kévin Petit0fc88042019-04-09 23:25:02 +0100338 std::unordered_set<std::string> Kernels;
alan-bakerfec0a472018-11-08 18:09:40 -0500339
340public:
341 explicit ExtraValidationConsumer(CompilerInstance &Instance,
342 llvm::StringRef InFile)
343 : Instance(Instance), InFile(InFile),
344 CustomDiagnosticsIDMap(CustomDiagnosticTotal), Visitor(*this) {
345 auto &DE = Instance.getDiagnostics();
346
347 CustomDiagnosticsIDMap[CustomDiagnosticVectorsMoreThan4Elements] =
348 DE.getCustomDiagID(
349 DiagnosticsEngine::Error,
350 "vectors with more than 4 elements are not supported");
351 CustomDiagnosticsIDMap[CustomDiagnosticVoidPointer] = DE.getCustomDiagID(
352 DiagnosticsEngine::Error, "pointer-to-void is not supported");
alan-baker9bb09792019-03-25 11:25:13 -0400353 CustomDiagnosticsIDMap[CustomDiagnosticUnalignedScalar] =
alan-bakerfec0a472018-11-08 18:09:40 -0500354 DE.getCustomDiagID(
355 DiagnosticsEngine::Error,
alan-baker9bb09792019-03-25 11:25:13 -0400356 "scalar elements must be aligned to their size");
357 CustomDiagnosticsIDMap[CustomDiagnosticUnalignedVec2] = DE.getCustomDiagID(
358 DiagnosticsEngine::Error,
359 "two-component vectors must be aligned to 2 times their element size");
360 CustomDiagnosticsIDMap[CustomDiagnosticUnalignedVec4] =
alan-bakerfec0a472018-11-08 18:09:40 -0500361 DE.getCustomDiagID(DiagnosticsEngine::Error,
alan-baker9bb09792019-03-25 11:25:13 -0400362 "three- and four-component vectors must be aligned "
363 "to 4 times their element size");
alan-bakerfec0a472018-11-08 18:09:40 -0500364 CustomDiagnosticsIDMap[CustomDiagnosticUBOUnalignedArray] =
365 DE.getCustomDiagID(DiagnosticsEngine::Error,
366 "in an UBO, arrays must be aligned to their element "
367 "alignment, rounded up to a multiple of 16 bytes");
368 CustomDiagnosticsIDMap[CustomDiagnosticUBOUnalignedStruct] =
369 DE.getCustomDiagID(
370 DiagnosticsEngine::Error,
371 "in an UBO, structs must be aligned to their "
372 "largest element alignment, rounded up to a multiple of "
373 "16 bytes");
alan-baker9bb09792019-03-25 11:25:13 -0400374 CustomDiagnosticsIDMap[CustomDiagnosticSmallStraddle] =
alan-bakerfec0a472018-11-08 18:09:40 -0500375 DE.getCustomDiagID(DiagnosticsEngine::Error,
alan-baker9bb09792019-03-25 11:25:13 -0400376 "vectors with a total size less than or equal to 16 "
377 "bytes must be placed entirely within a 16 byte "
378 "aligned region");
379 CustomDiagnosticsIDMap[CustomDiagnosticLargeStraddle] =
alan-bakerfec0a472018-11-08 18:09:40 -0500380 DE.getCustomDiagID(DiagnosticsEngine::Error,
alan-baker9bb09792019-03-25 11:25:13 -0400381 "vectors with a total size greater than 16 bytes "
382 "must aligned to 16 bytes");
383 CustomDiagnosticsIDMap[CustomDiagnosticUnalignedStructMember] =
alan-bakerfec0a472018-11-08 18:09:40 -0500384 DE.getCustomDiagID(DiagnosticsEngine::Error,
alan-baker9bb09792019-03-25 11:25:13 -0400385 "a structure member must not be placed between the "
386 "end of a structure or array and the next multiple "
387 "of the base alignment of that structure or array");
alan-bakerfec0a472018-11-08 18:09:40 -0500388 CustomDiagnosticsIDMap[CustomDiagnosticUBORestrictedSize] =
389 DE.getCustomDiagID(DiagnosticsEngine::Error,
390 "clspv restriction: UBO element size must be a "
391 "multiple of that element's alignment");
392 CustomDiagnosticsIDMap[CustomDiagnosticUBORestrictedStruct] =
393 DE.getCustomDiagID(
394 DiagnosticsEngine::Error,
395 "clspv restriction: UBO structures may not have implicit padding");
alan-baker3d9e2012019-01-11 14:55:30 -0500396 CustomDiagnosticsIDMap[CustomDiagnosticUBOArrayStride] = DE.getCustomDiagID(
397 DiagnosticsEngine::Error,
398 "clspv restriction: to satisfy UBO ArrayStride restrictions, element "
399 "size must be a multiple of array alignment");
400 CustomDiagnosticsIDMap[CustomDiagnosticLocationInfo] =
401 DE.getCustomDiagID(DiagnosticsEngine::Note, "here");
alan-baker9bb09792019-03-25 11:25:13 -0400402 CustomDiagnosticsIDMap[CustomDiagnosticSSBOUnalignedArray] =
403 DE.getCustomDiagID(
404 DiagnosticsEngine::Error,
405 "in a SSBO, arrays must be aligned to their element alignment");
406 CustomDiagnosticsIDMap[CustomDiagnosticSSBOUnalignedStruct] =
407 DE.getCustomDiagID(DiagnosticsEngine::Error,
408 "in a SSBO, structs must be aligned to their "
409 "largest element alignment");
Kévin Petit0fc88042019-04-09 23:25:02 +0100410 CustomDiagnosticsIDMap[CustomDiagnosticOverloadedKernel] =
411 DE.getCustomDiagID(DiagnosticsEngine::Error,
412 "kernel functions can't be overloaded");
alan-bakerfec0a472018-11-08 18:09:40 -0500413 }
414
415 virtual bool HandleTopLevelDecl(DeclGroupRef DG) override {
416 for (auto *D : DG) {
417 if (auto *FD = llvm::dyn_cast<FunctionDecl>(D)) {
418 // If the function has a body it means we are not an OpenCL builtin
419 // function.
420 if (FD->hasBody()) {
421 if (!IsSupportedType(FD->getReturnType(),
422 FD->getReturnTypeSourceRange())) {
423 return false;
424 }
425
426 bool is_opencl_kernel = false;
427 if (FD->hasAttrs()) {
428 for (auto *attr : FD->attrs()) {
429 if (attr->getKind() == attr::Kind::OpenCLKernel) {
430 is_opencl_kernel = true;
431 }
432 }
433 }
434
Kévin Petit0fc88042019-04-09 23:25:02 +0100435 if (is_opencl_kernel) {
436 if (Kernels.count(FD->getName()) != 0) {
437 auto srcRange = FD->getSourceRange();
438 Report(CustomDiagnosticOverloadedKernel, srcRange, srcRange);
439 } else {
440 Kernels.insert(FD->getName());
441 }
442 }
443
alan-bakerfec0a472018-11-08 18:09:40 -0500444 for (auto *P : FD->parameters()) {
445 auto type = P->getType();
446 if (!IsSupportedType(P->getOriginalType(), P->getSourceRange())) {
447 return false;
448 }
449
alan-baker9bb09792019-03-25 11:25:13 -0400450 if (is_opencl_kernel && type->isPointerType() &&
451 ((type->getPointeeType().getAddressSpace() ==
452 LangAS::opencl_constant) ||
453 (type->getPointeeType().getAddressSpace() ==
454 LangAS::opencl_global))) {
alan-baker3d9e2012019-01-11 14:55:30 -0500455 // The argument will be generated as an array within a block.
456 // Generate an array type to check the validity for the generated
457 // case.
alan-baker9bb09792019-03-25 11:25:13 -0400458 Layout layout = SSBO;
459 if (clspv::Option::ConstantArgsInUniformBuffer() &&
460 !clspv::Option::Std430UniformBufferLayout() &&
461 type->getPointeeType().getAddressSpace() ==
462 LangAS::opencl_constant) {
463 layout = UBO;
464 }
alan-baker3d9e2012019-01-11 14:55:30 -0500465 auto array_type = FD->getASTContext().getIncompleteArrayType(
466 type->getPointeeType(), clang::ArrayType::Normal, 0);
alan-baker9bb09792019-03-25 11:25:13 -0400467 if (!IsSupportedLayout(array_type, 0, layout, FD->getASTContext(),
468 P->getSourceRange(),
469 P->getSourceRange())) {
alan-bakerfec0a472018-11-08 18:09:40 -0500470 return false;
471 }
472 }
473 }
474
475 // Check for unsupported vector types.
476 Visitor.TraverseDecl(FD);
477 }
478 }
479 }
480
481 return true;
482 }
483};
484} // namespace
485
486namespace clspv {
487std::unique_ptr<ASTConsumer>
488ExtraValidationASTAction::CreateASTConsumer(CompilerInstance &CI,
489 llvm::StringRef InFile) {
490 return std::unique_ptr<ASTConsumer>(new ExtraValidationConsumer(CI, InFile));
491}
492} // namespace clspv