blob: 1ad55daeb178455ec95d00ea95d23cba10883e12 [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-baker28361f72020-01-07 16:35:25 -050058 CustomDiagnosticRecursiveStruct = 18,
alan-bakerfec0a472018-11-08 18:09:40 -050059 CustomDiagnosticTotal
60 };
61 std::vector<unsigned> CustomDiagnosticsIDMap;
62
alan-baker990e9b92019-06-07 11:26:39 -040063 bool ContainsPointerType(QualType QT) {
64 auto canonical = QT.getCanonicalType();
65 if (canonical->isPointerType()) {
66 return true;
67 } else if (auto *AT = dyn_cast<ArrayType>(canonical)) {
68 return ContainsPointerType(AT->getElementType());
69 } else if (auto *RT = dyn_cast<RecordType>(canonical)) {
70 for (auto field_decl : RT->getDecl()->fields()) {
71 if (ContainsPointerType(field_decl->getType()))
72 return true;
73 }
74 }
75
76 return false;
77 }
78
alan-baker28361f72020-01-07 16:35:25 -050079 bool IsRecursiveType(QualType QT, llvm::DenseSet<const Type *> *seen) {
80 auto canonical = QT.getCanonicalType();
81 if (canonical->isRecordType() &&
82 !seen->insert(canonical.getTypePtr()).second) {
83 return true;
84 }
85
86 if (auto *PT = dyn_cast<PointerType>(canonical)) {
87 return IsRecursiveType(canonical->getPointeeType(), seen);
88 } else if (auto *AT = dyn_cast<ArrayType>(canonical)) {
89 return IsRecursiveType(AT->getElementType(), seen);
90 } else if (auto *RT = dyn_cast<RecordType>(canonical)) {
91 for (auto field_decl : RT->getDecl()->fields()) {
92 if (IsRecursiveType(field_decl->getType(), seen))
93 return true;
94 }
95 }
96
97 seen->erase(canonical.getTypePtr());
98 return false;
99 }
100
alan-bakerfec0a472018-11-08 18:09:40 -0500101 bool IsSupportedType(QualType QT, SourceRange SR) {
102 auto *Ty = QT.getTypePtr();
103
104 // First check if we have a pointer type.
105 if (Ty->isPointerType()) {
106 const Type *pointeeTy = Ty->getPointeeType().getTypePtr();
107 if (pointeeTy && pointeeTy->isVoidType()) {
108 // We don't support void pointers.
109 Instance.getDiagnostics().Report(
110 SR.getBegin(), CustomDiagnosticsIDMap[CustomDiagnosticVoidPointer]);
111 return false;
112 }
113 // Otherwise check recursively.
114 return IsSupportedType(Ty->getPointeeType(), SR);
115 }
116
117 const auto &canonicalType = QT.getCanonicalType();
118 if (auto *VT = llvm::dyn_cast<ExtVectorType>(canonicalType)) {
119 // We don't support vectors with more than 4 elements.
120 if (4 < VT->getNumElements()) {
121 Instance.getDiagnostics().Report(
122 SR.getBegin(),
123 CustomDiagnosticsIDMap[CustomDiagnosticVectorsMoreThan4Elements]);
124 return false;
125 }
alan-baker990e9b92019-06-07 11:26:39 -0400126 } else if (canonicalType->isRecordType()) {
alan-baker28361f72020-01-07 16:35:25 -0500127 // Do not allow recursive struct definitions.
128 llvm::DenseSet<const Type *> seen;
129 if (IsRecursiveType(canonicalType, &seen)) {
alan-baker990e9b92019-06-07 11:26:39 -0400130 Instance.getDiagnostics().Report(
131 SR.getBegin(),
alan-baker28361f72020-01-07 16:35:25 -0500132 CustomDiagnosticsIDMap[CustomDiagnosticRecursiveStruct]);
alan-baker990e9b92019-06-07 11:26:39 -0400133 return false;
134 }
alan-bakerfec0a472018-11-08 18:09:40 -0500135 }
136
137 return true;
138 }
139
alan-baker3d9e2012019-01-11 14:55:30 -0500140 // Report a diagnostic using |diag|. If |arg_range| and |specific_range|
141 // differ, also issue a note with the specific location of the error.
142 void Report(const CustomDiagnosticType &diag, SourceRange arg_range,
143 SourceRange specific_range) {
144 Instance.getDiagnostics().Report(arg_range.getBegin(),
145 CustomDiagnosticsIDMap[diag]);
146 if (arg_range != specific_range) {
147 Instance.getDiagnostics().Report(
148 specific_range.getBegin(),
149 CustomDiagnosticsIDMap[CustomDiagnosticLocationInfo]);
150 }
151 }
152
alan-baker9bb09792019-03-25 11:25:13 -0400153 // Returns the alignment of |QT| to satisfy |layout|'s rules.
154 uint64_t GetAlignment(const QualType QT, const Layout &layout,
155 const ASTContext &context) const {
alan-bakerfec0a472018-11-08 18:09:40 -0500156 const auto canonical = QT.getCanonicalType();
157 uint64_t alignment = context.getTypeAlignInChars(canonical).getQuantity();
alan-baker9bb09792019-03-25 11:25:13 -0400158 if (layout == UBO &&
159 (canonical->isRecordType() || canonical->isArrayType())) {
alan-bakerfec0a472018-11-08 18:09:40 -0500160 return llvm::alignTo(alignment, 16);
161 }
162 return alignment;
163 }
164
165 // Returns true if |QT| is a valid layout for a Uniform buffer. Refer to
166 // 14.5.4 in the Vulkan specification.
alan-baker9bb09792019-03-25 11:25:13 -0400167 bool IsSupportedLayout(QualType QT, uint64_t offset, const Layout &layout,
168 ASTContext &context, SourceRange arg_range,
169 SourceRange specific_range) {
alan-bakerfec0a472018-11-08 18:09:40 -0500170 const auto canonical = QT.getCanonicalType();
171 if (canonical->isScalarType()) {
alan-baker9bb09792019-03-25 11:25:13 -0400172 if (!IsSupportedScalarLayout(canonical, offset, layout, context,
173 arg_range, specific_range))
alan-bakerfec0a472018-11-08 18:09:40 -0500174 return false;
175 } else if (canonical->isExtVectorType()) {
alan-baker9bb09792019-03-25 11:25:13 -0400176 if (!IsSupportedVectorLayout(canonical, offset, layout, context,
177 arg_range, specific_range))
alan-bakerfec0a472018-11-08 18:09:40 -0500178 return false;
179 } else if (canonical->isArrayType()) {
alan-baker9bb09792019-03-25 11:25:13 -0400180 if (!IsSupportedArrayLayout(canonical, offset, layout, context, arg_range,
181 specific_range))
alan-bakerfec0a472018-11-08 18:09:40 -0500182 return false;
183 } else if (canonical->isRecordType()) {
alan-baker9bb09792019-03-25 11:25:13 -0400184 if (!IsSupportedRecordLayout(canonical, offset, layout, context,
185 arg_range, specific_range))
alan-bakerfec0a472018-11-08 18:09:40 -0500186 return false;
187 }
188
189 // TODO(alan-baker): Find a way to avoid this restriction.
190 // Don't allow padding. This prevents structs like:
191 // struct {
192 // int x[2];
193 // int y __attribute((aligned(16)));
194 // };
195 //
196 // This would map in LLVM to { [2 x i32], [8 x i8], i32, [12 xi8] }.
197 // There is no easy way to manipulate the padding after the array to
198 // satisfy the standard Uniform buffer layout rules in this case. The usual
199 // trick is replacing the i8 arrays with an i32 element, but the i32 would
200 // still be laid out too close to the array.
201 const auto type_size = context.getTypeSizeInChars(canonical).getQuantity();
alan-baker9bb09792019-03-25 11:25:13 -0400202 const auto type_align = GetAlignment(canonical, layout, context);
203 if (layout == UBO && (type_size % type_align != 0)) {
alan-baker3d9e2012019-01-11 14:55:30 -0500204 Report(CustomDiagnosticUBORestrictedSize, arg_range, specific_range);
alan-bakerfec0a472018-11-08 18:09:40 -0500205 return false;
206 }
207
208 return true;
209 }
210
alan-baker9bb09792019-03-25 11:25:13 -0400211 bool IsSupportedScalarLayout(QualType QT, uint64_t offset,
212 const Layout & /*layout*/, ASTContext &context,
213 SourceRange arg_range,
214 SourceRange specific_range) {
alan-bakerfec0a472018-11-08 18:09:40 -0500215 // A scalar type of size N has a base alignment on N.
216 const unsigned type_size = context.getTypeSizeInChars(QT).getQuantity();
217 if (offset % type_size != 0) {
alan-baker9bb09792019-03-25 11:25:13 -0400218 Report(CustomDiagnosticUnalignedScalar, arg_range, specific_range);
alan-bakerfec0a472018-11-08 18:09:40 -0500219 return false;
220 }
221
222 return true;
223 }
224
alan-baker9bb09792019-03-25 11:25:13 -0400225 bool IsSupportedVectorLayout(QualType QT, uint64_t offset,
226 const Layout &layout, ASTContext &context,
227 SourceRange arg_range,
228 SourceRange specific_range) {
alan-bakerfec0a472018-11-08 18:09:40 -0500229 // 2-component vectors have a base alignment of 2 * (size of element).
230 // 3- and 4-component vectors hae a base alignment of 4 * (size of
231 // element).
232 const auto *VT = llvm::cast<VectorType>(QT);
233 const auto ele_size =
234 context.getTypeSizeInChars(VT->getElementType()).getQuantity();
235 if (VT->getNumElements() == 2) {
236 if (offset % (ele_size * 2) != 0) {
alan-baker9bb09792019-03-25 11:25:13 -0400237 Report(CustomDiagnosticUnalignedVec2, arg_range, specific_range);
alan-bakerfec0a472018-11-08 18:09:40 -0500238 return false;
239 }
240 } else if (offset % (ele_size * 4) != 0) {
241 // Other vector sizes cause errors elsewhere.
alan-baker9bb09792019-03-25 11:25:13 -0400242 Report(CustomDiagnosticUnalignedVec4, arg_range, specific_range);
alan-bakerfec0a472018-11-08 18:09:40 -0500243 return false;
244 }
245
246 // Straddling rules:
247 // * If total vector size is less than 16 bytes, the offset must place the
248 // entire vector within the same 16 bytes.
249 // * If total vector size is greater than 16 bytes, the offset must be a
250 // multiple of 16.
251 const auto size = context.getTypeSizeInChars(QT).getQuantity();
252 if (size <= 16 && (offset / 16 != (offset + size - 1) / 16)) {
alan-baker9bb09792019-03-25 11:25:13 -0400253 Report(CustomDiagnosticSmallStraddle, arg_range, specific_range);
alan-bakerfec0a472018-11-08 18:09:40 -0500254 return false;
255 } else if (size > 16 && (offset % 16 != 0)) {
alan-baker9bb09792019-03-25 11:25:13 -0400256 Report(CustomDiagnosticLargeStraddle, arg_range, specific_range);
alan-bakerfec0a472018-11-08 18:09:40 -0500257 return false;
258 }
259
alan-baker9bb09792019-03-25 11:25:13 -0400260 return IsSupportedLayout(VT->getElementType(), offset, layout, context,
261 arg_range, specific_range);
alan-bakerfec0a472018-11-08 18:09:40 -0500262 }
263
alan-baker9bb09792019-03-25 11:25:13 -0400264 bool IsSupportedArrayLayout(QualType QT, uint64_t offset,
265 const Layout &layout, ASTContext &context,
266 SourceRange arg_range,
267 SourceRange specific_range) {
268 // An array has a base alignment of is element type.
269 // If the layout is UBO, the alignment is rounded up to a multiple of 16.
alan-bakerfec0a472018-11-08 18:09:40 -0500270 const auto *AT = llvm::cast<ArrayType>(QT);
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400271 const auto element_align =
272 GetAlignment(AT->getElementType(), layout, context);
alan-baker9bb09792019-03-25 11:25:13 -0400273 const auto type_align =
274 layout == UBO ? llvm::alignTo(element_align, 16) : element_align;
alan-bakerfec0a472018-11-08 18:09:40 -0500275 if (offset % type_align != 0) {
alan-baker9bb09792019-03-25 11:25:13 -0400276 auto diag_id = layout == UBO ? CustomDiagnosticUBOUnalignedArray
277 : CustomDiagnosticSSBOUnalignedArray;
278 Report(diag_id, arg_range, specific_range);
alan-bakerfec0a472018-11-08 18:09:40 -0500279 return false;
280 }
alan-baker9bb09792019-03-25 11:25:13 -0400281 if (layout == UBO && !clspv::Option::RelaxedUniformBufferLayout()) {
alan-baker3d9e2012019-01-11 14:55:30 -0500282 // The ArrayStride must be a multiple of the base alignment of the array
283 // (i.e. a multiple of 16). This means that the element size must be
284 // restricted to be the base alignment of the array.
285 const auto element_size =
286 context.getTypeSizeInChars(AT->getElementType()).getQuantity();
287 if (element_size % type_align != 0) {
288 Report(CustomDiagnosticUBOArrayStride, arg_range, specific_range);
289 return false;
290 }
291 }
alan-bakerfec0a472018-11-08 18:09:40 -0500292
alan-baker9bb09792019-03-25 11:25:13 -0400293 return IsSupportedLayout(AT->getElementType(), offset, layout, context,
294 arg_range, specific_range);
alan-bakerfec0a472018-11-08 18:09:40 -0500295 }
296
alan-baker9bb09792019-03-25 11:25:13 -0400297 bool IsSupportedRecordLayout(QualType QT, uint64_t offset,
298 const Layout &layout, ASTContext &context,
299 SourceRange arg_range,
300 SourceRange specific_range) {
301 // A structure has a base alignment of its largest member. For UBO layouts,
302 // alignment is rounded up to a multiple of 16.
alan-bakerfec0a472018-11-08 18:09:40 -0500303 const auto *RT = llvm::cast<RecordType>(QT);
alan-baker9bb09792019-03-25 11:25:13 -0400304 auto type_alignment = GetAlignment(QT, layout, context);
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400305 if (layout == UBO)
306 llvm::alignTo(type_alignment, 16);
alan-bakerfec0a472018-11-08 18:09:40 -0500307 if (offset % type_alignment != 0) {
alan-baker9bb09792019-03-25 11:25:13 -0400308 auto diag_id = layout == UBO ? CustomDiagnosticUBOUnalignedStruct
309 : CustomDiagnosticSSBOUnalignedStruct;
310 Report(diag_id, arg_range, specific_range);
alan-bakerfec0a472018-11-08 18:09:40 -0500311 return false;
312 }
313
alan-baker9bb09792019-03-25 11:25:13 -0400314 const auto &record_layout = context.getASTRecordLayout(RT->getDecl());
alan-bakerfec0a472018-11-08 18:09:40 -0500315 const FieldDecl *prev = nullptr;
316 for (auto field_decl : RT->getDecl()->fields()) {
317 const auto field_type = field_decl->getType();
alan-baker9bb09792019-03-25 11:25:13 -0400318 const auto field_alignment = GetAlignment(field_type, layout, context);
alan-bakerfec0a472018-11-08 18:09:40 -0500319 const unsigned field_no = field_decl->getFieldIndex();
320 const uint64_t field_offset =
alan-baker9bb09792019-03-25 11:25:13 -0400321 record_layout.getFieldOffset(field_no) / context.getCharWidth();
alan-bakerfec0a472018-11-08 18:09:40 -0500322
323 // Rules must be checked recursively.
alan-baker9bb09792019-03-25 11:25:13 -0400324 if (!IsSupportedLayout(field_type, field_offset + offset, layout, context,
325 arg_range, field_decl->getSourceRange())) {
alan-bakerfec0a472018-11-08 18:09:40 -0500326 return false;
327 }
328
329 if (prev) {
330 const auto prev_canonical = prev->getType().getCanonicalType();
331 const uint64_t prev_offset =
alan-baker9bb09792019-03-25 11:25:13 -0400332 record_layout.getFieldOffset(field_no - 1) / context.getCharWidth();
alan-bakerfec0a472018-11-08 18:09:40 -0500333 const auto prev_size =
334 context.getTypeSizeInChars(prev_canonical).getQuantity();
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400335 const auto prev_alignment =
336 GetAlignment(prev_canonical, layout, context);
alan-bakerfec0a472018-11-08 18:09:40 -0500337 const auto next_available =
338 prev_offset + llvm::alignTo(prev_size, prev_alignment);
339 if (prev_canonical->isArrayType() || prev_canonical->isRecordType()) {
340 // The next element after an array or struct must be placed on or
341 // after the next multiple of the alignment of that array or
342 // struct.
alan-baker9bb09792019-03-25 11:25:13 -0400343 // For UBO layouts, both arrays and structs must be aligned to a
344 // multiple of 16 bytes.
345 const uint64_t final_align = layout == UBO
346 ? llvm::alignTo(next_available, 16)
347 : next_available;
348 if (final_align > field_offset) {
349 Report(CustomDiagnosticUnalignedStructMember, arg_range,
alan-baker3d9e2012019-01-11 14:55:30 -0500350 field_decl->getSourceRange());
alan-bakerfec0a472018-11-08 18:09:40 -0500351 return false;
352 }
353 }
354 }
355
356 prev = field_decl;
357 }
358
359 return true;
360 }
361
362 // This will be used to check the inside of function bodies.
363 class DeclVisitor : public RecursiveASTVisitor<DeclVisitor> {
364 private:
365 ExtraValidationConsumer &consumer;
366
367 public:
368 explicit DeclVisitor(ExtraValidationConsumer &VC) : consumer(VC) {}
369
370 // Visits a declaration. Emits a diagnostic and returns false if the
371 // declaration represents an unsupported vector value or vector type.
372 // Otherwise returns true.
373 bool VisitDecl(Decl *D) {
374 // Looking at the Decl class hierarchy, it seems ValueDecl and TypeDecl
375 // are the only two that might represent an unsupported vector type.
376 if (auto *VD = dyn_cast<ValueDecl>(D)) {
377 return consumer.IsSupportedType(VD->getType(), D->getSourceRange());
378 } else if (auto *TD = dyn_cast<TypeDecl>(D)) {
379 QualType DefinedType = TD->getASTContext().getTypeDeclType(TD);
380 return consumer.IsSupportedType(DefinedType, TD->getSourceRange());
381 }
382 return true;
383 }
384 };
385
386 DeclVisitor Visitor;
Kévin Petit0fc88042019-04-09 23:25:02 +0100387 std::unordered_set<std::string> Kernels;
alan-bakerfec0a472018-11-08 18:09:40 -0500388
389public:
390 explicit ExtraValidationConsumer(CompilerInstance &Instance,
391 llvm::StringRef InFile)
392 : Instance(Instance), InFile(InFile),
393 CustomDiagnosticsIDMap(CustomDiagnosticTotal), Visitor(*this) {
394 auto &DE = Instance.getDiagnostics();
395
396 CustomDiagnosticsIDMap[CustomDiagnosticVectorsMoreThan4Elements] =
397 DE.getCustomDiagID(
398 DiagnosticsEngine::Error,
399 "vectors with more than 4 elements are not supported");
400 CustomDiagnosticsIDMap[CustomDiagnosticVoidPointer] = DE.getCustomDiagID(
401 DiagnosticsEngine::Error, "pointer-to-void is not supported");
alan-baker9bb09792019-03-25 11:25:13 -0400402 CustomDiagnosticsIDMap[CustomDiagnosticUnalignedScalar] =
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400403 DE.getCustomDiagID(DiagnosticsEngine::Error,
404 "scalar elements must be aligned to their size");
alan-baker9bb09792019-03-25 11:25:13 -0400405 CustomDiagnosticsIDMap[CustomDiagnosticUnalignedVec2] = DE.getCustomDiagID(
406 DiagnosticsEngine::Error,
407 "two-component vectors must be aligned to 2 times their element size");
408 CustomDiagnosticsIDMap[CustomDiagnosticUnalignedVec4] =
alan-bakerfec0a472018-11-08 18:09:40 -0500409 DE.getCustomDiagID(DiagnosticsEngine::Error,
alan-baker9bb09792019-03-25 11:25:13 -0400410 "three- and four-component vectors must be aligned "
411 "to 4 times their element size");
alan-bakerfec0a472018-11-08 18:09:40 -0500412 CustomDiagnosticsIDMap[CustomDiagnosticUBOUnalignedArray] =
413 DE.getCustomDiagID(DiagnosticsEngine::Error,
414 "in an UBO, arrays must be aligned to their element "
415 "alignment, rounded up to a multiple of 16 bytes");
416 CustomDiagnosticsIDMap[CustomDiagnosticUBOUnalignedStruct] =
417 DE.getCustomDiagID(
418 DiagnosticsEngine::Error,
419 "in an UBO, structs must be aligned to their "
420 "largest element alignment, rounded up to a multiple of "
421 "16 bytes");
alan-baker9bb09792019-03-25 11:25:13 -0400422 CustomDiagnosticsIDMap[CustomDiagnosticSmallStraddle] =
alan-bakerfec0a472018-11-08 18:09:40 -0500423 DE.getCustomDiagID(DiagnosticsEngine::Error,
alan-baker9bb09792019-03-25 11:25:13 -0400424 "vectors with a total size less than or equal to 16 "
425 "bytes must be placed entirely within a 16 byte "
426 "aligned region");
427 CustomDiagnosticsIDMap[CustomDiagnosticLargeStraddle] =
alan-bakerfec0a472018-11-08 18:09:40 -0500428 DE.getCustomDiagID(DiagnosticsEngine::Error,
alan-baker9bb09792019-03-25 11:25:13 -0400429 "vectors with a total size greater than 16 bytes "
430 "must aligned to 16 bytes");
431 CustomDiagnosticsIDMap[CustomDiagnosticUnalignedStructMember] =
alan-bakerfec0a472018-11-08 18:09:40 -0500432 DE.getCustomDiagID(DiagnosticsEngine::Error,
alan-baker9bb09792019-03-25 11:25:13 -0400433 "a structure member must not be placed between the "
434 "end of a structure or array and the next multiple "
435 "of the base alignment of that structure or array");
alan-bakerfec0a472018-11-08 18:09:40 -0500436 CustomDiagnosticsIDMap[CustomDiagnosticUBORestrictedSize] =
437 DE.getCustomDiagID(DiagnosticsEngine::Error,
438 "clspv restriction: UBO element size must be a "
439 "multiple of that element's alignment");
440 CustomDiagnosticsIDMap[CustomDiagnosticUBORestrictedStruct] =
441 DE.getCustomDiagID(
442 DiagnosticsEngine::Error,
443 "clspv restriction: UBO structures may not have implicit padding");
alan-baker3d9e2012019-01-11 14:55:30 -0500444 CustomDiagnosticsIDMap[CustomDiagnosticUBOArrayStride] = DE.getCustomDiagID(
445 DiagnosticsEngine::Error,
446 "clspv restriction: to satisfy UBO ArrayStride restrictions, element "
447 "size must be a multiple of array alignment");
448 CustomDiagnosticsIDMap[CustomDiagnosticLocationInfo] =
449 DE.getCustomDiagID(DiagnosticsEngine::Note, "here");
alan-baker9bb09792019-03-25 11:25:13 -0400450 CustomDiagnosticsIDMap[CustomDiagnosticSSBOUnalignedArray] =
451 DE.getCustomDiagID(
452 DiagnosticsEngine::Error,
453 "in a SSBO, arrays must be aligned to their element alignment");
454 CustomDiagnosticsIDMap[CustomDiagnosticSSBOUnalignedStruct] =
455 DE.getCustomDiagID(DiagnosticsEngine::Error,
456 "in a SSBO, structs must be aligned to their "
457 "largest element alignment");
Kévin Petit0fc88042019-04-09 23:25:02 +0100458 CustomDiagnosticsIDMap[CustomDiagnosticOverloadedKernel] =
459 DE.getCustomDiagID(DiagnosticsEngine::Error,
460 "kernel functions can't be overloaded");
alan-baker990e9b92019-06-07 11:26:39 -0400461 CustomDiagnosticsIDMap[CustomDiagnosticStructContainsPointer] =
462 DE.getCustomDiagID(DiagnosticsEngine::Error,
463 "structures may not contain pointers");
alan-baker28361f72020-01-07 16:35:25 -0500464 CustomDiagnosticsIDMap[CustomDiagnosticRecursiveStruct] =
465 DE.getCustomDiagID(DiagnosticsEngine::Error,
466 "recursive structures are not supported");
alan-bakerfec0a472018-11-08 18:09:40 -0500467 }
468
469 virtual bool HandleTopLevelDecl(DeclGroupRef DG) override {
470 for (auto *D : DG) {
471 if (auto *FD = llvm::dyn_cast<FunctionDecl>(D)) {
472 // If the function has a body it means we are not an OpenCL builtin
473 // function.
474 if (FD->hasBody()) {
475 if (!IsSupportedType(FD->getReturnType(),
476 FD->getReturnTypeSourceRange())) {
477 return false;
478 }
479
480 bool is_opencl_kernel = false;
481 if (FD->hasAttrs()) {
482 for (auto *attr : FD->attrs()) {
483 if (attr->getKind() == attr::Kind::OpenCLKernel) {
484 is_opencl_kernel = true;
485 }
486 }
487 }
488
Kévin Petit0fc88042019-04-09 23:25:02 +0100489 if (is_opencl_kernel) {
490 if (Kernels.count(FD->getName()) != 0) {
491 auto srcRange = FD->getSourceRange();
492 Report(CustomDiagnosticOverloadedKernel, srcRange, srcRange);
493 } else {
494 Kernels.insert(FD->getName());
495 }
496 }
497
alan-bakerfec0a472018-11-08 18:09:40 -0500498 for (auto *P : FD->parameters()) {
499 auto type = P->getType();
500 if (!IsSupportedType(P->getOriginalType(), P->getSourceRange())) {
501 return false;
502 }
503
alan-baker9bb09792019-03-25 11:25:13 -0400504 if (is_opencl_kernel && type->isPointerType() &&
505 ((type->getPointeeType().getAddressSpace() ==
506 LangAS::opencl_constant) ||
507 (type->getPointeeType().getAddressSpace() ==
508 LangAS::opencl_global))) {
alan-baker3d9e2012019-01-11 14:55:30 -0500509 // The argument will be generated as an array within a block.
510 // Generate an array type to check the validity for the generated
511 // case.
alan-baker9bb09792019-03-25 11:25:13 -0400512 Layout layout = SSBO;
513 if (clspv::Option::ConstantArgsInUniformBuffer() &&
514 !clspv::Option::Std430UniformBufferLayout() &&
515 type->getPointeeType().getAddressSpace() ==
516 LangAS::opencl_constant) {
517 layout = UBO;
518 }
alan-baker3d9e2012019-01-11 14:55:30 -0500519 auto array_type = FD->getASTContext().getIncompleteArrayType(
520 type->getPointeeType(), clang::ArrayType::Normal, 0);
alan-baker9bb09792019-03-25 11:25:13 -0400521 if (!IsSupportedLayout(array_type, 0, layout, FD->getASTContext(),
522 P->getSourceRange(),
523 P->getSourceRange())) {
alan-bakerfec0a472018-11-08 18:09:40 -0500524 return false;
525 }
526 }
alan-baker038e9242019-04-19 22:14:41 -0400527
alan-baker28361f72020-01-07 16:35:25 -0500528 if (is_opencl_kernel && type->isPointerType()) {
529 auto pointee_type = type->getPointeeType().getCanonicalType();
530 if (ContainsPointerType(pointee_type)) {
531 Instance.getDiagnostics().Report(
532 P->getSourceRange().getBegin(),
533 CustomDiagnosticsIDMap
534 [CustomDiagnosticStructContainsPointer]);
535 return false;
536 }
537 }
538
alan-baker038e9242019-04-19 22:14:41 -0400539 if (is_opencl_kernel && !type->isPointerType()) {
540 Layout layout = SSBO;
541 if (clspv::Option::PodArgsInUniformBuffer() &&
542 !clspv::Option::Std430UniformBufferLayout())
543 layout = UBO;
544
545 if (!IsSupportedLayout(type, 0, layout, FD->getASTContext(),
546 P->getSourceRange(),
547 P->getSourceRange())) {
548 return false;
549 }
550 }
alan-bakerfec0a472018-11-08 18:09:40 -0500551 }
552
553 // Check for unsupported vector types.
554 Visitor.TraverseDecl(FD);
555 }
556 }
557 }
558
559 return true;
560 }
561};
562} // namespace
563
564namespace clspv {
565std::unique_ptr<ASTConsumer>
566ExtraValidationASTAction::CreateASTConsumer(CompilerInstance &CI,
567 llvm::StringRef InFile) {
568 return std::unique_ptr<ASTConsumer>(new ExtraValidationConsumer(CI, InFile));
569}
570} // namespace clspv