blob: 4c72a1ff7c60394234d164565e3e076e172b8158 [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
Diego Novillo3cc8d7a2019-04-10 13:30:34 -040037 enum Layout { UBO, SSBO };
alan-baker9bb09792019-03-25 11:25:13 -040038
alan-bakerfec0a472018-11-08 18:09:40 -050039 enum CustomDiagnosticType {
40 CustomDiagnosticVectorsMoreThan4Elements = 0,
41 CustomDiagnosticVoidPointer = 1,
alan-baker9bb09792019-03-25 11:25:13 -040042 CustomDiagnosticUnalignedScalar = 2,
43 CustomDiagnosticUnalignedVec2 = 3,
44 CustomDiagnosticUnalignedVec4 = 4,
alan-bakerfec0a472018-11-08 18:09:40 -050045 CustomDiagnosticUBOUnalignedArray = 5,
46 CustomDiagnosticUBOUnalignedStruct = 6,
alan-baker9bb09792019-03-25 11:25:13 -040047 CustomDiagnosticSmallStraddle = 7,
48 CustomDiagnosticLargeStraddle = 8,
49 CustomDiagnosticUnalignedStructMember = 9,
alan-bakerfec0a472018-11-08 18:09:40 -050050 CustomDiagnosticUBORestrictedSize = 10,
51 CustomDiagnosticUBORestrictedStruct = 11,
alan-baker3d9e2012019-01-11 14:55:30 -050052 CustomDiagnosticUBOArrayStride = 12,
53 CustomDiagnosticLocationInfo = 13,
alan-baker9bb09792019-03-25 11:25:13 -040054 CustomDiagnosticSSBOUnalignedArray = 14,
55 CustomDiagnosticSSBOUnalignedStruct = 15,
Kévin Petit0fc88042019-04-09 23:25:02 +010056 CustomDiagnosticOverloadedKernel = 16,
alan-baker990e9b92019-06-07 11:26:39 -040057 CustomDiagnosticStructContainsPointer = 17,
alan-bakerfec0a472018-11-08 18:09:40 -050058 CustomDiagnosticTotal
59 };
60 std::vector<unsigned> CustomDiagnosticsIDMap;
61
alan-baker990e9b92019-06-07 11:26:39 -040062 bool ContainsPointerType(QualType QT) {
63 auto canonical = QT.getCanonicalType();
64 if (canonical->isPointerType()) {
65 return true;
66 } else if (auto *AT = dyn_cast<ArrayType>(canonical)) {
67 return ContainsPointerType(AT->getElementType());
68 } else if (auto *RT = dyn_cast<RecordType>(canonical)) {
69 for (auto field_decl : RT->getDecl()->fields()) {
70 if (ContainsPointerType(field_decl->getType()))
71 return true;
72 }
73 }
74
75 return false;
76 }
77
alan-bakerfec0a472018-11-08 18:09:40 -050078 bool IsSupportedType(QualType QT, SourceRange SR) {
79 auto *Ty = QT.getTypePtr();
80
81 // First check if we have a pointer type.
82 if (Ty->isPointerType()) {
83 const Type *pointeeTy = Ty->getPointeeType().getTypePtr();
84 if (pointeeTy && pointeeTy->isVoidType()) {
85 // We don't support void pointers.
86 Instance.getDiagnostics().Report(
87 SR.getBegin(), CustomDiagnosticsIDMap[CustomDiagnosticVoidPointer]);
88 return false;
89 }
90 // Otherwise check recursively.
91 return IsSupportedType(Ty->getPointeeType(), SR);
92 }
93
94 const auto &canonicalType = QT.getCanonicalType();
95 if (auto *VT = llvm::dyn_cast<ExtVectorType>(canonicalType)) {
96 // We don't support vectors with more than 4 elements.
97 if (4 < VT->getNumElements()) {
98 Instance.getDiagnostics().Report(
99 SR.getBegin(),
100 CustomDiagnosticsIDMap[CustomDiagnosticVectorsMoreThan4Elements]);
101 return false;
102 }
alan-baker990e9b92019-06-07 11:26:39 -0400103 } else if (canonicalType->isRecordType()) {
104 // Structures should not contain pointers.
105 if (ContainsPointerType(canonicalType)) {
106 Instance.getDiagnostics().Report(
107 SR.getBegin(),
108 CustomDiagnosticsIDMap[CustomDiagnosticStructContainsPointer]);
109 return false;
110 }
alan-bakerfec0a472018-11-08 18:09:40 -0500111 }
112
113 return true;
114 }
115
alan-baker3d9e2012019-01-11 14:55:30 -0500116 // Report a diagnostic using |diag|. If |arg_range| and |specific_range|
117 // differ, also issue a note with the specific location of the error.
118 void Report(const CustomDiagnosticType &diag, SourceRange arg_range,
119 SourceRange specific_range) {
120 Instance.getDiagnostics().Report(arg_range.getBegin(),
121 CustomDiagnosticsIDMap[diag]);
122 if (arg_range != specific_range) {
123 Instance.getDiagnostics().Report(
124 specific_range.getBegin(),
125 CustomDiagnosticsIDMap[CustomDiagnosticLocationInfo]);
126 }
127 }
128
alan-baker9bb09792019-03-25 11:25:13 -0400129 // Returns the alignment of |QT| to satisfy |layout|'s rules.
130 uint64_t GetAlignment(const QualType QT, const Layout &layout,
131 const ASTContext &context) const {
alan-bakerfec0a472018-11-08 18:09:40 -0500132 const auto canonical = QT.getCanonicalType();
133 uint64_t alignment = context.getTypeAlignInChars(canonical).getQuantity();
alan-baker9bb09792019-03-25 11:25:13 -0400134 if (layout == UBO &&
135 (canonical->isRecordType() || canonical->isArrayType())) {
alan-bakerfec0a472018-11-08 18:09:40 -0500136 return llvm::alignTo(alignment, 16);
137 }
138 return alignment;
139 }
140
141 // Returns true if |QT| is a valid layout for a Uniform buffer. Refer to
142 // 14.5.4 in the Vulkan specification.
alan-baker9bb09792019-03-25 11:25:13 -0400143 bool IsSupportedLayout(QualType QT, uint64_t offset, const Layout &layout,
144 ASTContext &context, SourceRange arg_range,
145 SourceRange specific_range) {
alan-bakerfec0a472018-11-08 18:09:40 -0500146 const auto canonical = QT.getCanonicalType();
147 if (canonical->isScalarType()) {
alan-baker9bb09792019-03-25 11:25:13 -0400148 if (!IsSupportedScalarLayout(canonical, offset, layout, context,
149 arg_range, specific_range))
alan-bakerfec0a472018-11-08 18:09:40 -0500150 return false;
151 } else if (canonical->isExtVectorType()) {
alan-baker9bb09792019-03-25 11:25:13 -0400152 if (!IsSupportedVectorLayout(canonical, offset, layout, context,
153 arg_range, specific_range))
alan-bakerfec0a472018-11-08 18:09:40 -0500154 return false;
155 } else if (canonical->isArrayType()) {
alan-baker9bb09792019-03-25 11:25:13 -0400156 if (!IsSupportedArrayLayout(canonical, offset, layout, context, arg_range,
157 specific_range))
alan-bakerfec0a472018-11-08 18:09:40 -0500158 return false;
159 } else if (canonical->isRecordType()) {
alan-baker9bb09792019-03-25 11:25:13 -0400160 if (!IsSupportedRecordLayout(canonical, offset, layout, context,
161 arg_range, specific_range))
alan-bakerfec0a472018-11-08 18:09:40 -0500162 return false;
163 }
164
165 // TODO(alan-baker): Find a way to avoid this restriction.
166 // Don't allow padding. This prevents structs like:
167 // struct {
168 // int x[2];
169 // int y __attribute((aligned(16)));
170 // };
171 //
172 // This would map in LLVM to { [2 x i32], [8 x i8], i32, [12 xi8] }.
173 // There is no easy way to manipulate the padding after the array to
174 // satisfy the standard Uniform buffer layout rules in this case. The usual
175 // trick is replacing the i8 arrays with an i32 element, but the i32 would
176 // still be laid out too close to the array.
177 const auto type_size = context.getTypeSizeInChars(canonical).getQuantity();
alan-baker9bb09792019-03-25 11:25:13 -0400178 const auto type_align = GetAlignment(canonical, layout, context);
179 if (layout == UBO && (type_size % type_align != 0)) {
alan-baker3d9e2012019-01-11 14:55:30 -0500180 Report(CustomDiagnosticUBORestrictedSize, arg_range, specific_range);
alan-bakerfec0a472018-11-08 18:09:40 -0500181 return false;
182 }
183
184 return true;
185 }
186
alan-baker9bb09792019-03-25 11:25:13 -0400187 bool IsSupportedScalarLayout(QualType QT, uint64_t offset,
188 const Layout & /*layout*/, ASTContext &context,
189 SourceRange arg_range,
190 SourceRange specific_range) {
alan-bakerfec0a472018-11-08 18:09:40 -0500191 // A scalar type of size N has a base alignment on N.
192 const unsigned type_size = context.getTypeSizeInChars(QT).getQuantity();
193 if (offset % type_size != 0) {
alan-baker9bb09792019-03-25 11:25:13 -0400194 Report(CustomDiagnosticUnalignedScalar, arg_range, specific_range);
alan-bakerfec0a472018-11-08 18:09:40 -0500195 return false;
196 }
197
198 return true;
199 }
200
alan-baker9bb09792019-03-25 11:25:13 -0400201 bool IsSupportedVectorLayout(QualType QT, uint64_t offset,
202 const Layout &layout, ASTContext &context,
203 SourceRange arg_range,
204 SourceRange specific_range) {
alan-bakerfec0a472018-11-08 18:09:40 -0500205 // 2-component vectors have a base alignment of 2 * (size of element).
206 // 3- and 4-component vectors hae a base alignment of 4 * (size of
207 // element).
208 const auto *VT = llvm::cast<VectorType>(QT);
209 const auto ele_size =
210 context.getTypeSizeInChars(VT->getElementType()).getQuantity();
211 if (VT->getNumElements() == 2) {
212 if (offset % (ele_size * 2) != 0) {
alan-baker9bb09792019-03-25 11:25:13 -0400213 Report(CustomDiagnosticUnalignedVec2, arg_range, specific_range);
alan-bakerfec0a472018-11-08 18:09:40 -0500214 return false;
215 }
216 } else if (offset % (ele_size * 4) != 0) {
217 // Other vector sizes cause errors elsewhere.
alan-baker9bb09792019-03-25 11:25:13 -0400218 Report(CustomDiagnosticUnalignedVec4, arg_range, specific_range);
alan-bakerfec0a472018-11-08 18:09:40 -0500219 return false;
220 }
221
222 // Straddling rules:
223 // * If total vector size is less than 16 bytes, the offset must place the
224 // entire vector within the same 16 bytes.
225 // * If total vector size is greater than 16 bytes, the offset must be a
226 // multiple of 16.
227 const auto size = context.getTypeSizeInChars(QT).getQuantity();
228 if (size <= 16 && (offset / 16 != (offset + size - 1) / 16)) {
alan-baker9bb09792019-03-25 11:25:13 -0400229 Report(CustomDiagnosticSmallStraddle, arg_range, specific_range);
alan-bakerfec0a472018-11-08 18:09:40 -0500230 return false;
231 } else if (size > 16 && (offset % 16 != 0)) {
alan-baker9bb09792019-03-25 11:25:13 -0400232 Report(CustomDiagnosticLargeStraddle, arg_range, specific_range);
alan-bakerfec0a472018-11-08 18:09:40 -0500233 return false;
234 }
235
alan-baker9bb09792019-03-25 11:25:13 -0400236 return IsSupportedLayout(VT->getElementType(), offset, layout, context,
237 arg_range, specific_range);
alan-bakerfec0a472018-11-08 18:09:40 -0500238 }
239
alan-baker9bb09792019-03-25 11:25:13 -0400240 bool IsSupportedArrayLayout(QualType QT, uint64_t offset,
241 const Layout &layout, ASTContext &context,
242 SourceRange arg_range,
243 SourceRange specific_range) {
244 // An array has a base alignment of is element type.
245 // If the layout is UBO, the alignment is rounded up to a multiple of 16.
alan-bakerfec0a472018-11-08 18:09:40 -0500246 const auto *AT = llvm::cast<ArrayType>(QT);
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400247 const auto element_align =
248 GetAlignment(AT->getElementType(), layout, context);
alan-baker9bb09792019-03-25 11:25:13 -0400249 const auto type_align =
250 layout == UBO ? llvm::alignTo(element_align, 16) : element_align;
alan-bakerfec0a472018-11-08 18:09:40 -0500251 if (offset % type_align != 0) {
alan-baker9bb09792019-03-25 11:25:13 -0400252 auto diag_id = layout == UBO ? CustomDiagnosticUBOUnalignedArray
253 : CustomDiagnosticSSBOUnalignedArray;
254 Report(diag_id, arg_range, specific_range);
alan-bakerfec0a472018-11-08 18:09:40 -0500255 return false;
256 }
alan-baker9bb09792019-03-25 11:25:13 -0400257 if (layout == UBO && !clspv::Option::RelaxedUniformBufferLayout()) {
alan-baker3d9e2012019-01-11 14:55:30 -0500258 // The ArrayStride must be a multiple of the base alignment of the array
259 // (i.e. a multiple of 16). This means that the element size must be
260 // restricted to be the base alignment of the array.
261 const auto element_size =
262 context.getTypeSizeInChars(AT->getElementType()).getQuantity();
263 if (element_size % type_align != 0) {
264 Report(CustomDiagnosticUBOArrayStride, arg_range, specific_range);
265 return false;
266 }
267 }
alan-bakerfec0a472018-11-08 18:09:40 -0500268
alan-baker9bb09792019-03-25 11:25:13 -0400269 return IsSupportedLayout(AT->getElementType(), offset, layout, context,
270 arg_range, specific_range);
alan-bakerfec0a472018-11-08 18:09:40 -0500271 }
272
alan-baker9bb09792019-03-25 11:25:13 -0400273 bool IsSupportedRecordLayout(QualType QT, uint64_t offset,
274 const Layout &layout, ASTContext &context,
275 SourceRange arg_range,
276 SourceRange specific_range) {
277 // A structure has a base alignment of its largest member. For UBO layouts,
278 // alignment is rounded up to a multiple of 16.
alan-bakerfec0a472018-11-08 18:09:40 -0500279 const auto *RT = llvm::cast<RecordType>(QT);
alan-baker9bb09792019-03-25 11:25:13 -0400280 auto type_alignment = GetAlignment(QT, layout, context);
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400281 if (layout == UBO)
282 llvm::alignTo(type_alignment, 16);
alan-bakerfec0a472018-11-08 18:09:40 -0500283 if (offset % type_alignment != 0) {
alan-baker9bb09792019-03-25 11:25:13 -0400284 auto diag_id = layout == UBO ? CustomDiagnosticUBOUnalignedStruct
285 : CustomDiagnosticSSBOUnalignedStruct;
286 Report(diag_id, arg_range, specific_range);
alan-bakerfec0a472018-11-08 18:09:40 -0500287 return false;
288 }
289
alan-baker9bb09792019-03-25 11:25:13 -0400290 const auto &record_layout = context.getASTRecordLayout(RT->getDecl());
alan-bakerfec0a472018-11-08 18:09:40 -0500291 const FieldDecl *prev = nullptr;
292 for (auto field_decl : RT->getDecl()->fields()) {
293 const auto field_type = field_decl->getType();
alan-baker9bb09792019-03-25 11:25:13 -0400294 const auto field_alignment = GetAlignment(field_type, layout, context);
alan-bakerfec0a472018-11-08 18:09:40 -0500295 const unsigned field_no = field_decl->getFieldIndex();
296 const uint64_t field_offset =
alan-baker9bb09792019-03-25 11:25:13 -0400297 record_layout.getFieldOffset(field_no) / context.getCharWidth();
alan-bakerfec0a472018-11-08 18:09:40 -0500298
299 // Rules must be checked recursively.
alan-baker9bb09792019-03-25 11:25:13 -0400300 if (!IsSupportedLayout(field_type, field_offset + offset, layout, context,
301 arg_range, field_decl->getSourceRange())) {
alan-bakerfec0a472018-11-08 18:09:40 -0500302 return false;
303 }
304
305 if (prev) {
306 const auto prev_canonical = prev->getType().getCanonicalType();
307 const uint64_t prev_offset =
alan-baker9bb09792019-03-25 11:25:13 -0400308 record_layout.getFieldOffset(field_no - 1) / context.getCharWidth();
alan-bakerfec0a472018-11-08 18:09:40 -0500309 const auto prev_size =
310 context.getTypeSizeInChars(prev_canonical).getQuantity();
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400311 const auto prev_alignment =
312 GetAlignment(prev_canonical, layout, context);
alan-bakerfec0a472018-11-08 18:09:40 -0500313 const auto next_available =
314 prev_offset + llvm::alignTo(prev_size, prev_alignment);
315 if (prev_canonical->isArrayType() || prev_canonical->isRecordType()) {
316 // The next element after an array or struct must be placed on or
317 // after the next multiple of the alignment of that array or
318 // struct.
alan-baker9bb09792019-03-25 11:25:13 -0400319 // For UBO layouts, both arrays and structs must be aligned to a
320 // multiple of 16 bytes.
321 const uint64_t final_align = layout == UBO
322 ? llvm::alignTo(next_available, 16)
323 : next_available;
324 if (final_align > field_offset) {
325 Report(CustomDiagnosticUnalignedStructMember, arg_range,
alan-baker3d9e2012019-01-11 14:55:30 -0500326 field_decl->getSourceRange());
alan-bakerfec0a472018-11-08 18:09:40 -0500327 return false;
328 }
329 }
330 }
331
332 prev = field_decl;
333 }
334
335 return true;
336 }
337
338 // This will be used to check the inside of function bodies.
339 class DeclVisitor : public RecursiveASTVisitor<DeclVisitor> {
340 private:
341 ExtraValidationConsumer &consumer;
342
343 public:
344 explicit DeclVisitor(ExtraValidationConsumer &VC) : consumer(VC) {}
345
346 // Visits a declaration. Emits a diagnostic and returns false if the
347 // declaration represents an unsupported vector value or vector type.
348 // Otherwise returns true.
349 bool VisitDecl(Decl *D) {
350 // Looking at the Decl class hierarchy, it seems ValueDecl and TypeDecl
351 // are the only two that might represent an unsupported vector type.
352 if (auto *VD = dyn_cast<ValueDecl>(D)) {
353 return consumer.IsSupportedType(VD->getType(), D->getSourceRange());
354 } else if (auto *TD = dyn_cast<TypeDecl>(D)) {
355 QualType DefinedType = TD->getASTContext().getTypeDeclType(TD);
356 return consumer.IsSupportedType(DefinedType, TD->getSourceRange());
357 }
358 return true;
359 }
360 };
361
362 DeclVisitor Visitor;
Kévin Petit0fc88042019-04-09 23:25:02 +0100363 std::unordered_set<std::string> Kernels;
alan-bakerfec0a472018-11-08 18:09:40 -0500364
365public:
366 explicit ExtraValidationConsumer(CompilerInstance &Instance,
367 llvm::StringRef InFile)
368 : Instance(Instance), InFile(InFile),
369 CustomDiagnosticsIDMap(CustomDiagnosticTotal), Visitor(*this) {
370 auto &DE = Instance.getDiagnostics();
371
372 CustomDiagnosticsIDMap[CustomDiagnosticVectorsMoreThan4Elements] =
373 DE.getCustomDiagID(
374 DiagnosticsEngine::Error,
375 "vectors with more than 4 elements are not supported");
376 CustomDiagnosticsIDMap[CustomDiagnosticVoidPointer] = DE.getCustomDiagID(
377 DiagnosticsEngine::Error, "pointer-to-void is not supported");
alan-baker9bb09792019-03-25 11:25:13 -0400378 CustomDiagnosticsIDMap[CustomDiagnosticUnalignedScalar] =
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400379 DE.getCustomDiagID(DiagnosticsEngine::Error,
380 "scalar elements must be aligned to their size");
alan-baker9bb09792019-03-25 11:25:13 -0400381 CustomDiagnosticsIDMap[CustomDiagnosticUnalignedVec2] = DE.getCustomDiagID(
382 DiagnosticsEngine::Error,
383 "two-component vectors must be aligned to 2 times their element size");
384 CustomDiagnosticsIDMap[CustomDiagnosticUnalignedVec4] =
alan-bakerfec0a472018-11-08 18:09:40 -0500385 DE.getCustomDiagID(DiagnosticsEngine::Error,
alan-baker9bb09792019-03-25 11:25:13 -0400386 "three- and four-component vectors must be aligned "
387 "to 4 times their element size");
alan-bakerfec0a472018-11-08 18:09:40 -0500388 CustomDiagnosticsIDMap[CustomDiagnosticUBOUnalignedArray] =
389 DE.getCustomDiagID(DiagnosticsEngine::Error,
390 "in an UBO, arrays must be aligned to their element "
391 "alignment, rounded up to a multiple of 16 bytes");
392 CustomDiagnosticsIDMap[CustomDiagnosticUBOUnalignedStruct] =
393 DE.getCustomDiagID(
394 DiagnosticsEngine::Error,
395 "in an UBO, structs must be aligned to their "
396 "largest element alignment, rounded up to a multiple of "
397 "16 bytes");
alan-baker9bb09792019-03-25 11:25:13 -0400398 CustomDiagnosticsIDMap[CustomDiagnosticSmallStraddle] =
alan-bakerfec0a472018-11-08 18:09:40 -0500399 DE.getCustomDiagID(DiagnosticsEngine::Error,
alan-baker9bb09792019-03-25 11:25:13 -0400400 "vectors with a total size less than or equal to 16 "
401 "bytes must be placed entirely within a 16 byte "
402 "aligned region");
403 CustomDiagnosticsIDMap[CustomDiagnosticLargeStraddle] =
alan-bakerfec0a472018-11-08 18:09:40 -0500404 DE.getCustomDiagID(DiagnosticsEngine::Error,
alan-baker9bb09792019-03-25 11:25:13 -0400405 "vectors with a total size greater than 16 bytes "
406 "must aligned to 16 bytes");
407 CustomDiagnosticsIDMap[CustomDiagnosticUnalignedStructMember] =
alan-bakerfec0a472018-11-08 18:09:40 -0500408 DE.getCustomDiagID(DiagnosticsEngine::Error,
alan-baker9bb09792019-03-25 11:25:13 -0400409 "a structure member must not be placed between the "
410 "end of a structure or array and the next multiple "
411 "of the base alignment of that structure or array");
alan-bakerfec0a472018-11-08 18:09:40 -0500412 CustomDiagnosticsIDMap[CustomDiagnosticUBORestrictedSize] =
413 DE.getCustomDiagID(DiagnosticsEngine::Error,
414 "clspv restriction: UBO element size must be a "
415 "multiple of that element's alignment");
416 CustomDiagnosticsIDMap[CustomDiagnosticUBORestrictedStruct] =
417 DE.getCustomDiagID(
418 DiagnosticsEngine::Error,
419 "clspv restriction: UBO structures may not have implicit padding");
alan-baker3d9e2012019-01-11 14:55:30 -0500420 CustomDiagnosticsIDMap[CustomDiagnosticUBOArrayStride] = DE.getCustomDiagID(
421 DiagnosticsEngine::Error,
422 "clspv restriction: to satisfy UBO ArrayStride restrictions, element "
423 "size must be a multiple of array alignment");
424 CustomDiagnosticsIDMap[CustomDiagnosticLocationInfo] =
425 DE.getCustomDiagID(DiagnosticsEngine::Note, "here");
alan-baker9bb09792019-03-25 11:25:13 -0400426 CustomDiagnosticsIDMap[CustomDiagnosticSSBOUnalignedArray] =
427 DE.getCustomDiagID(
428 DiagnosticsEngine::Error,
429 "in a SSBO, arrays must be aligned to their element alignment");
430 CustomDiagnosticsIDMap[CustomDiagnosticSSBOUnalignedStruct] =
431 DE.getCustomDiagID(DiagnosticsEngine::Error,
432 "in a SSBO, structs must be aligned to their "
433 "largest element alignment");
Kévin Petit0fc88042019-04-09 23:25:02 +0100434 CustomDiagnosticsIDMap[CustomDiagnosticOverloadedKernel] =
435 DE.getCustomDiagID(DiagnosticsEngine::Error,
436 "kernel functions can't be overloaded");
alan-baker990e9b92019-06-07 11:26:39 -0400437 CustomDiagnosticsIDMap[CustomDiagnosticStructContainsPointer] =
438 DE.getCustomDiagID(DiagnosticsEngine::Error,
439 "structures may not contain pointers");
alan-bakerfec0a472018-11-08 18:09:40 -0500440 }
441
442 virtual bool HandleTopLevelDecl(DeclGroupRef DG) override {
443 for (auto *D : DG) {
444 if (auto *FD = llvm::dyn_cast<FunctionDecl>(D)) {
445 // If the function has a body it means we are not an OpenCL builtin
446 // function.
447 if (FD->hasBody()) {
448 if (!IsSupportedType(FD->getReturnType(),
449 FD->getReturnTypeSourceRange())) {
450 return false;
451 }
452
453 bool is_opencl_kernel = false;
454 if (FD->hasAttrs()) {
455 for (auto *attr : FD->attrs()) {
456 if (attr->getKind() == attr::Kind::OpenCLKernel) {
457 is_opencl_kernel = true;
458 }
459 }
460 }
461
Kévin Petit0fc88042019-04-09 23:25:02 +0100462 if (is_opencl_kernel) {
463 if (Kernels.count(FD->getName()) != 0) {
464 auto srcRange = FD->getSourceRange();
465 Report(CustomDiagnosticOverloadedKernel, srcRange, srcRange);
466 } else {
467 Kernels.insert(FD->getName());
468 }
469 }
470
alan-bakerfec0a472018-11-08 18:09:40 -0500471 for (auto *P : FD->parameters()) {
472 auto type = P->getType();
473 if (!IsSupportedType(P->getOriginalType(), P->getSourceRange())) {
474 return false;
475 }
476
alan-baker9bb09792019-03-25 11:25:13 -0400477 if (is_opencl_kernel && type->isPointerType() &&
478 ((type->getPointeeType().getAddressSpace() ==
479 LangAS::opencl_constant) ||
480 (type->getPointeeType().getAddressSpace() ==
481 LangAS::opencl_global))) {
alan-baker3d9e2012019-01-11 14:55:30 -0500482 // The argument will be generated as an array within a block.
483 // Generate an array type to check the validity for the generated
484 // case.
alan-baker9bb09792019-03-25 11:25:13 -0400485 Layout layout = SSBO;
486 if (clspv::Option::ConstantArgsInUniformBuffer() &&
487 !clspv::Option::Std430UniformBufferLayout() &&
488 type->getPointeeType().getAddressSpace() ==
489 LangAS::opencl_constant) {
490 layout = UBO;
491 }
alan-baker3d9e2012019-01-11 14:55:30 -0500492 auto array_type = FD->getASTContext().getIncompleteArrayType(
493 type->getPointeeType(), clang::ArrayType::Normal, 0);
alan-baker9bb09792019-03-25 11:25:13 -0400494 if (!IsSupportedLayout(array_type, 0, layout, FD->getASTContext(),
495 P->getSourceRange(),
496 P->getSourceRange())) {
alan-bakerfec0a472018-11-08 18:09:40 -0500497 return false;
498 }
499 }
alan-baker038e9242019-04-19 22:14:41 -0400500
501 if (is_opencl_kernel && !type->isPointerType()) {
502 Layout layout = SSBO;
503 if (clspv::Option::PodArgsInUniformBuffer() &&
504 !clspv::Option::Std430UniformBufferLayout())
505 layout = UBO;
506
507 if (!IsSupportedLayout(type, 0, layout, FD->getASTContext(),
508 P->getSourceRange(),
509 P->getSourceRange())) {
510 return false;
511 }
512 }
alan-bakerfec0a472018-11-08 18:09:40 -0500513 }
514
515 // Check for unsupported vector types.
516 Visitor.TraverseDecl(FD);
517 }
518 }
519 }
520
521 return true;
522 }
523};
524} // namespace
525
526namespace clspv {
527std::unique_ptr<ASTConsumer>
528ExtraValidationASTAction::CreateASTConsumer(CompilerInstance &CI,
529 llvm::StringRef InFile) {
530 return std::unique_ptr<ASTConsumer>(new ExtraValidationConsumer(CI, InFile));
531}
532} // namespace clspv