1//===- SemaHLSL.cpp - Semantic Analysis for HLSL constructs ---------------===//
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// This implements Semantic Analysis for HLSL constructs.
9//===----------------------------------------------------------------------===//
10
11#include "clang/Sema/SemaHLSL.h"
12#include "clang/AST/ASTConsumer.h"
13#include "clang/AST/ASTContext.h"
14#include "clang/AST/Attr.h"
15#include "clang/AST/Attrs.inc"
16#include "clang/AST/Decl.h"
17#include "clang/AST/DeclBase.h"
18#include "clang/AST/DeclCXX.h"
19#include "clang/AST/DeclarationName.h"
20#include "clang/AST/DynamicRecursiveASTVisitor.h"
21#include "clang/AST/Expr.h"
22#include "clang/AST/Type.h"
23#include "clang/AST/TypeLoc.h"
24#include "clang/Basic/Builtins.h"
25#include "clang/Basic/DiagnosticSema.h"
26#include "clang/Basic/IdentifierTable.h"
27#include "clang/Basic/LLVM.h"
28#include "clang/Basic/SourceLocation.h"
29#include "clang/Basic/Specifiers.h"
30#include "clang/Basic/TargetInfo.h"
31#include "clang/Sema/Initialization.h"
32#include "clang/Sema/Lookup.h"
33#include "clang/Sema/ParsedAttr.h"
34#include "clang/Sema/Sema.h"
35#include "clang/Sema/Template.h"
36#include "llvm/ADT/ArrayRef.h"
37#include "llvm/ADT/STLExtras.h"
38#include "llvm/ADT/SmallVector.h"
39#include "llvm/ADT/StringExtras.h"
40#include "llvm/ADT/StringRef.h"
41#include "llvm/ADT/Twine.h"
42#include "llvm/Support/Casting.h"
43#include "llvm/Support/DXILABI.h"
44#include "llvm/Support/ErrorHandling.h"
45#include "llvm/TargetParser/Triple.h"
46#include <cstddef>
47#include <iterator>
48#include <utility>
49
50using namespace clang;
51using RegisterType = HLSLResourceBindingAttr::RegisterType;
52
53static CXXRecordDecl *createHostLayoutStruct(Sema &S,
54 CXXRecordDecl *StructDecl);
55
56static RegisterType getRegisterType(ResourceClass RC) {
57 switch (RC) {
58 case ResourceClass::SRV:
59 return RegisterType::SRV;
60 case ResourceClass::UAV:
61 return RegisterType::UAV;
62 case ResourceClass::CBuffer:
63 return RegisterType::CBuffer;
64 case ResourceClass::Sampler:
65 return RegisterType::Sampler;
66 }
67 llvm_unreachable("unexpected ResourceClass value");
68}
69
70// Converts the first letter of string Slot to RegisterType.
71// Returns false if the letter does not correspond to a valid register type.
72static bool convertToRegisterType(StringRef Slot, RegisterType *RT) {
73 assert(RT != nullptr);
74 switch (Slot[0]) {
75 case 't':
76 case 'T':
77 *RT = RegisterType::SRV;
78 return true;
79 case 'u':
80 case 'U':
81 *RT = RegisterType::UAV;
82 return true;
83 case 'b':
84 case 'B':
85 *RT = RegisterType::CBuffer;
86 return true;
87 case 's':
88 case 'S':
89 *RT = RegisterType::Sampler;
90 return true;
91 case 'c':
92 case 'C':
93 *RT = RegisterType::C;
94 return true;
95 case 'i':
96 case 'I':
97 *RT = RegisterType::I;
98 return true;
99 default:
100 return false;
101 }
102}
103
104static ResourceClass getResourceClass(RegisterType RT) {
105 switch (RT) {
106 case RegisterType::SRV:
107 return ResourceClass::SRV;
108 case RegisterType::UAV:
109 return ResourceClass::UAV;
110 case RegisterType::CBuffer:
111 return ResourceClass::CBuffer;
112 case RegisterType::Sampler:
113 return ResourceClass::Sampler;
114 case RegisterType::C:
115 case RegisterType::I:
116 // Deliberately falling through to the unreachable below.
117 break;
118 }
119 llvm_unreachable("unexpected RegisterType value");
120}
121
122DeclBindingInfo *ResourceBindings::addDeclBindingInfo(const VarDecl *VD,
123 ResourceClass ResClass) {
124 assert(getDeclBindingInfo(VD, ResClass) == nullptr &&
125 "DeclBindingInfo already added");
126 assert(!hasBindingInfoForDecl(VD) || BindingsList.back().Decl == VD);
127 // VarDecl may have multiple entries for different resource classes.
128 // DeclToBindingListIndex stores the index of the first binding we saw
129 // for this decl. If there are any additional ones then that index
130 // shouldn't be updated.
131 DeclToBindingListIndex.try_emplace(Key: VD, Args: BindingsList.size());
132 return &BindingsList.emplace_back(Args&: VD, Args&: ResClass);
133}
134
135DeclBindingInfo *ResourceBindings::getDeclBindingInfo(const VarDecl *VD,
136 ResourceClass ResClass) {
137 auto Entry = DeclToBindingListIndex.find(Val: VD);
138 if (Entry != DeclToBindingListIndex.end()) {
139 for (unsigned Index = Entry->getSecond();
140 Index < BindingsList.size() && BindingsList[Index].Decl == VD;
141 ++Index) {
142 if (BindingsList[Index].ResClass == ResClass)
143 return &BindingsList[Index];
144 }
145 }
146 return nullptr;
147}
148
149bool ResourceBindings::hasBindingInfoForDecl(const VarDecl *VD) const {
150 return DeclToBindingListIndex.contains(Val: VD);
151}
152
153SemaHLSL::SemaHLSL(Sema &S) : SemaBase(S) {}
154
155Decl *SemaHLSL::ActOnStartBuffer(Scope *BufferScope, bool CBuffer,
156 SourceLocation KwLoc, IdentifierInfo *Ident,
157 SourceLocation IdentLoc,
158 SourceLocation LBrace) {
159 // For anonymous namespace, take the location of the left brace.
160 DeclContext *LexicalParent = SemaRef.getCurLexicalContext();
161 HLSLBufferDecl *Result = HLSLBufferDecl::Create(
162 C&: getASTContext(), LexicalParent, CBuffer, KwLoc, ID: Ident, IDLoc: IdentLoc, LBrace);
163
164 // if CBuffer is false, then it's a TBuffer
165 auto RC = CBuffer ? llvm::hlsl::ResourceClass::CBuffer
166 : llvm::hlsl::ResourceClass::SRV;
167 Result->addAttr(HLSLResourceClassAttr::CreateImplicit(getASTContext(), RC));
168
169 SemaRef.PushOnScopeChains(Result, BufferScope);
170 SemaRef.PushDeclContext(BufferScope, Result);
171
172 return Result;
173}
174
175static unsigned calculateLegacyCbufferFieldAlign(const ASTContext &Context,
176 QualType T) {
177 // Arrays and Structs are always aligned to new buffer rows
178 if (T->isArrayType() || T->isStructureType())
179 return 16;
180
181 // Vectors are aligned to the type they contain
182 if (const VectorType *VT = T->getAs<VectorType>())
183 return calculateLegacyCbufferFieldAlign(Context, T: VT->getElementType());
184
185 assert(Context.getTypeSize(T) <= 64 &&
186 "Scalar bit widths larger than 64 not supported");
187
188 // Scalar types are aligned to their byte width
189 return Context.getTypeSize(T) / 8;
190}
191
192// Calculate the size of a legacy cbuffer type in bytes based on
193// https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-packing-rules
194static unsigned calculateLegacyCbufferSize(const ASTContext &Context,
195 QualType T) {
196 constexpr unsigned CBufferAlign = 16;
197 if (const RecordType *RT = T->getAs<RecordType>()) {
198 unsigned Size = 0;
199 const RecordDecl *RD = RT->getDecl();
200 for (const FieldDecl *Field : RD->fields()) {
201 QualType Ty = Field->getType();
202 unsigned FieldSize = calculateLegacyCbufferSize(Context, T: Ty);
203 unsigned FieldAlign = calculateLegacyCbufferFieldAlign(Context, T: Ty);
204
205 // If the field crosses the row boundary after alignment it drops to the
206 // next row
207 unsigned AlignSize = llvm::alignTo(Value: Size, Align: FieldAlign);
208 if ((AlignSize % CBufferAlign) + FieldSize > CBufferAlign) {
209 FieldAlign = CBufferAlign;
210 }
211
212 Size = llvm::alignTo(Value: Size, Align: FieldAlign);
213 Size += FieldSize;
214 }
215 return Size;
216 }
217
218 if (const ConstantArrayType *AT = Context.getAsConstantArrayType(T)) {
219 unsigned ElementCount = AT->getSize().getZExtValue();
220 if (ElementCount == 0)
221 return 0;
222
223 unsigned ElementSize =
224 calculateLegacyCbufferSize(Context, AT->getElementType());
225 unsigned AlignedElementSize = llvm::alignTo(Value: ElementSize, Align: CBufferAlign);
226 return AlignedElementSize * (ElementCount - 1) + ElementSize;
227 }
228
229 if (const VectorType *VT = T->getAs<VectorType>()) {
230 unsigned ElementCount = VT->getNumElements();
231 unsigned ElementSize =
232 calculateLegacyCbufferSize(Context, T: VT->getElementType());
233 return ElementSize * ElementCount;
234 }
235
236 return Context.getTypeSize(T) / 8;
237}
238
239// Validate packoffset:
240// - if packoffset it used it must be set on all declarations inside the buffer
241// - packoffset ranges must not overlap
242static void validatePackoffset(Sema &S, HLSLBufferDecl *BufDecl) {
243 llvm::SmallVector<std::pair<VarDecl *, HLSLPackOffsetAttr *>> PackOffsetVec;
244
245 // Make sure the packoffset annotations are either on all declarations
246 // or on none.
247 bool HasPackOffset = false;
248 bool HasNonPackOffset = false;
249 for (auto *Field : BufDecl->buffer_decls()) {
250 VarDecl *Var = dyn_cast<VarDecl>(Val: Field);
251 if (!Var)
252 continue;
253 if (Field->hasAttr<HLSLPackOffsetAttr>()) {
254 PackOffsetVec.emplace_back(Var, Field->getAttr<HLSLPackOffsetAttr>());
255 HasPackOffset = true;
256 } else {
257 HasNonPackOffset = true;
258 }
259 }
260
261 if (!HasPackOffset)
262 return;
263
264 if (HasNonPackOffset)
265 S.Diag(BufDecl->getLocation(), diag::warn_hlsl_packoffset_mix);
266
267 // Make sure there is no overlap in packoffset - sort PackOffsetVec by offset
268 // and compare adjacent values.
269 bool IsValid = true;
270 ASTContext &Context = S.getASTContext();
271 std::sort(PackOffsetVec.begin(), PackOffsetVec.end(),
272 [](const std::pair<VarDecl *, HLSLPackOffsetAttr *> &LHS,
273 const std::pair<VarDecl *, HLSLPackOffsetAttr *> &RHS) {
274 return LHS.second->getOffsetInBytes() <
275 RHS.second->getOffsetInBytes();
276 });
277 for (unsigned i = 0; i < PackOffsetVec.size() - 1; i++) {
278 VarDecl *Var = PackOffsetVec[i].first;
279 HLSLPackOffsetAttr *Attr = PackOffsetVec[i].second;
280 unsigned Size = calculateLegacyCbufferSize(Context, Var->getType());
281 unsigned Begin = Attr->getOffsetInBytes();
282 unsigned End = Begin + Size;
283 unsigned NextBegin = PackOffsetVec[i + 1].second->getOffsetInBytes();
284 if (End > NextBegin) {
285 VarDecl *NextVar = PackOffsetVec[i + 1].first;
286 S.Diag(NextVar->getLocation(), diag::err_hlsl_packoffset_overlap)
287 << NextVar << Var;
288 IsValid = false;
289 }
290 }
291 BufDecl->setHasValidPackoffset(IsValid);
292}
293
294// Returns true if the array has a zero size = if any of the dimensions is 0
295static bool isZeroSizedArray(const ConstantArrayType *CAT) {
296 while (CAT && !CAT->isZeroSize())
297 CAT = dyn_cast<ConstantArrayType>(
298 CAT->getElementType()->getUnqualifiedDesugaredType());
299 return CAT != nullptr;
300}
301
302// Returns true if the record type is an HLSL resource class or an array of
303// resource classes
304static bool isResourceRecordTypeOrArrayOf(const Type *Ty) {
305 while (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(Val: Ty))
306 Ty = CAT->getArrayElementTypeNoTypeQual();
307 return HLSLAttributedResourceType::findHandleTypeOnResource(RT: Ty) != nullptr;
308}
309
310static bool isResourceRecordTypeOrArrayOf(VarDecl *VD) {
311 return isResourceRecordTypeOrArrayOf(VD->getType().getTypePtr());
312}
313
314// Returns true if the type is a leaf element type that is not valid to be
315// included in HLSL Buffer, such as a resource class, empty struct, zero-sized
316// array, or a builtin intangible type. Returns false it is a valid leaf element
317// type or if it is a record type that needs to be inspected further.
318static bool isInvalidConstantBufferLeafElementType(const Type *Ty) {
319 Ty = Ty->getUnqualifiedDesugaredType();
320 if (isResourceRecordTypeOrArrayOf(Ty))
321 return true;
322 if (Ty->isRecordType())
323 return Ty->getAsCXXRecordDecl()->isEmpty();
324 if (Ty->isConstantArrayType() &&
325 isZeroSizedArray(CAT: cast<ConstantArrayType>(Val: Ty)))
326 return true;
327 if (Ty->isHLSLBuiltinIntangibleType() || Ty->isHLSLAttributedResourceType())
328 return true;
329 return false;
330}
331
332// Returns true if the struct contains at least one element that prevents it
333// from being included inside HLSL Buffer as is, such as an intangible type,
334// empty struct, or zero-sized array. If it does, a new implicit layout struct
335// needs to be created for HLSL Buffer use that will exclude these unwanted
336// declarations (see createHostLayoutStruct function).
337static bool requiresImplicitBufferLayoutStructure(const CXXRecordDecl *RD) {
338 if (RD->getTypeForDecl()->isHLSLIntangibleType() || RD->isEmpty())
339 return true;
340 // check fields
341 for (const FieldDecl *Field : RD->fields()) {
342 QualType Ty = Field->getType();
343 if (isInvalidConstantBufferLeafElementType(Ty.getTypePtr()))
344 return true;
345 if (Ty->isRecordType() &&
346 requiresImplicitBufferLayoutStructure(Ty->getAsCXXRecordDecl()))
347 return true;
348 }
349 // check bases
350 for (const CXXBaseSpecifier &Base : RD->bases())
351 if (requiresImplicitBufferLayoutStructure(
352 RD: Base.getType()->getAsCXXRecordDecl()))
353 return true;
354 return false;
355}
356
357static CXXRecordDecl *findRecordDeclInContext(IdentifierInfo *II,
358 DeclContext *DC) {
359 CXXRecordDecl *RD = nullptr;
360 for (NamedDecl *Decl :
361 DC->getNonTransparentContext()->lookup(Name: DeclarationName(II))) {
362 if (CXXRecordDecl *FoundRD = dyn_cast<CXXRecordDecl>(Val: Decl)) {
363 assert(RD == nullptr &&
364 "there should be at most 1 record by a given name in a scope");
365 RD = FoundRD;
366 }
367 }
368 return RD;
369}
370
371// Creates a name for buffer layout struct using the provide name base.
372// If the name must be unique (not previously defined), a suffix is added
373// until a unique name is found.
374static IdentifierInfo *getHostLayoutStructName(Sema &S, NamedDecl *BaseDecl,
375 bool MustBeUnique) {
376 ASTContext &AST = S.getASTContext();
377
378 IdentifierInfo *NameBaseII = BaseDecl->getIdentifier();
379 llvm::SmallString<64> Name("__cblayout_");
380 if (NameBaseII) {
381 Name.append(RHS: NameBaseII->getName());
382 } else {
383 // anonymous struct
384 Name.append(RHS: "anon");
385 MustBeUnique = true;
386 }
387
388 size_t NameLength = Name.size();
389 IdentifierInfo *II = &AST.Idents.get(Name, TokenCode: tok::TokenKind::identifier);
390 if (!MustBeUnique)
391 return II;
392
393 unsigned suffix = 0;
394 while (true) {
395 if (suffix != 0) {
396 Name.append(RHS: "_");
397 Name.append(RHS: llvm::Twine(suffix).str());
398 II = &AST.Idents.get(Name, TokenCode: tok::TokenKind::identifier);
399 }
400 if (!findRecordDeclInContext(II, BaseDecl->getDeclContext()))
401 return II;
402 // declaration with that name already exists - increment suffix and try
403 // again until unique name is found
404 suffix++;
405 Name.truncate(N: NameLength);
406 };
407}
408
409// Creates a field declaration of given name and type for HLSL buffer layout
410// struct. Returns nullptr if the type cannot be use in HLSL Buffer layout.
411static FieldDecl *createFieldForHostLayoutStruct(Sema &S, const Type *Ty,
412 IdentifierInfo *II,
413 CXXRecordDecl *LayoutStruct) {
414 if (isInvalidConstantBufferLeafElementType(Ty))
415 return nullptr;
416
417 if (Ty->isRecordType()) {
418 CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
419 if (requiresImplicitBufferLayoutStructure(RD)) {
420 RD = createHostLayoutStruct(S, StructDecl: RD);
421 if (!RD)
422 return nullptr;
423 Ty = RD->getTypeForDecl();
424 }
425 }
426
427 QualType QT = QualType(Ty, 0);
428 ASTContext &AST = S.getASTContext();
429 TypeSourceInfo *TSI = AST.getTrivialTypeSourceInfo(T: QT, Loc: SourceLocation());
430 auto *Field = FieldDecl::Create(AST, LayoutStruct, SourceLocation(),
431 SourceLocation(), II, QT, TSI, nullptr, false,
432 InClassInitStyle::ICIS_NoInit);
433 Field->setAccess(AccessSpecifier::AS_public);
434 return Field;
435}
436
437// Creates host layout struct for a struct included in HLSL Buffer.
438// The layout struct will include only fields that are allowed in HLSL buffer.
439// These fields will be filtered out:
440// - resource classes
441// - empty structs
442// - zero-sized arrays
443// Returns nullptr if the resulting layout struct would be empty.
444static CXXRecordDecl *createHostLayoutStruct(Sema &S,
445 CXXRecordDecl *StructDecl) {
446 assert(requiresImplicitBufferLayoutStructure(StructDecl) &&
447 "struct is already HLSL buffer compatible");
448
449 ASTContext &AST = S.getASTContext();
450 DeclContext *DC = StructDecl->getDeclContext();
451 IdentifierInfo *II = getHostLayoutStructName(S, StructDecl, false);
452
453 // reuse existing if the layout struct if it already exists
454 if (CXXRecordDecl *RD = findRecordDeclInContext(II, DC))
455 return RD;
456
457 CXXRecordDecl *LS =
458 CXXRecordDecl::Create(C: AST, TK: TagDecl::TagKind::Struct, DC, StartLoc: SourceLocation(),
459 IdLoc: SourceLocation(), Id: II);
460 LS->setImplicit(true);
461 LS->addAttr(PackedAttr::CreateImplicit(AST));
462 LS->startDefinition();
463
464 // copy base struct, create HLSL Buffer compatible version if needed
465 if (unsigned NumBases = StructDecl->getNumBases()) {
466 assert(NumBases == 1 && "HLSL supports only one base type");
467 (void)NumBases;
468 CXXBaseSpecifier Base = *StructDecl->bases_begin();
469 CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
470 if (requiresImplicitBufferLayoutStructure(RD: BaseDecl)) {
471 BaseDecl = createHostLayoutStruct(S, StructDecl: BaseDecl);
472 if (BaseDecl) {
473 TypeSourceInfo *TSI = AST.getTrivialTypeSourceInfo(
474 T: QualType(BaseDecl->getTypeForDecl(), 0));
475 Base = CXXBaseSpecifier(SourceRange(), false, StructDecl->isClass(),
476 AS_none, TSI, SourceLocation());
477 }
478 }
479 if (BaseDecl) {
480 const CXXBaseSpecifier *BasesArray[1] = {&Base};
481 LS->setBases(Bases: BasesArray, NumBases: 1);
482 }
483 }
484
485 // filter struct fields
486 for (const FieldDecl *FD : StructDecl->fields()) {
487 const Type *Ty = FD->getType()->getUnqualifiedDesugaredType();
488 if (FieldDecl *NewFD =
489 createFieldForHostLayoutStruct(S, Ty, FD->getIdentifier(), LS))
490 LS->addDecl(NewFD);
491 }
492 LS->completeDefinition();
493
494 if (LS->field_empty() && LS->getNumBases() == 0)
495 return nullptr;
496
497 DC->addDecl(LS);
498 return LS;
499}
500
501// Creates host layout struct for HLSL Buffer. The struct will include only
502// fields of types that are allowed in HLSL buffer and it will filter out:
503// - static or groupshared variable declarations
504// - resource classes
505// - empty structs
506// - zero-sized arrays
507// - non-variable declarations
508// The layout struct will be added to the HLSLBufferDecl declarations.
509void createHostLayoutStructForBuffer(Sema &S, HLSLBufferDecl *BufDecl) {
510 ASTContext &AST = S.getASTContext();
511 IdentifierInfo *II = getHostLayoutStructName(S, BufDecl, true);
512
513 CXXRecordDecl *LS =
514 CXXRecordDecl::Create(AST, TagDecl::TagKind::Struct, BufDecl,
515 SourceLocation(), SourceLocation(), II);
516 LS->addAttr(PackedAttr::CreateImplicit(AST));
517 LS->setImplicit(true);
518 LS->startDefinition();
519
520 for (Decl *D : BufDecl->buffer_decls()) {
521 VarDecl *VD = dyn_cast<VarDecl>(Val: D);
522 if (!VD || VD->getStorageClass() == SC_Static ||
523 VD->getType().getAddressSpace() == LangAS::hlsl_groupshared)
524 continue;
525 const Type *Ty = VD->getType()->getUnqualifiedDesugaredType();
526 if (FieldDecl *FD =
527 createFieldForHostLayoutStruct(S, Ty, VD->getIdentifier(), LS)) {
528 // add the field decl to the layout struct
529 LS->addDecl(FD);
530 // update address space of the original decl to hlsl_constant
531 QualType NewTy =
532 AST.getAddrSpaceQualType(T: VD->getType(), AddressSpace: LangAS::hlsl_constant);
533 VD->setType(NewTy);
534 }
535 }
536 LS->completeDefinition();
537 BufDecl->addLayoutStruct(LS);
538}
539
540static void addImplicitBindingAttrToBuffer(Sema &S, HLSLBufferDecl *BufDecl,
541 uint32_t ImplicitBindingOrderID) {
542 RegisterType RT =
543 BufDecl->isCBuffer() ? RegisterType::CBuffer : RegisterType::SRV;
544 auto *Attr =
545 HLSLResourceBindingAttr::CreateImplicit(S.getASTContext(), "", "0", {});
546 std::optional<unsigned> RegSlot;
547 Attr->setBinding(RT, RegSlot, 0);
548 Attr->setImplicitBindingOrderID(ImplicitBindingOrderID);
549 BufDecl->addAttr(A: Attr);
550}
551
552// Handle end of cbuffer/tbuffer declaration
553void SemaHLSL::ActOnFinishBuffer(Decl *Dcl, SourceLocation RBrace) {
554 auto *BufDecl = cast<HLSLBufferDecl>(Val: Dcl);
555 BufDecl->setRBraceLoc(RBrace);
556
557 validatePackoffset(S&: SemaRef, BufDecl);
558
559 // create buffer layout struct
560 createHostLayoutStructForBuffer(S&: SemaRef, BufDecl);
561
562 HLSLResourceBindingAttr *RBA = Dcl->getAttr<HLSLResourceBindingAttr>();
563 if (!RBA || !RBA->hasRegisterSlot()) {
564 SemaRef.Diag(Dcl->getLocation(), diag::warn_hlsl_implicit_binding);
565 // Use HLSLResourceBindingAttr to transfer implicit binding order_ID
566 // to codegen. If it does not exist, create an implicit attribute.
567 uint32_t OrderID = getNextImplicitBindingOrderID();
568 if (RBA)
569 RBA->setImplicitBindingOrderID(OrderID);
570 else
571 addImplicitBindingAttrToBuffer(S&: SemaRef, BufDecl, ImplicitBindingOrderID: OrderID);
572 }
573
574 SemaRef.PopDeclContext();
575}
576
577HLSLNumThreadsAttr *SemaHLSL::mergeNumThreadsAttr(Decl *D,
578 const AttributeCommonInfo &AL,
579 int X, int Y, int Z) {
580 if (HLSLNumThreadsAttr *NT = D->getAttr<HLSLNumThreadsAttr>()) {
581 if (NT->getX() != X || NT->getY() != Y || NT->getZ() != Z) {
582 Diag(NT->getLocation(), diag::err_hlsl_attribute_param_mismatch) << AL;
583 Diag(AL.getLoc(), diag::note_conflicting_attribute);
584 }
585 return nullptr;
586 }
587 return ::new (getASTContext())
588 HLSLNumThreadsAttr(getASTContext(), AL, X, Y, Z);
589}
590
591HLSLWaveSizeAttr *SemaHLSL::mergeWaveSizeAttr(Decl *D,
592 const AttributeCommonInfo &AL,
593 int Min, int Max, int Preferred,
594 int SpelledArgsCount) {
595 if (HLSLWaveSizeAttr *WS = D->getAttr<HLSLWaveSizeAttr>()) {
596 if (WS->getMin() != Min || WS->getMax() != Max ||
597 WS->getPreferred() != Preferred ||
598 WS->getSpelledArgsCount() != SpelledArgsCount) {
599 Diag(WS->getLocation(), diag::err_hlsl_attribute_param_mismatch) << AL;
600 Diag(AL.getLoc(), diag::note_conflicting_attribute);
601 }
602 return nullptr;
603 }
604 HLSLWaveSizeAttr *Result = ::new (getASTContext())
605 HLSLWaveSizeAttr(getASTContext(), AL, Min, Max, Preferred);
606 Result->setSpelledArgsCount(SpelledArgsCount);
607 return Result;
608}
609
610HLSLShaderAttr *
611SemaHLSL::mergeShaderAttr(Decl *D, const AttributeCommonInfo &AL,
612 llvm::Triple::EnvironmentType ShaderType) {
613 if (HLSLShaderAttr *NT = D->getAttr<HLSLShaderAttr>()) {
614 if (NT->getType() != ShaderType) {
615 Diag(NT->getLocation(), diag::err_hlsl_attribute_param_mismatch) << AL;
616 Diag(AL.getLoc(), diag::note_conflicting_attribute);
617 }
618 return nullptr;
619 }
620 return HLSLShaderAttr::Create(getASTContext(), ShaderType, AL);
621}
622
623HLSLParamModifierAttr *
624SemaHLSL::mergeParamModifierAttr(Decl *D, const AttributeCommonInfo &AL,
625 HLSLParamModifierAttr::Spelling Spelling) {
626 // We can only merge an `in` attribute with an `out` attribute. All other
627 // combinations of duplicated attributes are ill-formed.
628 if (HLSLParamModifierAttr *PA = D->getAttr<HLSLParamModifierAttr>()) {
629 if ((PA->isIn() && Spelling == HLSLParamModifierAttr::Keyword_out) ||
630 (PA->isOut() && Spelling == HLSLParamModifierAttr::Keyword_in)) {
631 D->dropAttr<HLSLParamModifierAttr>();
632 SourceRange AdjustedRange = {PA->getLocation(), AL.getRange().getEnd()};
633 return HLSLParamModifierAttr::Create(
634 getASTContext(), /*MergedSpelling=*/true, AdjustedRange,
635 HLSLParamModifierAttr::Keyword_inout);
636 }
637 Diag(AL.getLoc(), diag::err_hlsl_duplicate_parameter_modifier) << AL;
638 Diag(PA->getLocation(), diag::note_conflicting_attribute);
639 return nullptr;
640 }
641 return HLSLParamModifierAttr::Create(getASTContext(), AL);
642}
643
644void SemaHLSL::ActOnTopLevelFunction(FunctionDecl *FD) {
645 auto &TargetInfo = getASTContext().getTargetInfo();
646
647 if (FD->getName() != TargetInfo.getTargetOpts().HLSLEntry)
648 return;
649
650 llvm::Triple::EnvironmentType Env = TargetInfo.getTriple().getEnvironment();
651 if (HLSLShaderAttr::isValidShaderType(Env) && Env != llvm::Triple::Library) {
652 if (const auto *Shader = FD->getAttr<HLSLShaderAttr>()) {
653 // The entry point is already annotated - check that it matches the
654 // triple.
655 if (Shader->getType() != Env) {
656 Diag(Shader->getLocation(), diag::err_hlsl_entry_shader_attr_mismatch)
657 << Shader;
658 FD->setInvalidDecl();
659 }
660 } else {
661 // Implicitly add the shader attribute if the entry function isn't
662 // explicitly annotated.
663 FD->addAttr(HLSLShaderAttr::CreateImplicit(getASTContext(), Env,
664 FD->getBeginLoc()));
665 }
666 } else {
667 switch (Env) {
668 case llvm::Triple::UnknownEnvironment:
669 case llvm::Triple::Library:
670 break;
671 default:
672 llvm_unreachable("Unhandled environment in triple");
673 }
674 }
675}
676
677void SemaHLSL::CheckEntryPoint(FunctionDecl *FD) {
678 const auto *ShaderAttr = FD->getAttr<HLSLShaderAttr>();
679 assert(ShaderAttr && "Entry point has no shader attribute");
680 llvm::Triple::EnvironmentType ST = ShaderAttr->getType();
681 auto &TargetInfo = getASTContext().getTargetInfo();
682 VersionTuple Ver = TargetInfo.getTriple().getOSVersion();
683 switch (ST) {
684 case llvm::Triple::Pixel:
685 case llvm::Triple::Vertex:
686 case llvm::Triple::Geometry:
687 case llvm::Triple::Hull:
688 case llvm::Triple::Domain:
689 case llvm::Triple::RayGeneration:
690 case llvm::Triple::Intersection:
691 case llvm::Triple::AnyHit:
692 case llvm::Triple::ClosestHit:
693 case llvm::Triple::Miss:
694 case llvm::Triple::Callable:
695 if (const auto *NT = FD->getAttr<HLSLNumThreadsAttr>()) {
696 DiagnoseAttrStageMismatch(A: NT, Stage: ST,
697 AllowedStages: {llvm::Triple::Compute,
698 llvm::Triple::Amplification,
699 llvm::Triple::Mesh});
700 FD->setInvalidDecl();
701 }
702 if (const auto *WS = FD->getAttr<HLSLWaveSizeAttr>()) {
703 DiagnoseAttrStageMismatch(A: WS, Stage: ST,
704 AllowedStages: {llvm::Triple::Compute,
705 llvm::Triple::Amplification,
706 llvm::Triple::Mesh});
707 FD->setInvalidDecl();
708 }
709 break;
710
711 case llvm::Triple::Compute:
712 case llvm::Triple::Amplification:
713 case llvm::Triple::Mesh:
714 if (!FD->hasAttr<HLSLNumThreadsAttr>()) {
715 Diag(FD->getLocation(), diag::err_hlsl_missing_numthreads)
716 << llvm::Triple::getEnvironmentTypeName(ST);
717 FD->setInvalidDecl();
718 }
719 if (const auto *WS = FD->getAttr<HLSLWaveSizeAttr>()) {
720 if (Ver < VersionTuple(6, 6)) {
721 Diag(WS->getLocation(), diag::err_hlsl_attribute_in_wrong_shader_model)
722 << WS << "6.6";
723 FD->setInvalidDecl();
724 } else if (WS->getSpelledArgsCount() > 1 && Ver < VersionTuple(6, 8)) {
725 Diag(
726 WS->getLocation(),
727 diag::err_hlsl_attribute_number_arguments_insufficient_shader_model)
728 << WS << WS->getSpelledArgsCount() << "6.8";
729 FD->setInvalidDecl();
730 }
731 }
732 break;
733 default:
734 llvm_unreachable("Unhandled environment in triple");
735 }
736
737 for (ParmVarDecl *Param : FD->parameters()) {
738 if (const auto *AnnotationAttr = Param->getAttr<HLSLAnnotationAttr>()) {
739 CheckSemanticAnnotation(EntryPoint: FD, Param, AnnotationAttr: AnnotationAttr);
740 } else {
741 // FIXME: Handle struct parameters where annotations are on struct fields.
742 // See: https://github.com/llvm/llvm-project/issues/57875
743 Diag(FD->getLocation(), diag::err_hlsl_missing_semantic_annotation);
744 Diag(Param->getLocation(), diag::note_previous_decl) << Param;
745 FD->setInvalidDecl();
746 }
747 }
748 // FIXME: Verify return type semantic annotation.
749}
750
751void SemaHLSL::CheckSemanticAnnotation(
752 FunctionDecl *EntryPoint, const Decl *Param,
753 const HLSLAnnotationAttr *AnnotationAttr) {
754 auto *ShaderAttr = EntryPoint->getAttr<HLSLShaderAttr>();
755 assert(ShaderAttr && "Entry point has no shader attribute");
756 llvm::Triple::EnvironmentType ST = ShaderAttr->getType();
757
758 switch (AnnotationAttr->getKind()) {
759 case attr::HLSLSV_DispatchThreadID:
760 case attr::HLSLSV_GroupIndex:
761 case attr::HLSLSV_GroupThreadID:
762 case attr::HLSLSV_GroupID:
763 if (ST == llvm::Triple::Compute)
764 return;
765 DiagnoseAttrStageMismatch(A: AnnotationAttr, Stage: ST, AllowedStages: {llvm::Triple::Compute});
766 break;
767 case attr::HLSLSV_Position:
768 // TODO(#143523): allow use on other shader types & output once the overall
769 // semantic logic is implemented.
770 if (ST == llvm::Triple::Pixel)
771 return;
772 DiagnoseAttrStageMismatch(A: AnnotationAttr, Stage: ST, AllowedStages: {llvm::Triple::Pixel});
773 break;
774 default:
775 llvm_unreachable("Unknown HLSLAnnotationAttr");
776 }
777}
778
779void SemaHLSL::DiagnoseAttrStageMismatch(
780 const Attr *A, llvm::Triple::EnvironmentType Stage,
781 std::initializer_list<llvm::Triple::EnvironmentType> AllowedStages) {
782 SmallVector<StringRef, 8> StageStrings;
783 llvm::transform(Range&: AllowedStages, d_first: std::back_inserter(x&: StageStrings),
784 F: [](llvm::Triple::EnvironmentType ST) {
785 return StringRef(
786 HLSLShaderAttr::ConvertEnvironmentTypeToStr(ST));
787 });
788 Diag(A->getLoc(), diag::err_hlsl_attr_unsupported_in_stage)
789 << A->getAttrName() << llvm::Triple::getEnvironmentTypeName(Stage)
790 << (AllowedStages.size() != 1) << join(StageStrings, ", ");
791}
792
793template <CastKind Kind>
794static void castVector(Sema &S, ExprResult &E, QualType &Ty, unsigned Sz) {
795 if (const auto *VTy = Ty->getAs<VectorType>())
796 Ty = VTy->getElementType();
797 Ty = S.getASTContext().getExtVectorType(VectorType: Ty, NumElts: Sz);
798 E = S.ImpCastExprToType(E: E.get(), Type: Ty, CK: Kind);
799}
800
801template <CastKind Kind>
802static QualType castElement(Sema &S, ExprResult &E, QualType Ty) {
803 E = S.ImpCastExprToType(E: E.get(), Type: Ty, CK: Kind);
804 return Ty;
805}
806
807static QualType handleFloatVectorBinOpConversion(
808 Sema &SemaRef, ExprResult &LHS, ExprResult &RHS, QualType LHSType,
809 QualType RHSType, QualType LElTy, QualType RElTy, bool IsCompAssign) {
810 bool LHSFloat = LElTy->isRealFloatingType();
811 bool RHSFloat = RElTy->isRealFloatingType();
812
813 if (LHSFloat && RHSFloat) {
814 if (IsCompAssign ||
815 SemaRef.getASTContext().getFloatingTypeOrder(LHS: LElTy, RHS: RElTy) > 0)
816 return castElement<CK_FloatingCast>(S&: SemaRef, E&: RHS, Ty: LHSType);
817
818 return castElement<CK_FloatingCast>(S&: SemaRef, E&: LHS, Ty: RHSType);
819 }
820
821 if (LHSFloat)
822 return castElement<CK_IntegralToFloating>(S&: SemaRef, E&: RHS, Ty: LHSType);
823
824 assert(RHSFloat);
825 if (IsCompAssign)
826 return castElement<clang::CK_FloatingToIntegral>(S&: SemaRef, E&: RHS, Ty: LHSType);
827
828 return castElement<CK_IntegralToFloating>(S&: SemaRef, E&: LHS, Ty: RHSType);
829}
830
831static QualType handleIntegerVectorBinOpConversion(
832 Sema &SemaRef, ExprResult &LHS, ExprResult &RHS, QualType LHSType,
833 QualType RHSType, QualType LElTy, QualType RElTy, bool IsCompAssign) {
834
835 int IntOrder = SemaRef.Context.getIntegerTypeOrder(LHS: LElTy, RHS: RElTy);
836 bool LHSSigned = LElTy->hasSignedIntegerRepresentation();
837 bool RHSSigned = RElTy->hasSignedIntegerRepresentation();
838 auto &Ctx = SemaRef.getASTContext();
839
840 // If both types have the same signedness, use the higher ranked type.
841 if (LHSSigned == RHSSigned) {
842 if (IsCompAssign || IntOrder >= 0)
843 return castElement<CK_IntegralCast>(S&: SemaRef, E&: RHS, Ty: LHSType);
844
845 return castElement<CK_IntegralCast>(S&: SemaRef, E&: LHS, Ty: RHSType);
846 }
847
848 // If the unsigned type has greater than or equal rank of the signed type, use
849 // the unsigned type.
850 if (IntOrder != (LHSSigned ? 1 : -1)) {
851 if (IsCompAssign || RHSSigned)
852 return castElement<CK_IntegralCast>(S&: SemaRef, E&: RHS, Ty: LHSType);
853 return castElement<CK_IntegralCast>(S&: SemaRef, E&: LHS, Ty: RHSType);
854 }
855
856 // At this point the signed type has higher rank than the unsigned type, which
857 // means it will be the same size or bigger. If the signed type is bigger, it
858 // can represent all the values of the unsigned type, so select it.
859 if (Ctx.getIntWidth(T: LElTy) != Ctx.getIntWidth(T: RElTy)) {
860 if (IsCompAssign || LHSSigned)
861 return castElement<CK_IntegralCast>(S&: SemaRef, E&: RHS, Ty: LHSType);
862 return castElement<CK_IntegralCast>(S&: SemaRef, E&: LHS, Ty: RHSType);
863 }
864
865 // This is a bit of an odd duck case in HLSL. It shouldn't happen, but can due
866 // to C/C++ leaking through. The place this happens today is long vs long
867 // long. When arguments are vector<unsigned long, N> and vector<long long, N>,
868 // the long long has higher rank than long even though they are the same size.
869
870 // If this is a compound assignment cast the right hand side to the left hand
871 // side's type.
872 if (IsCompAssign)
873 return castElement<CK_IntegralCast>(S&: SemaRef, E&: RHS, Ty: LHSType);
874
875 // If this isn't a compound assignment we convert to unsigned long long.
876 QualType ElTy = Ctx.getCorrespondingUnsignedType(T: LHSSigned ? LElTy : RElTy);
877 QualType NewTy = Ctx.getExtVectorType(
878 VectorType: ElTy, NumElts: RHSType->castAs<VectorType>()->getNumElements());
879 (void)castElement<CK_IntegralCast>(S&: SemaRef, E&: RHS, Ty: NewTy);
880
881 return castElement<CK_IntegralCast>(S&: SemaRef, E&: LHS, Ty: NewTy);
882}
883
884static CastKind getScalarCastKind(ASTContext &Ctx, QualType DestTy,
885 QualType SrcTy) {
886 if (DestTy->isRealFloatingType() && SrcTy->isRealFloatingType())
887 return CK_FloatingCast;
888 if (DestTy->isIntegralType(Ctx) && SrcTy->isIntegralType(Ctx))
889 return CK_IntegralCast;
890 if (DestTy->isRealFloatingType())
891 return CK_IntegralToFloating;
892 assert(SrcTy->isRealFloatingType() && DestTy->isIntegralType(Ctx));
893 return CK_FloatingToIntegral;
894}
895
896QualType SemaHLSL::handleVectorBinOpConversion(ExprResult &LHS, ExprResult &RHS,
897 QualType LHSType,
898 QualType RHSType,
899 bool IsCompAssign) {
900 const auto *LVecTy = LHSType->getAs<VectorType>();
901 const auto *RVecTy = RHSType->getAs<VectorType>();
902 auto &Ctx = getASTContext();
903
904 // If the LHS is not a vector and this is a compound assignment, we truncate
905 // the argument to a scalar then convert it to the LHS's type.
906 if (!LVecTy && IsCompAssign) {
907 QualType RElTy = RHSType->castAs<VectorType>()->getElementType();
908 RHS = SemaRef.ImpCastExprToType(E: RHS.get(), Type: RElTy, CK: CK_HLSLVectorTruncation);
909 RHSType = RHS.get()->getType();
910 if (Ctx.hasSameUnqualifiedType(T1: LHSType, T2: RHSType))
911 return LHSType;
912 RHS = SemaRef.ImpCastExprToType(E: RHS.get(), Type: LHSType,
913 CK: getScalarCastKind(Ctx, DestTy: LHSType, SrcTy: RHSType));
914 return LHSType;
915 }
916
917 unsigned EndSz = std::numeric_limits<unsigned>::max();
918 unsigned LSz = 0;
919 if (LVecTy)
920 LSz = EndSz = LVecTy->getNumElements();
921 if (RVecTy)
922 EndSz = std::min(a: RVecTy->getNumElements(), b: EndSz);
923 assert(EndSz != std::numeric_limits<unsigned>::max() &&
924 "one of the above should have had a value");
925
926 // In a compound assignment, the left operand does not change type, the right
927 // operand is converted to the type of the left operand.
928 if (IsCompAssign && LSz != EndSz) {
929 Diag(LHS.get()->getBeginLoc(),
930 diag::err_hlsl_vector_compound_assignment_truncation)
931 << LHSType << RHSType;
932 return QualType();
933 }
934
935 if (RVecTy && RVecTy->getNumElements() > EndSz)
936 castVector<CK_HLSLVectorTruncation>(S&: SemaRef, E&: RHS, Ty&: RHSType, Sz: EndSz);
937 if (!IsCompAssign && LVecTy && LVecTy->getNumElements() > EndSz)
938 castVector<CK_HLSLVectorTruncation>(S&: SemaRef, E&: LHS, Ty&: LHSType, Sz: EndSz);
939
940 if (!RVecTy)
941 castVector<CK_VectorSplat>(S&: SemaRef, E&: RHS, Ty&: RHSType, Sz: EndSz);
942 if (!IsCompAssign && !LVecTy)
943 castVector<CK_VectorSplat>(S&: SemaRef, E&: LHS, Ty&: LHSType, Sz: EndSz);
944
945 // If we're at the same type after resizing we can stop here.
946 if (Ctx.hasSameUnqualifiedType(T1: LHSType, T2: RHSType))
947 return Ctx.getCommonSugaredType(X: LHSType, Y: RHSType);
948
949 QualType LElTy = LHSType->castAs<VectorType>()->getElementType();
950 QualType RElTy = RHSType->castAs<VectorType>()->getElementType();
951
952 // Handle conversion for floating point vectors.
953 if (LElTy->isRealFloatingType() || RElTy->isRealFloatingType())
954 return handleFloatVectorBinOpConversion(SemaRef, LHS, RHS, LHSType, RHSType,
955 LElTy, RElTy, IsCompAssign);
956
957 assert(LElTy->isIntegralType(Ctx) && RElTy->isIntegralType(Ctx) &&
958 "HLSL Vectors can only contain integer or floating point types");
959 return handleIntegerVectorBinOpConversion(SemaRef, LHS, RHS, LHSType, RHSType,
960 LElTy, RElTy, IsCompAssign);
961}
962
963void SemaHLSL::emitLogicalOperatorFixIt(Expr *LHS, Expr *RHS,
964 BinaryOperatorKind Opc) {
965 assert((Opc == BO_LOr || Opc == BO_LAnd) &&
966 "Called with non-logical operator");
967 llvm::SmallVector<char, 256> Buff;
968 llvm::raw_svector_ostream OS(Buff);
969 PrintingPolicy PP(SemaRef.getLangOpts());
970 StringRef NewFnName = Opc == BO_LOr ? "or" : "and";
971 OS << NewFnName << "(";
972 LHS->printPretty(OS, nullptr, PP);
973 OS << ", ";
974 RHS->printPretty(OS, nullptr, PP);
975 OS << ")";
976 SourceRange FullRange = SourceRange(LHS->getBeginLoc(), RHS->getEndLoc());
977 SemaRef.Diag(LHS->getBeginLoc(), diag::note_function_suggestion)
978 << NewFnName << FixItHint::CreateReplacement(FullRange, OS.str());
979}
980
981void SemaHLSL::handleRootSignatureAttr(Decl *D, const ParsedAttr &AL) {
982 if (AL.getNumArgs() != 1) {
983 Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1;
984 return;
985 }
986
987 IdentifierInfo *Ident = AL.getArgAsIdent(Arg: 0)->getIdentifierInfo();
988 if (auto *RS = D->getAttr<RootSignatureAttr>()) {
989 if (RS->getSignatureIdent() != Ident) {
990 Diag(AL.getLoc(), diag::err_disallowed_duplicate_attribute) << RS;
991 return;
992 }
993
994 Diag(AL.getLoc(), diag::warn_duplicate_attribute_exact) << RS;
995 return;
996 }
997
998 LookupResult R(SemaRef, Ident, SourceLocation(), Sema::LookupOrdinaryName);
999 if (SemaRef.LookupQualifiedName(R, LookupCtx: D->getDeclContext()))
1000 if (auto *SignatureDecl =
1001 dyn_cast<HLSLRootSignatureDecl>(Val: R.getFoundDecl())) {
1002 // Perform validation of constructs here
1003 D->addAttr(::new (getASTContext()) RootSignatureAttr(
1004 getASTContext(), AL, Ident, SignatureDecl));
1005 }
1006}
1007
1008void SemaHLSL::handleNumThreadsAttr(Decl *D, const ParsedAttr &AL) {
1009 llvm::VersionTuple SMVersion =
1010 getASTContext().getTargetInfo().getTriple().getOSVersion();
1011 uint32_t ZMax = 1024;
1012 uint32_t ThreadMax = 1024;
1013 if (SMVersion.getMajor() <= 4) {
1014 ZMax = 1;
1015 ThreadMax = 768;
1016 } else if (SMVersion.getMajor() == 5) {
1017 ZMax = 64;
1018 ThreadMax = 1024;
1019 }
1020
1021 uint32_t X;
1022 if (!SemaRef.checkUInt32Argument(AI: AL, Expr: AL.getArgAsExpr(Arg: 0), Val&: X))
1023 return;
1024 if (X > 1024) {
1025 Diag(AL.getArgAsExpr(0)->getExprLoc(),
1026 diag::err_hlsl_numthreads_argument_oor)
1027 << 0 << 1024;
1028 return;
1029 }
1030 uint32_t Y;
1031 if (!SemaRef.checkUInt32Argument(AI: AL, Expr: AL.getArgAsExpr(Arg: 1), Val&: Y))
1032 return;
1033 if (Y > 1024) {
1034 Diag(AL.getArgAsExpr(1)->getExprLoc(),
1035 diag::err_hlsl_numthreads_argument_oor)
1036 << 1 << 1024;
1037 return;
1038 }
1039 uint32_t Z;
1040 if (!SemaRef.checkUInt32Argument(AI: AL, Expr: AL.getArgAsExpr(Arg: 2), Val&: Z))
1041 return;
1042 if (Z > ZMax) {
1043 SemaRef.Diag(AL.getArgAsExpr(2)->getExprLoc(),
1044 diag::err_hlsl_numthreads_argument_oor)
1045 << 2 << ZMax;
1046 return;
1047 }
1048
1049 if (X * Y * Z > ThreadMax) {
1050 Diag(AL.getLoc(), diag::err_hlsl_numthreads_invalid) << ThreadMax;
1051 return;
1052 }
1053
1054 HLSLNumThreadsAttr *NewAttr = mergeNumThreadsAttr(D, AL, X, Y, Z);
1055 if (NewAttr)
1056 D->addAttr(A: NewAttr);
1057}
1058
1059static bool isValidWaveSizeValue(unsigned Value) {
1060 return llvm::isPowerOf2_32(Value) && Value >= 4 && Value <= 128;
1061}
1062
1063void SemaHLSL::handleWaveSizeAttr(Decl *D, const ParsedAttr &AL) {
1064 // validate that the wavesize argument is a power of 2 between 4 and 128
1065 // inclusive
1066 unsigned SpelledArgsCount = AL.getNumArgs();
1067 if (SpelledArgsCount == 0 || SpelledArgsCount > 3)
1068 return;
1069
1070 uint32_t Min;
1071 if (!SemaRef.checkUInt32Argument(AI: AL, Expr: AL.getArgAsExpr(Arg: 0), Val&: Min))
1072 return;
1073
1074 uint32_t Max = 0;
1075 if (SpelledArgsCount > 1 &&
1076 !SemaRef.checkUInt32Argument(AI: AL, Expr: AL.getArgAsExpr(Arg: 1), Val&: Max))
1077 return;
1078
1079 uint32_t Preferred = 0;
1080 if (SpelledArgsCount > 2 &&
1081 !SemaRef.checkUInt32Argument(AI: AL, Expr: AL.getArgAsExpr(Arg: 2), Val&: Preferred))
1082 return;
1083
1084 if (SpelledArgsCount > 2) {
1085 if (!isValidWaveSizeValue(Value: Preferred)) {
1086 Diag(AL.getArgAsExpr(2)->getExprLoc(),
1087 diag::err_attribute_power_of_two_in_range)
1088 << AL << llvm::dxil::MinWaveSize << llvm::dxil::MaxWaveSize
1089 << Preferred;
1090 return;
1091 }
1092 // Preferred not in range.
1093 if (Preferred < Min || Preferred > Max) {
1094 Diag(AL.getArgAsExpr(2)->getExprLoc(),
1095 diag::err_attribute_power_of_two_in_range)
1096 << AL << Min << Max << Preferred;
1097 return;
1098 }
1099 } else if (SpelledArgsCount > 1) {
1100 if (!isValidWaveSizeValue(Value: Max)) {
1101 Diag(AL.getArgAsExpr(1)->getExprLoc(),
1102 diag::err_attribute_power_of_two_in_range)
1103 << AL << llvm::dxil::MinWaveSize << llvm::dxil::MaxWaveSize << Max;
1104 return;
1105 }
1106 if (Max < Min) {
1107 Diag(AL.getLoc(), diag::err_attribute_argument_invalid) << AL << 1;
1108 return;
1109 } else if (Max == Min) {
1110 Diag(AL.getLoc(), diag::warn_attr_min_eq_max) << AL;
1111 }
1112 } else {
1113 if (!isValidWaveSizeValue(Value: Min)) {
1114 Diag(AL.getArgAsExpr(0)->getExprLoc(),
1115 diag::err_attribute_power_of_two_in_range)
1116 << AL << llvm::dxil::MinWaveSize << llvm::dxil::MaxWaveSize << Min;
1117 return;
1118 }
1119 }
1120
1121 HLSLWaveSizeAttr *NewAttr =
1122 mergeWaveSizeAttr(D, AL, Min, Max, Preferred, SpelledArgsCount);
1123 if (NewAttr)
1124 D->addAttr(A: NewAttr);
1125}
1126
1127void SemaHLSL::handleVkExtBuiltinInputAttr(Decl *D, const ParsedAttr &AL) {
1128 uint32_t ID;
1129 if (!SemaRef.checkUInt32Argument(AI: AL, Expr: AL.getArgAsExpr(Arg: 0), Val&: ID))
1130 return;
1131 D->addAttr(::new (getASTContext())
1132 HLSLVkExtBuiltinInputAttr(getASTContext(), AL, ID));
1133}
1134
1135bool SemaHLSL::diagnoseInputIDType(QualType T, const ParsedAttr &AL) {
1136 const auto *VT = T->getAs<VectorType>();
1137
1138 if (!T->hasUnsignedIntegerRepresentation() ||
1139 (VT && VT->getNumElements() > 3)) {
1140 Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type)
1141 << AL << "uint/uint2/uint3";
1142 return false;
1143 }
1144
1145 return true;
1146}
1147
1148void SemaHLSL::handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL) {
1149 auto *VD = cast<ValueDecl>(Val: D);
1150 if (!diagnoseInputIDType(T: VD->getType(), AL))
1151 return;
1152
1153 D->addAttr(::new (getASTContext())
1154 HLSLSV_DispatchThreadIDAttr(getASTContext(), AL));
1155}
1156
1157bool SemaHLSL::diagnosePositionType(QualType T, const ParsedAttr &AL) {
1158 const auto *VT = T->getAs<VectorType>();
1159
1160 if (!T->hasFloatingRepresentation() || (VT && VT->getNumElements() > 4)) {
1161 Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type)
1162 << AL << "float/float1/float2/float3/float4";
1163 return false;
1164 }
1165
1166 return true;
1167}
1168
1169void SemaHLSL::handleSV_PositionAttr(Decl *D, const ParsedAttr &AL) {
1170 auto *VD = cast<ValueDecl>(Val: D);
1171 if (!diagnosePositionType(T: VD->getType(), AL))
1172 return;
1173
1174 D->addAttr(::new (getASTContext()) HLSLSV_PositionAttr(getASTContext(), AL));
1175}
1176
1177void SemaHLSL::handleSV_GroupThreadIDAttr(Decl *D, const ParsedAttr &AL) {
1178 auto *VD = cast<ValueDecl>(Val: D);
1179 if (!diagnoseInputIDType(T: VD->getType(), AL))
1180 return;
1181
1182 D->addAttr(::new (getASTContext())
1183 HLSLSV_GroupThreadIDAttr(getASTContext(), AL));
1184}
1185
1186void SemaHLSL::handleSV_GroupIDAttr(Decl *D, const ParsedAttr &AL) {
1187 auto *VD = cast<ValueDecl>(Val: D);
1188 if (!diagnoseInputIDType(T: VD->getType(), AL))
1189 return;
1190
1191 D->addAttr(::new (getASTContext()) HLSLSV_GroupIDAttr(getASTContext(), AL));
1192}
1193
1194void SemaHLSL::handlePackOffsetAttr(Decl *D, const ParsedAttr &AL) {
1195 if (!isa<VarDecl>(Val: D) || !isa<HLSLBufferDecl>(Val: D->getDeclContext())) {
1196 Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_ast_node)
1197 << AL << "shader constant in a constant buffer";
1198 return;
1199 }
1200
1201 uint32_t SubComponent;
1202 if (!SemaRef.checkUInt32Argument(AI: AL, Expr: AL.getArgAsExpr(Arg: 0), Val&: SubComponent))
1203 return;
1204 uint32_t Component;
1205 if (!SemaRef.checkUInt32Argument(AI: AL, Expr: AL.getArgAsExpr(Arg: 1), Val&: Component))
1206 return;
1207
1208 QualType T = cast<VarDecl>(Val: D)->getType().getCanonicalType();
1209 // Check if T is an array or struct type.
1210 // TODO: mark matrix type as aggregate type.
1211 bool IsAggregateTy = (T->isArrayType() || T->isStructureType());
1212
1213 // Check Component is valid for T.
1214 if (Component) {
1215 unsigned Size = getASTContext().getTypeSize(T);
1216 if (IsAggregateTy || Size > 128) {
1217 Diag(AL.getLoc(), diag::err_hlsl_packoffset_cross_reg_boundary);
1218 return;
1219 } else {
1220 // Make sure Component + sizeof(T) <= 4.
1221 if ((Component * 32 + Size) > 128) {
1222 Diag(AL.getLoc(), diag::err_hlsl_packoffset_cross_reg_boundary);
1223 return;
1224 }
1225 QualType EltTy = T;
1226 if (const auto *VT = T->getAs<VectorType>())
1227 EltTy = VT->getElementType();
1228 unsigned Align = getASTContext().getTypeAlign(T: EltTy);
1229 if (Align > 32 && Component == 1) {
1230 // NOTE: Component 3 will hit err_hlsl_packoffset_cross_reg_boundary.
1231 // So we only need to check Component 1 here.
1232 Diag(AL.getLoc(), diag::err_hlsl_packoffset_alignment_mismatch)
1233 << Align << EltTy;
1234 return;
1235 }
1236 }
1237 }
1238
1239 D->addAttr(::new (getASTContext()) HLSLPackOffsetAttr(
1240 getASTContext(), AL, SubComponent, Component));
1241}
1242
1243void SemaHLSL::handleShaderAttr(Decl *D, const ParsedAttr &AL) {
1244 StringRef Str;
1245 SourceLocation ArgLoc;
1246 if (!SemaRef.checkStringLiteralArgumentAttr(Attr: AL, ArgNum: 0, Str, ArgLocation: &ArgLoc))
1247 return;
1248
1249 llvm::Triple::EnvironmentType ShaderType;
1250 if (!HLSLShaderAttr::ConvertStrToEnvironmentType(Str, ShaderType)) {
1251 Diag(AL.getLoc(), diag::warn_attribute_type_not_supported)
1252 << AL << Str << ArgLoc;
1253 return;
1254 }
1255
1256 // FIXME: check function match the shader stage.
1257
1258 HLSLShaderAttr *NewAttr = mergeShaderAttr(D, AL, ShaderType);
1259 if (NewAttr)
1260 D->addAttr(A: NewAttr);
1261}
1262
1263bool clang::CreateHLSLAttributedResourceType(
1264 Sema &S, QualType Wrapped, ArrayRef<const Attr *> AttrList,
1265 QualType &ResType, HLSLAttributedResourceLocInfo *LocInfo) {
1266 assert(AttrList.size() && "expected list of resource attributes");
1267
1268 QualType ContainedTy = QualType();
1269 TypeSourceInfo *ContainedTyInfo = nullptr;
1270 SourceLocation LocBegin = AttrList[0]->getRange().getBegin();
1271 SourceLocation LocEnd = AttrList[0]->getRange().getEnd();
1272
1273 HLSLAttributedResourceType::Attributes ResAttrs;
1274
1275 bool HasResourceClass = false;
1276 for (const Attr *A : AttrList) {
1277 if (!A)
1278 continue;
1279 LocEnd = A->getRange().getEnd();
1280 switch (A->getKind()) {
1281 case attr::HLSLResourceClass: {
1282 ResourceClass RC = cast<HLSLResourceClassAttr>(A)->getResourceClass();
1283 if (HasResourceClass) {
1284 S.Diag(A->getLocation(), ResAttrs.ResourceClass == RC
1285 ? diag::warn_duplicate_attribute_exact
1286 : diag::warn_duplicate_attribute)
1287 << A;
1288 return false;
1289 }
1290 ResAttrs.ResourceClass = RC;
1291 HasResourceClass = true;
1292 break;
1293 }
1294 case attr::HLSLROV:
1295 if (ResAttrs.IsROV) {
1296 S.Diag(A->getLocation(), diag::warn_duplicate_attribute_exact) << A;
1297 return false;
1298 }
1299 ResAttrs.IsROV = true;
1300 break;
1301 case attr::HLSLRawBuffer:
1302 if (ResAttrs.RawBuffer) {
1303 S.Diag(A->getLocation(), diag::warn_duplicate_attribute_exact) << A;
1304 return false;
1305 }
1306 ResAttrs.RawBuffer = true;
1307 break;
1308 case attr::HLSLContainedType: {
1309 const HLSLContainedTypeAttr *CTAttr = cast<HLSLContainedTypeAttr>(A);
1310 QualType Ty = CTAttr->getType();
1311 if (!ContainedTy.isNull()) {
1312 S.Diag(A->getLocation(), ContainedTy == Ty
1313 ? diag::warn_duplicate_attribute_exact
1314 : diag::warn_duplicate_attribute)
1315 << A;
1316 return false;
1317 }
1318 ContainedTy = Ty;
1319 ContainedTyInfo = CTAttr->getTypeLoc();
1320 break;
1321 }
1322 default:
1323 llvm_unreachable("unhandled resource attribute type");
1324 }
1325 }
1326
1327 if (!HasResourceClass) {
1328 S.Diag(AttrList.back()->getRange().getEnd(),
1329 diag::err_hlsl_missing_resource_class);
1330 return false;
1331 }
1332
1333 ResType = S.getASTContext().getHLSLAttributedResourceType(
1334 Wrapped, Contained: ContainedTy, Attrs: ResAttrs);
1335
1336 if (LocInfo && ContainedTyInfo) {
1337 LocInfo->Range = SourceRange(LocBegin, LocEnd);
1338 LocInfo->ContainedTyInfo = ContainedTyInfo;
1339 }
1340 return true;
1341}
1342
1343// Validates and creates an HLSL attribute that is applied as type attribute on
1344// HLSL resource. The attributes are collected in HLSLResourcesTypeAttrs and at
1345// the end of the declaration they are applied to the declaration type by
1346// wrapping it in HLSLAttributedResourceType.
1347bool SemaHLSL::handleResourceTypeAttr(QualType T, const ParsedAttr &AL) {
1348 // only allow resource type attributes on intangible types
1349 if (!T->isHLSLResourceType()) {
1350 Diag(AL.getLoc(), diag::err_hlsl_attribute_needs_intangible_type)
1351 << AL << getASTContext().HLSLResourceTy;
1352 return false;
1353 }
1354
1355 // validate number of arguments
1356 if (!AL.checkExactlyNumArgs(S&: SemaRef, Num: AL.getMinArgs()))
1357 return false;
1358
1359 Attr *A = nullptr;
1360 switch (AL.getKind()) {
1361 case ParsedAttr::AT_HLSLResourceClass: {
1362 if (!AL.isArgIdent(Arg: 0)) {
1363 Diag(AL.getLoc(), diag::err_attribute_argument_type)
1364 << AL << AANT_ArgumentIdentifier;
1365 return false;
1366 }
1367
1368 IdentifierLoc *Loc = AL.getArgAsIdent(Arg: 0);
1369 StringRef Identifier = Loc->getIdentifierInfo()->getName();
1370 SourceLocation ArgLoc = Loc->getLoc();
1371
1372 // Validate resource class value
1373 ResourceClass RC;
1374 if (!HLSLResourceClassAttr::ConvertStrToResourceClass(Identifier, RC)) {
1375 Diag(ArgLoc, diag::warn_attribute_type_not_supported)
1376 << "ResourceClass" << Identifier;
1377 return false;
1378 }
1379 A = HLSLResourceClassAttr::Create(getASTContext(), RC, AL.getLoc());
1380 break;
1381 }
1382
1383 case ParsedAttr::AT_HLSLROV:
1384 A = HLSLROVAttr::Create(getASTContext(), AL.getLoc());
1385 break;
1386
1387 case ParsedAttr::AT_HLSLRawBuffer:
1388 A = HLSLRawBufferAttr::Create(getASTContext(), AL.getLoc());
1389 break;
1390
1391 case ParsedAttr::AT_HLSLContainedType: {
1392 if (AL.getNumArgs() != 1 && !AL.hasParsedType()) {
1393 Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1;
1394 return false;
1395 }
1396
1397 TypeSourceInfo *TSI = nullptr;
1398 QualType QT = SemaRef.GetTypeFromParser(Ty: AL.getTypeArg(), TInfo: &TSI);
1399 assert(TSI && "no type source info for attribute argument");
1400 if (SemaRef.RequireCompleteType(TSI->getTypeLoc().getBeginLoc(), QT,
1401 diag::err_incomplete_type))
1402 return false;
1403 A = HLSLContainedTypeAttr::Create(getASTContext(), TSI, AL.getLoc());
1404 break;
1405 }
1406
1407 default:
1408 llvm_unreachable("unhandled HLSL attribute");
1409 }
1410
1411 HLSLResourcesTypeAttrs.emplace_back(Args&: A);
1412 return true;
1413}
1414
1415// Combines all resource type attributes and creates HLSLAttributedResourceType.
1416QualType SemaHLSL::ProcessResourceTypeAttributes(QualType CurrentType) {
1417 if (!HLSLResourcesTypeAttrs.size())
1418 return CurrentType;
1419
1420 QualType QT = CurrentType;
1421 HLSLAttributedResourceLocInfo LocInfo;
1422 if (CreateHLSLAttributedResourceType(S&: SemaRef, Wrapped: CurrentType,
1423 AttrList: HLSLResourcesTypeAttrs, ResType&: QT, LocInfo: &LocInfo)) {
1424 const HLSLAttributedResourceType *RT =
1425 cast<HLSLAttributedResourceType>(Val: QT.getTypePtr());
1426
1427 // Temporarily store TypeLoc information for the new type.
1428 // It will be transferred to HLSLAttributesResourceTypeLoc
1429 // shortly after the type is created by TypeSpecLocFiller which
1430 // will call the TakeLocForHLSLAttribute method below.
1431 LocsForHLSLAttributedResources.insert(KV: std::pair(RT, LocInfo));
1432 }
1433 HLSLResourcesTypeAttrs.clear();
1434 return QT;
1435}
1436
1437// Returns source location for the HLSLAttributedResourceType
1438HLSLAttributedResourceLocInfo
1439SemaHLSL::TakeLocForHLSLAttribute(const HLSLAttributedResourceType *RT) {
1440 HLSLAttributedResourceLocInfo LocInfo = {};
1441 auto I = LocsForHLSLAttributedResources.find(Val: RT);
1442 if (I != LocsForHLSLAttributedResources.end()) {
1443 LocInfo = I->second;
1444 LocsForHLSLAttributedResources.erase(I);
1445 return LocInfo;
1446 }
1447 LocInfo.Range = SourceRange();
1448 return LocInfo;
1449}
1450
1451// Walks though the global variable declaration, collects all resource binding
1452// requirements and adds them to Bindings
1453void SemaHLSL::collectResourceBindingsOnUserRecordDecl(const VarDecl *VD,
1454 const RecordType *RT) {
1455 const RecordDecl *RD = RT->getDecl();
1456 for (FieldDecl *FD : RD->fields()) {
1457 const Type *Ty = FD->getType()->getUnqualifiedDesugaredType();
1458
1459 // Unwrap arrays
1460 // FIXME: Calculate array size while unwrapping
1461 assert(!Ty->isIncompleteArrayType() &&
1462 "incomplete arrays inside user defined types are not supported");
1463 while (Ty->isConstantArrayType()) {
1464 const ConstantArrayType *CAT = cast<ConstantArrayType>(Val: Ty);
1465 Ty = CAT->getElementType()->getUnqualifiedDesugaredType();
1466 }
1467
1468 if (!Ty->isRecordType())
1469 continue;
1470
1471 if (const HLSLAttributedResourceType *AttrResType =
1472 HLSLAttributedResourceType::findHandleTypeOnResource(RT: Ty)) {
1473 // Add a new DeclBindingInfo to Bindings if it does not already exist
1474 ResourceClass RC = AttrResType->getAttrs().ResourceClass;
1475 DeclBindingInfo *DBI = Bindings.getDeclBindingInfo(VD, ResClass: RC);
1476 if (!DBI)
1477 Bindings.addDeclBindingInfo(VD, ResClass: RC);
1478 } else if (const RecordType *RT = dyn_cast<RecordType>(Val: Ty)) {
1479 // Recursively scan embedded struct or class; it would be nice to do this
1480 // without recursion, but tricky to correctly calculate the size of the
1481 // binding, which is something we are probably going to need to do later
1482 // on. Hopefully nesting of structs in structs too many levels is
1483 // unlikely.
1484 collectResourceBindingsOnUserRecordDecl(VD, RT);
1485 }
1486 }
1487}
1488
1489// Diagnose localized register binding errors for a single binding; does not
1490// diagnose resource binding on user record types, that will be done later
1491// in processResourceBindingOnDecl based on the information collected in
1492// collectResourceBindingsOnVarDecl.
1493// Returns false if the register binding is not valid.
1494static bool DiagnoseLocalRegisterBinding(Sema &S, SourceLocation &ArgLoc,
1495 Decl *D, RegisterType RegType,
1496 bool SpecifiedSpace) {
1497 int RegTypeNum = static_cast<int>(RegType);
1498
1499 // check if the decl type is groupshared
1500 if (D->hasAttr<HLSLGroupSharedAddressSpaceAttr>()) {
1501 S.Diag(ArgLoc, diag::err_hlsl_binding_type_mismatch) << RegTypeNum;
1502 return false;
1503 }
1504
1505 // Cbuffers and Tbuffers are HLSLBufferDecl types
1506 if (HLSLBufferDecl *CBufferOrTBuffer = dyn_cast<HLSLBufferDecl>(Val: D)) {
1507 ResourceClass RC = CBufferOrTBuffer->isCBuffer() ? ResourceClass::CBuffer
1508 : ResourceClass::SRV;
1509 if (RegType == getRegisterType(RC))
1510 return true;
1511
1512 S.Diag(D->getLocation(), diag::err_hlsl_binding_type_mismatch)
1513 << RegTypeNum;
1514 return false;
1515 }
1516
1517 // Samplers, UAVs, and SRVs are VarDecl types
1518 assert(isa<VarDecl>(D) && "D is expected to be VarDecl or HLSLBufferDecl");
1519 VarDecl *VD = cast<VarDecl>(Val: D);
1520
1521 // Resource
1522 if (const HLSLAttributedResourceType *AttrResType =
1523 HLSLAttributedResourceType::findHandleTypeOnResource(
1524 RT: VD->getType().getTypePtr())) {
1525 if (RegType == getRegisterType(AttrResType->getAttrs().ResourceClass))
1526 return true;
1527
1528 S.Diag(D->getLocation(), diag::err_hlsl_binding_type_mismatch)
1529 << RegTypeNum;
1530 return false;
1531 }
1532
1533 const clang::Type *Ty = VD->getType().getTypePtr();
1534 while (Ty->isArrayType())
1535 Ty = Ty->getArrayElementTypeNoTypeQual();
1536
1537 // Basic types
1538 if (Ty->isArithmeticType() || Ty->isVectorType()) {
1539 bool DeclaredInCOrTBuffer = isa<HLSLBufferDecl>(Val: D->getDeclContext());
1540 if (SpecifiedSpace && !DeclaredInCOrTBuffer)
1541 S.Diag(ArgLoc, diag::err_hlsl_space_on_global_constant);
1542
1543 if (!DeclaredInCOrTBuffer && (Ty->isIntegralType(Ctx: S.getASTContext()) ||
1544 Ty->isFloatingType() || Ty->isVectorType())) {
1545 // Register annotation on default constant buffer declaration ($Globals)
1546 if (RegType == RegisterType::CBuffer)
1547 S.Diag(ArgLoc, diag::warn_hlsl_deprecated_register_type_b);
1548 else if (RegType != RegisterType::C)
1549 S.Diag(ArgLoc, diag::err_hlsl_binding_type_mismatch) << RegTypeNum;
1550 else
1551 return true;
1552 } else {
1553 if (RegType == RegisterType::C)
1554 S.Diag(ArgLoc, diag::warn_hlsl_register_type_c_packoffset);
1555 else
1556 S.Diag(ArgLoc, diag::err_hlsl_binding_type_mismatch) << RegTypeNum;
1557 }
1558 return false;
1559 }
1560 if (Ty->isRecordType())
1561 // RecordTypes will be diagnosed in processResourceBindingOnDecl
1562 // that is called from ActOnVariableDeclarator
1563 return true;
1564
1565 // Anything else is an error
1566 S.Diag(ArgLoc, diag::err_hlsl_binding_type_mismatch) << RegTypeNum;
1567 return false;
1568}
1569
1570static bool ValidateMultipleRegisterAnnotations(Sema &S, Decl *TheDecl,
1571 RegisterType regType) {
1572 // make sure that there are no two register annotations
1573 // applied to the decl with the same register type
1574 bool RegisterTypesDetected[5] = {false};
1575 RegisterTypesDetected[static_cast<int>(regType)] = true;
1576
1577 for (auto it = TheDecl->attr_begin(); it != TheDecl->attr_end(); ++it) {
1578 if (HLSLResourceBindingAttr *attr =
1579 dyn_cast<HLSLResourceBindingAttr>(*it)) {
1580
1581 RegisterType otherRegType = attr->getRegisterType();
1582 if (RegisterTypesDetected[static_cast<int>(otherRegType)]) {
1583 int otherRegTypeNum = static_cast<int>(otherRegType);
1584 S.Diag(TheDecl->getLocation(),
1585 diag::err_hlsl_duplicate_register_annotation)
1586 << otherRegTypeNum;
1587 return false;
1588 }
1589 RegisterTypesDetected[static_cast<int>(otherRegType)] = true;
1590 }
1591 }
1592 return true;
1593}
1594
1595static bool DiagnoseHLSLRegisterAttribute(Sema &S, SourceLocation &ArgLoc,
1596 Decl *D, RegisterType RegType,
1597 bool SpecifiedSpace) {
1598
1599 // exactly one of these two types should be set
1600 assert(((isa<VarDecl>(D) && !isa<HLSLBufferDecl>(D)) ||
1601 (!isa<VarDecl>(D) && isa<HLSLBufferDecl>(D))) &&
1602 "expecting VarDecl or HLSLBufferDecl");
1603
1604 // check if the declaration contains resource matching the register type
1605 if (!DiagnoseLocalRegisterBinding(S, ArgLoc, D, RegType, SpecifiedSpace))
1606 return false;
1607
1608 // next, if multiple register annotations exist, check that none conflict.
1609 return ValidateMultipleRegisterAnnotations(S, D, RegType);
1610}
1611
1612void SemaHLSL::handleResourceBindingAttr(Decl *TheDecl, const ParsedAttr &AL) {
1613 if (isa<VarDecl>(Val: TheDecl)) {
1614 if (SemaRef.RequireCompleteType(TheDecl->getBeginLoc(),
1615 cast<ValueDecl>(TheDecl)->getType(),
1616 diag::err_incomplete_type))
1617 return;
1618 }
1619
1620 StringRef Slot = "";
1621 StringRef Space = "";
1622 SourceLocation SlotLoc, SpaceLoc;
1623
1624 if (!AL.isArgIdent(Arg: 0)) {
1625 Diag(AL.getLoc(), diag::err_attribute_argument_type)
1626 << AL << AANT_ArgumentIdentifier;
1627 return;
1628 }
1629 IdentifierLoc *Loc = AL.getArgAsIdent(Arg: 0);
1630
1631 if (AL.getNumArgs() == 2) {
1632 Slot = Loc->getIdentifierInfo()->getName();
1633 SlotLoc = Loc->getLoc();
1634 if (!AL.isArgIdent(Arg: 1)) {
1635 Diag(AL.getLoc(), diag::err_attribute_argument_type)
1636 << AL << AANT_ArgumentIdentifier;
1637 return;
1638 }
1639 Loc = AL.getArgAsIdent(Arg: 1);
1640 Space = Loc->getIdentifierInfo()->getName();
1641 SpaceLoc = Loc->getLoc();
1642 } else {
1643 StringRef Str = Loc->getIdentifierInfo()->getName();
1644 if (Str.starts_with(Prefix: "space")) {
1645 Space = Str;
1646 SpaceLoc = Loc->getLoc();
1647 } else {
1648 Slot = Str;
1649 SlotLoc = Loc->getLoc();
1650 Space = "space0";
1651 }
1652 }
1653
1654 RegisterType RegType = RegisterType::SRV;
1655 std::optional<unsigned> SlotNum;
1656 unsigned SpaceNum = 0;
1657
1658 // Validate slot
1659 if (!Slot.empty()) {
1660 if (!convertToRegisterType(Slot, &RegType)) {
1661 Diag(SlotLoc, diag::err_hlsl_binding_type_invalid) << Slot.substr(0, 1);
1662 return;
1663 }
1664 if (RegType == RegisterType::I) {
1665 Diag(SlotLoc, diag::warn_hlsl_deprecated_register_type_i);
1666 return;
1667 }
1668 StringRef SlotNumStr = Slot.substr(Start: 1);
1669 unsigned N;
1670 if (SlotNumStr.getAsInteger(Radix: 10, Result&: N)) {
1671 Diag(SlotLoc, diag::err_hlsl_unsupported_register_number);
1672 return;
1673 }
1674 SlotNum = N;
1675 }
1676
1677 // Validate space
1678 if (!Space.starts_with(Prefix: "space")) {
1679 Diag(SpaceLoc, diag::err_hlsl_expected_space) << Space;
1680 return;
1681 }
1682 StringRef SpaceNumStr = Space.substr(Start: 5);
1683 if (SpaceNumStr.getAsInteger(Radix: 10, Result&: SpaceNum)) {
1684 Diag(SpaceLoc, diag::err_hlsl_expected_space) << Space;
1685 return;
1686 }
1687
1688 // If we have slot, diagnose it is the right register type for the decl
1689 if (SlotNum.has_value())
1690 if (!DiagnoseHLSLRegisterAttribute(SemaRef, SlotLoc, TheDecl, RegType,
1691 !SpaceLoc.isInvalid()))
1692 return;
1693
1694 HLSLResourceBindingAttr *NewAttr =
1695 HLSLResourceBindingAttr::Create(getASTContext(), Slot, Space, AL);
1696 if (NewAttr) {
1697 NewAttr->setBinding(RegType, SlotNum, SpaceNum);
1698 TheDecl->addAttr(A: NewAttr);
1699 }
1700}
1701
1702void SemaHLSL::handleParamModifierAttr(Decl *D, const ParsedAttr &AL) {
1703 HLSLParamModifierAttr *NewAttr = mergeParamModifierAttr(
1704 D, AL,
1705 static_cast<HLSLParamModifierAttr::Spelling>(AL.getSemanticSpelling()));
1706 if (NewAttr)
1707 D->addAttr(A: NewAttr);
1708}
1709
1710namespace {
1711
1712/// This class implements HLSL availability diagnostics for default
1713/// and relaxed mode
1714///
1715/// The goal of this diagnostic is to emit an error or warning when an
1716/// unavailable API is found in code that is reachable from the shader
1717/// entry function or from an exported function (when compiling a shader
1718/// library).
1719///
1720/// This is done by traversing the AST of all shader entry point functions
1721/// and of all exported functions, and any functions that are referenced
1722/// from this AST. In other words, any functions that are reachable from
1723/// the entry points.
1724class DiagnoseHLSLAvailability : public DynamicRecursiveASTVisitor {
1725 Sema &SemaRef;
1726
1727 // Stack of functions to be scaned
1728 llvm::SmallVector<const FunctionDecl *, 8> DeclsToScan;
1729
1730 // Tracks which environments functions have been scanned in.
1731 //
1732 // Maps FunctionDecl to an unsigned number that represents the set of shader
1733 // environments the function has been scanned for.
1734 // The llvm::Triple::EnvironmentType enum values for shader stages guaranteed
1735 // to be numbered from llvm::Triple::Pixel to llvm::Triple::Amplification
1736 // (verified by static_asserts in Triple.cpp), we can use it to index
1737 // individual bits in the set, as long as we shift the values to start with 0
1738 // by subtracting the value of llvm::Triple::Pixel first.
1739 //
1740 // The N'th bit in the set will be set if the function has been scanned
1741 // in shader environment whose llvm::Triple::EnvironmentType integer value
1742 // equals (llvm::Triple::Pixel + N).
1743 //
1744 // For example, if a function has been scanned in compute and pixel stage
1745 // environment, the value will be 0x21 (100001 binary) because:
1746 //
1747 // (int)(llvm::Triple::Pixel - llvm::Triple::Pixel) == 0
1748 // (int)(llvm::Triple::Compute - llvm::Triple::Pixel) == 5
1749 //
1750 // A FunctionDecl is mapped to 0 (or not included in the map) if it has not
1751 // been scanned in any environment.
1752 llvm::DenseMap<const FunctionDecl *, unsigned> ScannedDecls;
1753
1754 // Do not access these directly, use the get/set methods below to make
1755 // sure the values are in sync
1756 llvm::Triple::EnvironmentType CurrentShaderEnvironment;
1757 unsigned CurrentShaderStageBit;
1758
1759 // True if scanning a function that was already scanned in a different
1760 // shader stage context, and therefore we should not report issues that
1761 // depend only on shader model version because they would be duplicate.
1762 bool ReportOnlyShaderStageIssues;
1763
1764 // Helper methods for dealing with current stage context / environment
1765 void SetShaderStageContext(llvm::Triple::EnvironmentType ShaderType) {
1766 static_assert(sizeof(unsigned) >= 4);
1767 assert(HLSLShaderAttr::isValidShaderType(ShaderType));
1768 assert((unsigned)(ShaderType - llvm::Triple::Pixel) < 31 &&
1769 "ShaderType is too big for this bitmap"); // 31 is reserved for
1770 // "unknown"
1771
1772 unsigned bitmapIndex = ShaderType - llvm::Triple::Pixel;
1773 CurrentShaderEnvironment = ShaderType;
1774 CurrentShaderStageBit = (1 << bitmapIndex);
1775 }
1776
1777 void SetUnknownShaderStageContext() {
1778 CurrentShaderEnvironment = llvm::Triple::UnknownEnvironment;
1779 CurrentShaderStageBit = (1 << 31);
1780 }
1781
1782 llvm::Triple::EnvironmentType GetCurrentShaderEnvironment() const {
1783 return CurrentShaderEnvironment;
1784 }
1785
1786 bool InUnknownShaderStageContext() const {
1787 return CurrentShaderEnvironment == llvm::Triple::UnknownEnvironment;
1788 }
1789
1790 // Helper methods for dealing with shader stage bitmap
1791 void AddToScannedFunctions(const FunctionDecl *FD) {
1792 unsigned &ScannedStages = ScannedDecls[FD];
1793 ScannedStages |= CurrentShaderStageBit;
1794 }
1795
1796 unsigned GetScannedStages(const FunctionDecl *FD) { return ScannedDecls[FD]; }
1797
1798 bool WasAlreadyScannedInCurrentStage(const FunctionDecl *FD) {
1799 return WasAlreadyScannedInCurrentStage(ScannerStages: GetScannedStages(FD));
1800 }
1801
1802 bool WasAlreadyScannedInCurrentStage(unsigned ScannerStages) {
1803 return ScannerStages & CurrentShaderStageBit;
1804 }
1805
1806 static bool NeverBeenScanned(unsigned ScannedStages) {
1807 return ScannedStages == 0;
1808 }
1809
1810 // Scanning methods
1811 void HandleFunctionOrMethodRef(FunctionDecl *FD, Expr *RefExpr);
1812 void CheckDeclAvailability(NamedDecl *D, const AvailabilityAttr *AA,
1813 SourceRange Range);
1814 const AvailabilityAttr *FindAvailabilityAttr(const Decl *D);
1815 bool HasMatchingEnvironmentOrNone(const AvailabilityAttr *AA);
1816
1817public:
1818 DiagnoseHLSLAvailability(Sema &SemaRef)
1819 : SemaRef(SemaRef),
1820 CurrentShaderEnvironment(llvm::Triple::UnknownEnvironment),
1821 CurrentShaderStageBit(0), ReportOnlyShaderStageIssues(false) {}
1822
1823 // AST traversal methods
1824 void RunOnTranslationUnit(const TranslationUnitDecl *TU);
1825 void RunOnFunction(const FunctionDecl *FD);
1826
1827 bool VisitDeclRefExpr(DeclRefExpr *DRE) override {
1828 FunctionDecl *FD = llvm::dyn_cast<FunctionDecl>(Val: DRE->getDecl());
1829 if (FD)
1830 HandleFunctionOrMethodRef(FD, DRE);
1831 return true;
1832 }
1833
1834 bool VisitMemberExpr(MemberExpr *ME) override {
1835 FunctionDecl *FD = llvm::dyn_cast<FunctionDecl>(Val: ME->getMemberDecl());
1836 if (FD)
1837 HandleFunctionOrMethodRef(FD, ME);
1838 return true;
1839 }
1840};
1841
1842void DiagnoseHLSLAvailability::HandleFunctionOrMethodRef(FunctionDecl *FD,
1843 Expr *RefExpr) {
1844 assert((isa<DeclRefExpr>(RefExpr) || isa<MemberExpr>(RefExpr)) &&
1845 "expected DeclRefExpr or MemberExpr");
1846
1847 // has a definition -> add to stack to be scanned
1848 const FunctionDecl *FDWithBody = nullptr;
1849 if (FD->hasBody(Definition&: FDWithBody)) {
1850 if (!WasAlreadyScannedInCurrentStage(FD: FDWithBody))
1851 DeclsToScan.push_back(Elt: FDWithBody);
1852 return;
1853 }
1854
1855 // no body -> diagnose availability
1856 const AvailabilityAttr *AA = FindAvailabilityAttr(FD);
1857 if (AA)
1858 CheckDeclAvailability(
1859 FD, AA, SourceRange(RefExpr->getBeginLoc(), RefExpr->getEndLoc()));
1860}
1861
1862void DiagnoseHLSLAvailability::RunOnTranslationUnit(
1863 const TranslationUnitDecl *TU) {
1864
1865 // Iterate over all shader entry functions and library exports, and for those
1866 // that have a body (definiton), run diag scan on each, setting appropriate
1867 // shader environment context based on whether it is a shader entry function
1868 // or an exported function. Exported functions can be in namespaces and in
1869 // export declarations so we need to scan those declaration contexts as well.
1870 llvm::SmallVector<const DeclContext *, 8> DeclContextsToScan;
1871 DeclContextsToScan.push_back(TU);
1872
1873 while (!DeclContextsToScan.empty()) {
1874 const DeclContext *DC = DeclContextsToScan.pop_back_val();
1875 for (auto &D : DC->decls()) {
1876 // do not scan implicit declaration generated by the implementation
1877 if (D->isImplicit())
1878 continue;
1879
1880 // for namespace or export declaration add the context to the list to be
1881 // scanned later
1882 if (llvm::dyn_cast<NamespaceDecl>(Val: D) || llvm::dyn_cast<ExportDecl>(Val: D)) {
1883 DeclContextsToScan.push_back(Elt: llvm::dyn_cast<DeclContext>(Val: D));
1884 continue;
1885 }
1886
1887 // skip over other decls or function decls without body
1888 const FunctionDecl *FD = llvm::dyn_cast<FunctionDecl>(Val: D);
1889 if (!FD || !FD->isThisDeclarationADefinition())
1890 continue;
1891
1892 // shader entry point
1893 if (HLSLShaderAttr *ShaderAttr = FD->getAttr<HLSLShaderAttr>()) {
1894 SetShaderStageContext(ShaderAttr->getType());
1895 RunOnFunction(FD);
1896 continue;
1897 }
1898 // exported library function
1899 // FIXME: replace this loop with external linkage check once issue #92071
1900 // is resolved
1901 bool isExport = FD->isInExportDeclContext();
1902 if (!isExport) {
1903 for (const auto *Redecl : FD->redecls()) {
1904 if (Redecl->isInExportDeclContext()) {
1905 isExport = true;
1906 break;
1907 }
1908 }
1909 }
1910 if (isExport) {
1911 SetUnknownShaderStageContext();
1912 RunOnFunction(FD);
1913 continue;
1914 }
1915 }
1916 }
1917}
1918
1919void DiagnoseHLSLAvailability::RunOnFunction(const FunctionDecl *FD) {
1920 assert(DeclsToScan.empty() && "DeclsToScan should be empty");
1921 DeclsToScan.push_back(Elt: FD);
1922
1923 while (!DeclsToScan.empty()) {
1924 // Take one decl from the stack and check it by traversing its AST.
1925 // For any CallExpr found during the traversal add it's callee to the top of
1926 // the stack to be processed next. Functions already processed are stored in
1927 // ScannedDecls.
1928 const FunctionDecl *FD = DeclsToScan.pop_back_val();
1929
1930 // Decl was already scanned
1931 const unsigned ScannedStages = GetScannedStages(FD);
1932 if (WasAlreadyScannedInCurrentStage(ScannerStages: ScannedStages))
1933 continue;
1934
1935 ReportOnlyShaderStageIssues = !NeverBeenScanned(ScannedStages);
1936
1937 AddToScannedFunctions(FD);
1938 TraverseStmt(FD->getBody());
1939 }
1940}
1941
1942bool DiagnoseHLSLAvailability::HasMatchingEnvironmentOrNone(
1943 const AvailabilityAttr *AA) {
1944 IdentifierInfo *IIEnvironment = AA->getEnvironment();
1945 if (!IIEnvironment)
1946 return true;
1947
1948 llvm::Triple::EnvironmentType CurrentEnv = GetCurrentShaderEnvironment();
1949 if (CurrentEnv == llvm::Triple::UnknownEnvironment)
1950 return false;
1951
1952 llvm::Triple::EnvironmentType AttrEnv =
1953 AvailabilityAttr::getEnvironmentType(IIEnvironment->getName());
1954
1955 return CurrentEnv == AttrEnv;
1956}
1957
1958const AvailabilityAttr *
1959DiagnoseHLSLAvailability::FindAvailabilityAttr(const Decl *D) {
1960 AvailabilityAttr const *PartialMatch = nullptr;
1961 // Check each AvailabilityAttr to find the one for this platform.
1962 // For multiple attributes with the same platform try to find one for this
1963 // environment.
1964 for (const auto *A : D->attrs()) {
1965 if (const auto *Avail = dyn_cast<AvailabilityAttr>(A)) {
1966 StringRef AttrPlatform = Avail->getPlatform()->getName();
1967 StringRef TargetPlatform =
1968 SemaRef.getASTContext().getTargetInfo().getPlatformName();
1969
1970 // Match the platform name.
1971 if (AttrPlatform == TargetPlatform) {
1972 // Find the best matching attribute for this environment
1973 if (HasMatchingEnvironmentOrNone(Avail))
1974 return Avail;
1975 PartialMatch = Avail;
1976 }
1977 }
1978 }
1979 return PartialMatch;
1980}
1981
1982// Check availability against target shader model version and current shader
1983// stage and emit diagnostic
1984void DiagnoseHLSLAvailability::CheckDeclAvailability(NamedDecl *D,
1985 const AvailabilityAttr *AA,
1986 SourceRange Range) {
1987
1988 IdentifierInfo *IIEnv = AA->getEnvironment();
1989
1990 if (!IIEnv) {
1991 // The availability attribute does not have environment -> it depends only
1992 // on shader model version and not on specific the shader stage.
1993
1994 // Skip emitting the diagnostics if the diagnostic mode is set to
1995 // strict (-fhlsl-strict-availability) because all relevant diagnostics
1996 // were already emitted in the DiagnoseUnguardedAvailability scan
1997 // (SemaAvailability.cpp).
1998 if (SemaRef.getLangOpts().HLSLStrictAvailability)
1999 return;
2000
2001 // Do not report shader-stage-independent issues if scanning a function
2002 // that was already scanned in a different shader stage context (they would
2003 // be duplicate)
2004 if (ReportOnlyShaderStageIssues)
2005 return;
2006
2007 } else {
2008 // The availability attribute has environment -> we need to know
2009 // the current stage context to property diagnose it.
2010 if (InUnknownShaderStageContext())
2011 return;
2012 }
2013
2014 // Check introduced version and if environment matches
2015 bool EnvironmentMatches = HasMatchingEnvironmentOrNone(AA);
2016 VersionTuple Introduced = AA->getIntroduced();
2017 VersionTuple TargetVersion =
2018 SemaRef.Context.getTargetInfo().getPlatformMinVersion();
2019
2020 if (TargetVersion >= Introduced && EnvironmentMatches)
2021 return;
2022
2023 // Emit diagnostic message
2024 const TargetInfo &TI = SemaRef.getASTContext().getTargetInfo();
2025 llvm::StringRef PlatformName(
2026 AvailabilityAttr::getPrettyPlatformName(TI.getPlatformName()));
2027
2028 llvm::StringRef CurrentEnvStr =
2029 llvm::Triple::getEnvironmentTypeName(Kind: GetCurrentShaderEnvironment());
2030
2031 llvm::StringRef AttrEnvStr =
2032 AA->getEnvironment() ? AA->getEnvironment()->getName() : "";
2033 bool UseEnvironment = !AttrEnvStr.empty();
2034
2035 if (EnvironmentMatches) {
2036 SemaRef.Diag(Range.getBegin(), diag::warn_hlsl_availability)
2037 << Range << D << PlatformName << Introduced.getAsString()
2038 << UseEnvironment << CurrentEnvStr;
2039 } else {
2040 SemaRef.Diag(Range.getBegin(), diag::warn_hlsl_availability_unavailable)
2041 << Range << D;
2042 }
2043
2044 SemaRef.Diag(D->getLocation(), diag::note_partial_availability_specified_here)
2045 << D << PlatformName << Introduced.getAsString()
2046 << SemaRef.Context.getTargetInfo().getPlatformMinVersion().getAsString()
2047 << UseEnvironment << AttrEnvStr << CurrentEnvStr;
2048}
2049
2050} // namespace
2051
2052void SemaHLSL::ActOnEndOfTranslationUnit(TranslationUnitDecl *TU) {
2053 // process default CBuffer - create buffer layout struct and invoke codegenCGH
2054 if (!DefaultCBufferDecls.empty()) {
2055 HLSLBufferDecl *DefaultCBuffer = HLSLBufferDecl::CreateDefaultCBuffer(
2056 C&: SemaRef.getASTContext(), LexicalParent: SemaRef.getCurLexicalContext(),
2057 DefaultCBufferDecls);
2058 addImplicitBindingAttrToBuffer(S&: SemaRef, BufDecl: DefaultCBuffer,
2059 ImplicitBindingOrderID: getNextImplicitBindingOrderID());
2060 SemaRef.getCurLexicalContext()->addDecl(DefaultCBuffer);
2061 createHostLayoutStructForBuffer(S&: SemaRef, BufDecl: DefaultCBuffer);
2062
2063 // Set HasValidPackoffset if any of the decls has a register(c#) annotation;
2064 for (const Decl *VD : DefaultCBufferDecls) {
2065 const HLSLResourceBindingAttr *RBA =
2066 VD->getAttr<HLSLResourceBindingAttr>();
2067 if (RBA && RBA->hasRegisterSlot() &&
2068 RBA->getRegisterType() == HLSLResourceBindingAttr::RegisterType::C) {
2069 DefaultCBuffer->setHasValidPackoffset(true);
2070 break;
2071 }
2072 }
2073
2074 DeclGroupRef DG(DefaultCBuffer);
2075 SemaRef.Consumer.HandleTopLevelDecl(D: DG);
2076 }
2077 diagnoseAvailabilityViolations(TU);
2078}
2079
2080void SemaHLSL::diagnoseAvailabilityViolations(TranslationUnitDecl *TU) {
2081 // Skip running the diagnostics scan if the diagnostic mode is
2082 // strict (-fhlsl-strict-availability) and the target shader stage is known
2083 // because all relevant diagnostics were already emitted in the
2084 // DiagnoseUnguardedAvailability scan (SemaAvailability.cpp).
2085 const TargetInfo &TI = SemaRef.getASTContext().getTargetInfo();
2086 if (SemaRef.getLangOpts().HLSLStrictAvailability &&
2087 TI.getTriple().getEnvironment() != llvm::Triple::EnvironmentType::Library)
2088 return;
2089
2090 DiagnoseHLSLAvailability(SemaRef).RunOnTranslationUnit(TU);
2091}
2092
2093static bool CheckAllArgsHaveSameType(Sema *S, CallExpr *TheCall) {
2094 assert(TheCall->getNumArgs() > 1);
2095 QualType ArgTy0 = TheCall->getArg(Arg: 0)->getType();
2096
2097 for (unsigned I = 1, N = TheCall->getNumArgs(); I < N; ++I) {
2098 if (!S->getASTContext().hasSameUnqualifiedType(
2099 T1: ArgTy0, T2: TheCall->getArg(Arg: I)->getType())) {
2100 S->Diag(TheCall->getBeginLoc(), diag::err_vec_builtin_incompatible_vector)
2101 << TheCall->getDirectCallee() << /*useAllTerminology*/ true
2102 << SourceRange(TheCall->getArg(0)->getBeginLoc(),
2103 TheCall->getArg(N - 1)->getEndLoc());
2104 return true;
2105 }
2106 }
2107 return false;
2108}
2109
2110static bool CheckArgTypeMatches(Sema *S, Expr *Arg, QualType ExpectedType) {
2111 QualType ArgType = Arg->getType();
2112 if (!S->getASTContext().hasSameUnqualifiedType(T1: ArgType, T2: ExpectedType)) {
2113 S->Diag(Arg->getBeginLoc(), diag::err_typecheck_convert_incompatible)
2114 << ArgType << ExpectedType << 1 << 0 << 0;
2115 return true;
2116 }
2117 return false;
2118}
2119
2120static bool CheckAllArgTypesAreCorrect(
2121 Sema *S, CallExpr *TheCall,
2122 llvm::function_ref<bool(Sema *S, SourceLocation Loc, int ArgOrdinal,
2123 clang::QualType PassedType)>
2124 Check) {
2125 for (unsigned I = 0; I < TheCall->getNumArgs(); ++I) {
2126 Expr *Arg = TheCall->getArg(Arg: I);
2127 if (Check(S, Arg->getBeginLoc(), I + 1, Arg->getType()))
2128 return true;
2129 }
2130 return false;
2131}
2132
2133static bool CheckFloatOrHalfRepresentation(Sema *S, SourceLocation Loc,
2134 int ArgOrdinal,
2135 clang::QualType PassedType) {
2136 clang::QualType BaseType =
2137 PassedType->isVectorType()
2138 ? PassedType->getAs<clang::VectorType>()->getElementType()
2139 : PassedType;
2140 if (!BaseType->isHalfType() && !BaseType->isFloat32Type())
2141 return S->Diag(Loc, diag::err_builtin_invalid_arg_type)
2142 << ArgOrdinal << /* scalar or vector of */ 5 << /* no int */ 0
2143 << /* half or float */ 2 << PassedType;
2144 return false;
2145}
2146
2147static bool CheckModifiableLValue(Sema *S, CallExpr *TheCall,
2148 unsigned ArgIndex) {
2149 auto *Arg = TheCall->getArg(Arg: ArgIndex);
2150 SourceLocation OrigLoc = Arg->getExprLoc();
2151 if (Arg->IgnoreCasts()->isModifiableLvalue(Ctx&: S->Context, Loc: &OrigLoc) ==
2152 Expr::MLV_Valid)
2153 return false;
2154 S->Diag(OrigLoc, diag::error_hlsl_inout_lvalue) << Arg << 0;
2155 return true;
2156}
2157
2158static bool CheckNoDoubleVectors(Sema *S, SourceLocation Loc, int ArgOrdinal,
2159 clang::QualType PassedType) {
2160 const auto *VecTy = PassedType->getAs<VectorType>();
2161 if (!VecTy)
2162 return false;
2163
2164 if (VecTy->getElementType()->isDoubleType())
2165 return S->Diag(Loc, diag::err_builtin_invalid_arg_type)
2166 << ArgOrdinal << /* scalar */ 1 << /* no int */ 0 << /* fp */ 1
2167 << PassedType;
2168 return false;
2169}
2170
2171static bool CheckFloatingOrIntRepresentation(Sema *S, SourceLocation Loc,
2172 int ArgOrdinal,
2173 clang::QualType PassedType) {
2174 if (!PassedType->hasIntegerRepresentation() &&
2175 !PassedType->hasFloatingRepresentation())
2176 return S->Diag(Loc, diag::err_builtin_invalid_arg_type)
2177 << ArgOrdinal << /* scalar or vector of */ 5 << /* integer */ 1
2178 << /* fp */ 1 << PassedType;
2179 return false;
2180}
2181
2182static bool CheckUnsignedIntVecRepresentation(Sema *S, SourceLocation Loc,
2183 int ArgOrdinal,
2184 clang::QualType PassedType) {
2185 if (auto *VecTy = PassedType->getAs<VectorType>())
2186 if (VecTy->getElementType()->isUnsignedIntegerType())
2187 return false;
2188
2189 return S->Diag(Loc, diag::err_builtin_invalid_arg_type)
2190 << ArgOrdinal << /* vector of */ 4 << /* uint */ 3 << /* no fp */ 0
2191 << PassedType;
2192}
2193
2194// checks for unsigned ints of all sizes
2195static bool CheckUnsignedIntRepresentation(Sema *S, SourceLocation Loc,
2196 int ArgOrdinal,
2197 clang::QualType PassedType) {
2198 if (!PassedType->hasUnsignedIntegerRepresentation())
2199 return S->Diag(Loc, diag::err_builtin_invalid_arg_type)
2200 << ArgOrdinal << /* scalar or vector of */ 5 << /* unsigned int */ 3
2201 << /* no fp */ 0 << PassedType;
2202 return false;
2203}
2204
2205static void SetElementTypeAsReturnType(Sema *S, CallExpr *TheCall,
2206 QualType ReturnType) {
2207 auto *VecTyA = TheCall->getArg(Arg: 0)->getType()->getAs<VectorType>();
2208 if (VecTyA)
2209 ReturnType = S->Context.getVectorType(VectorType: ReturnType, NumElts: VecTyA->getNumElements(),
2210 VecKind: VectorKind::Generic);
2211 TheCall->setType(ReturnType);
2212}
2213
2214static bool CheckScalarOrVector(Sema *S, CallExpr *TheCall, QualType Scalar,
2215 unsigned ArgIndex) {
2216 assert(TheCall->getNumArgs() >= ArgIndex);
2217 QualType ArgType = TheCall->getArg(Arg: ArgIndex)->getType();
2218 auto *VTy = ArgType->getAs<VectorType>();
2219 // not the scalar or vector<scalar>
2220 if (!(S->Context.hasSameUnqualifiedType(T1: ArgType, T2: Scalar) ||
2221 (VTy &&
2222 S->Context.hasSameUnqualifiedType(T1: VTy->getElementType(), T2: Scalar)))) {
2223 S->Diag(TheCall->getArg(0)->getBeginLoc(),
2224 diag::err_typecheck_expect_scalar_or_vector)
2225 << ArgType << Scalar;
2226 return true;
2227 }
2228 return false;
2229}
2230
2231static bool CheckAnyScalarOrVector(Sema *S, CallExpr *TheCall,
2232 unsigned ArgIndex) {
2233 assert(TheCall->getNumArgs() >= ArgIndex);
2234 QualType ArgType = TheCall->getArg(Arg: ArgIndex)->getType();
2235 auto *VTy = ArgType->getAs<VectorType>();
2236 // not the scalar or vector<scalar>
2237 if (!(ArgType->isScalarType() ||
2238 (VTy && VTy->getElementType()->isScalarType()))) {
2239 S->Diag(TheCall->getArg(0)->getBeginLoc(),
2240 diag::err_typecheck_expect_any_scalar_or_vector)
2241 << ArgType << 1;
2242 return true;
2243 }
2244 return false;
2245}
2246
2247static bool CheckWaveActive(Sema *S, CallExpr *TheCall) {
2248 QualType BoolType = S->getASTContext().BoolTy;
2249 assert(TheCall->getNumArgs() >= 1);
2250 QualType ArgType = TheCall->getArg(Arg: 0)->getType();
2251 auto *VTy = ArgType->getAs<VectorType>();
2252 // is the bool or vector<bool>
2253 if (S->Context.hasSameUnqualifiedType(T1: ArgType, T2: BoolType) ||
2254 (VTy &&
2255 S->Context.hasSameUnqualifiedType(T1: VTy->getElementType(), T2: BoolType))) {
2256 S->Diag(TheCall->getArg(0)->getBeginLoc(),
2257 diag::err_typecheck_expect_any_scalar_or_vector)
2258 << ArgType << 0;
2259 return true;
2260 }
2261 return false;
2262}
2263
2264static bool CheckBoolSelect(Sema *S, CallExpr *TheCall) {
2265 assert(TheCall->getNumArgs() == 3);
2266 Expr *Arg1 = TheCall->getArg(Arg: 1);
2267 Expr *Arg2 = TheCall->getArg(Arg: 2);
2268 if (!S->Context.hasSameUnqualifiedType(T1: Arg1->getType(), T2: Arg2->getType())) {
2269 S->Diag(TheCall->getBeginLoc(),
2270 diag::err_typecheck_call_different_arg_types)
2271 << Arg1->getType() << Arg2->getType() << Arg1->getSourceRange()
2272 << Arg2->getSourceRange();
2273 return true;
2274 }
2275
2276 TheCall->setType(Arg1->getType());
2277 return false;
2278}
2279
2280static bool CheckVectorSelect(Sema *S, CallExpr *TheCall) {
2281 assert(TheCall->getNumArgs() == 3);
2282 Expr *Arg1 = TheCall->getArg(Arg: 1);
2283 QualType Arg1Ty = Arg1->getType();
2284 Expr *Arg2 = TheCall->getArg(Arg: 2);
2285 QualType Arg2Ty = Arg2->getType();
2286
2287 QualType Arg1ScalarTy = Arg1Ty;
2288 if (auto VTy = Arg1ScalarTy->getAs<VectorType>())
2289 Arg1ScalarTy = VTy->getElementType();
2290
2291 QualType Arg2ScalarTy = Arg2Ty;
2292 if (auto VTy = Arg2ScalarTy->getAs<VectorType>())
2293 Arg2ScalarTy = VTy->getElementType();
2294
2295 if (!S->Context.hasSameUnqualifiedType(Arg1ScalarTy, Arg2ScalarTy))
2296 S->Diag(Arg1->getBeginLoc(), diag::err_hlsl_builtin_scalar_vector_mismatch)
2297 << /* second and third */ 1 << TheCall->getCallee() << Arg1Ty << Arg2Ty;
2298
2299 QualType Arg0Ty = TheCall->getArg(Arg: 0)->getType();
2300 unsigned Arg0Length = Arg0Ty->getAs<VectorType>()->getNumElements();
2301 unsigned Arg1Length = Arg1Ty->isVectorType()
2302 ? Arg1Ty->getAs<VectorType>()->getNumElements()
2303 : 0;
2304 unsigned Arg2Length = Arg2Ty->isVectorType()
2305 ? Arg2Ty->getAs<VectorType>()->getNumElements()
2306 : 0;
2307 if (Arg1Length > 0 && Arg0Length != Arg1Length) {
2308 S->Diag(TheCall->getBeginLoc(),
2309 diag::err_typecheck_vector_lengths_not_equal)
2310 << Arg0Ty << Arg1Ty << TheCall->getArg(0)->getSourceRange()
2311 << Arg1->getSourceRange();
2312 return true;
2313 }
2314
2315 if (Arg2Length > 0 && Arg0Length != Arg2Length) {
2316 S->Diag(TheCall->getBeginLoc(),
2317 diag::err_typecheck_vector_lengths_not_equal)
2318 << Arg0Ty << Arg2Ty << TheCall->getArg(0)->getSourceRange()
2319 << Arg2->getSourceRange();
2320 return true;
2321 }
2322
2323 TheCall->setType(
2324 S->getASTContext().getExtVectorType(VectorType: Arg1ScalarTy, NumElts: Arg0Length));
2325 return false;
2326}
2327
2328static bool CheckResourceHandle(
2329 Sema *S, CallExpr *TheCall, unsigned ArgIndex,
2330 llvm::function_ref<bool(const HLSLAttributedResourceType *ResType)> Check =
2331 nullptr) {
2332 assert(TheCall->getNumArgs() >= ArgIndex);
2333 QualType ArgType = TheCall->getArg(Arg: ArgIndex)->getType();
2334 const HLSLAttributedResourceType *ResTy =
2335 ArgType.getTypePtr()->getAs<HLSLAttributedResourceType>();
2336 if (!ResTy) {
2337 S->Diag(TheCall->getArg(ArgIndex)->getBeginLoc(),
2338 diag::err_typecheck_expect_hlsl_resource)
2339 << ArgType;
2340 return true;
2341 }
2342 if (Check && Check(ResTy)) {
2343 S->Diag(TheCall->getArg(ArgIndex)->getExprLoc(),
2344 diag::err_invalid_hlsl_resource_type)
2345 << ArgType;
2346 return true;
2347 }
2348 return false;
2349}
2350
2351// Note: returning true in this case results in CheckBuiltinFunctionCall
2352// returning an ExprError
2353bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
2354 switch (BuiltinID) {
2355 case Builtin::BI__builtin_hlsl_adduint64: {
2356 if (SemaRef.checkArgCount(Call: TheCall, DesiredArgCount: 2))
2357 return true;
2358
2359 if (CheckAllArgTypesAreCorrect(S: &SemaRef, TheCall,
2360 Check: CheckUnsignedIntVecRepresentation))
2361 return true;
2362
2363 auto *VTy = TheCall->getArg(Arg: 0)->getType()->getAs<VectorType>();
2364 // ensure arg integers are 32-bits
2365 uint64_t ElementBitCount = getASTContext()
2366 .getTypeSizeInChars(T: VTy->getElementType())
2367 .getQuantity() *
2368 8;
2369 if (ElementBitCount != 32) {
2370 SemaRef.Diag(TheCall->getBeginLoc(),
2371 diag::err_integer_incorrect_bit_count)
2372 << 32 << ElementBitCount;
2373 return true;
2374 }
2375
2376 // ensure both args are vectors of total bit size of a multiple of 64
2377 int NumElementsArg = VTy->getNumElements();
2378 if (NumElementsArg != 2 && NumElementsArg != 4) {
2379 SemaRef.Diag(TheCall->getBeginLoc(), diag::err_vector_incorrect_bit_count)
2380 << 1 /*a multiple of*/ << 64 << NumElementsArg * ElementBitCount;
2381 return true;
2382 }
2383
2384 // ensure first arg and second arg have the same type
2385 if (CheckAllArgsHaveSameType(S: &SemaRef, TheCall))
2386 return true;
2387
2388 ExprResult A = TheCall->getArg(Arg: 0);
2389 QualType ArgTyA = A.get()->getType();
2390 // return type is the same as the input type
2391 TheCall->setType(ArgTyA);
2392 break;
2393 }
2394 case Builtin::BI__builtin_hlsl_resource_getpointer: {
2395 if (SemaRef.checkArgCount(Call: TheCall, DesiredArgCount: 2) ||
2396 CheckResourceHandle(S: &SemaRef, TheCall, ArgIndex: 0) ||
2397 CheckArgTypeMatches(&SemaRef, TheCall->getArg(Arg: 1),
2398 SemaRef.getASTContext().UnsignedIntTy))
2399 return true;
2400
2401 auto *ResourceTy =
2402 TheCall->getArg(Arg: 0)->getType()->castAs<HLSLAttributedResourceType>();
2403 QualType ContainedTy = ResourceTy->getContainedType();
2404 auto ReturnType =
2405 SemaRef.Context.getAddrSpaceQualType(T: ContainedTy, AddressSpace: LangAS::hlsl_device);
2406 ReturnType = SemaRef.Context.getPointerType(T: ReturnType);
2407 TheCall->setType(ReturnType);
2408 TheCall->setValueKind(VK_LValue);
2409
2410 break;
2411 }
2412 case Builtin::BI__builtin_hlsl_resource_uninitializedhandle: {
2413 if (SemaRef.checkArgCount(Call: TheCall, DesiredArgCount: 1) ||
2414 CheckResourceHandle(S: &SemaRef, TheCall, ArgIndex: 0))
2415 return true;
2416 // use the type of the handle (arg0) as a return type
2417 QualType ResourceTy = TheCall->getArg(Arg: 0)->getType();
2418 TheCall->setType(ResourceTy);
2419 break;
2420 }
2421 case Builtin::BI__builtin_hlsl_resource_handlefrombinding: {
2422 ASTContext &AST = SemaRef.getASTContext();
2423 if (SemaRef.checkArgCount(Call: TheCall, DesiredArgCount: 6) ||
2424 CheckResourceHandle(S: &SemaRef, TheCall, ArgIndex: 0) ||
2425 CheckArgTypeMatches(&SemaRef, TheCall->getArg(Arg: 1), AST.UnsignedIntTy) ||
2426 CheckArgTypeMatches(&SemaRef, TheCall->getArg(Arg: 2), AST.UnsignedIntTy) ||
2427 CheckArgTypeMatches(&SemaRef, TheCall->getArg(Arg: 3), AST.IntTy) ||
2428 CheckArgTypeMatches(&SemaRef, TheCall->getArg(Arg: 4), AST.UnsignedIntTy) ||
2429 CheckArgTypeMatches(&SemaRef, TheCall->getArg(Arg: 5),
2430 AST.getPointerType(AST.CharTy.withConst())))
2431 return true;
2432 // use the type of the handle (arg0) as a return type
2433 QualType ResourceTy = TheCall->getArg(Arg: 0)->getType();
2434 TheCall->setType(ResourceTy);
2435 break;
2436 }
2437 case Builtin::BI__builtin_hlsl_resource_handlefromimplicitbinding: {
2438 ASTContext &AST = SemaRef.getASTContext();
2439 if (SemaRef.checkArgCount(Call: TheCall, DesiredArgCount: 6) ||
2440 CheckResourceHandle(S: &SemaRef, TheCall, ArgIndex: 0) ||
2441 CheckArgTypeMatches(&SemaRef, TheCall->getArg(Arg: 1), AST.UnsignedIntTy) ||
2442 CheckArgTypeMatches(&SemaRef, TheCall->getArg(Arg: 2), AST.IntTy) ||
2443 CheckArgTypeMatches(&SemaRef, TheCall->getArg(Arg: 3), AST.UnsignedIntTy) ||
2444 CheckArgTypeMatches(&SemaRef, TheCall->getArg(Arg: 4), AST.UnsignedIntTy) ||
2445 CheckArgTypeMatches(&SemaRef, TheCall->getArg(Arg: 5),
2446 AST.getPointerType(AST.CharTy.withConst())))
2447 return true;
2448 // use the type of the handle (arg0) as a return type
2449 QualType ResourceTy = TheCall->getArg(Arg: 0)->getType();
2450 TheCall->setType(ResourceTy);
2451 break;
2452 }
2453 case Builtin::BI__builtin_hlsl_and:
2454 case Builtin::BI__builtin_hlsl_or: {
2455 if (SemaRef.checkArgCount(Call: TheCall, DesiredArgCount: 2))
2456 return true;
2457 if (CheckScalarOrVector(&SemaRef, TheCall, getASTContext().BoolTy, 0))
2458 return true;
2459 if (CheckAllArgsHaveSameType(S: &SemaRef, TheCall))
2460 return true;
2461
2462 ExprResult A = TheCall->getArg(Arg: 0);
2463 QualType ArgTyA = A.get()->getType();
2464 // return type is the same as the input type
2465 TheCall->setType(ArgTyA);
2466 break;
2467 }
2468 case Builtin::BI__builtin_hlsl_all:
2469 case Builtin::BI__builtin_hlsl_any: {
2470 if (SemaRef.checkArgCount(Call: TheCall, DesiredArgCount: 1))
2471 return true;
2472 if (CheckAnyScalarOrVector(S: &SemaRef, TheCall, ArgIndex: 0))
2473 return true;
2474 break;
2475 }
2476 case Builtin::BI__builtin_hlsl_asdouble: {
2477 if (SemaRef.checkArgCount(Call: TheCall, DesiredArgCount: 2))
2478 return true;
2479 if (CheckScalarOrVector(
2480 &SemaRef, TheCall,
2481 /*only check for uint*/ SemaRef.Context.UnsignedIntTy,
2482 /* arg index */ 0))
2483 return true;
2484 if (CheckScalarOrVector(
2485 &SemaRef, TheCall,
2486 /*only check for uint*/ SemaRef.Context.UnsignedIntTy,
2487 /* arg index */ 1))
2488 return true;
2489 if (CheckAllArgsHaveSameType(S: &SemaRef, TheCall))
2490 return true;
2491
2492 SetElementTypeAsReturnType(&SemaRef, TheCall, getASTContext().DoubleTy);
2493 break;
2494 }
2495 case Builtin::BI__builtin_hlsl_elementwise_clamp: {
2496 if (SemaRef.BuiltinElementwiseTernaryMath(
2497 TheCall, /*ArgTyRestr=*/
2498 Sema::EltwiseBuiltinArgTyRestriction::None))
2499 return true;
2500 break;
2501 }
2502 case Builtin::BI__builtin_hlsl_dot: {
2503 // arg count is checked by BuiltinVectorToScalarMath
2504 if (SemaRef.BuiltinVectorToScalarMath(TheCall))
2505 return true;
2506 if (CheckAllArgTypesAreCorrect(S: &SemaRef, TheCall, Check: CheckNoDoubleVectors))
2507 return true;
2508 break;
2509 }
2510 case Builtin::BI__builtin_hlsl_elementwise_firstbithigh:
2511 case Builtin::BI__builtin_hlsl_elementwise_firstbitlow: {
2512 if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall))
2513 return true;
2514
2515 const Expr *Arg = TheCall->getArg(Arg: 0);
2516 QualType ArgTy = Arg->getType();
2517 QualType EltTy = ArgTy;
2518
2519 QualType ResTy = SemaRef.Context.UnsignedIntTy;
2520
2521 if (auto *VecTy = EltTy->getAs<VectorType>()) {
2522 EltTy = VecTy->getElementType();
2523 ResTy = SemaRef.Context.getVectorType(VectorType: ResTy, NumElts: VecTy->getNumElements(),
2524 VecKind: VecTy->getVectorKind());
2525 }
2526
2527 if (!EltTy->isIntegerType()) {
2528 Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
2529 << 1 << /* scalar or vector of */ 5 << /* integer ty */ 1
2530 << /* no fp */ 0 << ArgTy;
2531 return true;
2532 }
2533
2534 TheCall->setType(ResTy);
2535 break;
2536 }
2537 case Builtin::BI__builtin_hlsl_select: {
2538 if (SemaRef.checkArgCount(Call: TheCall, DesiredArgCount: 3))
2539 return true;
2540 if (CheckScalarOrVector(&SemaRef, TheCall, getASTContext().BoolTy, 0))
2541 return true;
2542 QualType ArgTy = TheCall->getArg(Arg: 0)->getType();
2543 if (ArgTy->isBooleanType() && CheckBoolSelect(S: &SemaRef, TheCall))
2544 return true;
2545 auto *VTy = ArgTy->getAs<VectorType>();
2546 if (VTy && VTy->getElementType()->isBooleanType() &&
2547 CheckVectorSelect(S: &SemaRef, TheCall))
2548 return true;
2549 break;
2550 }
2551 case Builtin::BI__builtin_hlsl_elementwise_saturate:
2552 case Builtin::BI__builtin_hlsl_elementwise_rcp: {
2553 if (SemaRef.checkArgCount(Call: TheCall, DesiredArgCount: 1))
2554 return true;
2555 if (!TheCall->getArg(0)
2556 ->getType()
2557 ->hasFloatingRepresentation()) // half or float or double
2558 return SemaRef.Diag(TheCall->getArg(0)->getBeginLoc(),
2559 diag::err_builtin_invalid_arg_type)
2560 << /* ordinal */ 1 << /* scalar or vector */ 5 << /* no int */ 0
2561 << /* fp */ 1 << TheCall->getArg(0)->getType();
2562 if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall))
2563 return true;
2564 break;
2565 }
2566 case Builtin::BI__builtin_hlsl_elementwise_degrees:
2567 case Builtin::BI__builtin_hlsl_elementwise_radians:
2568 case Builtin::BI__builtin_hlsl_elementwise_rsqrt:
2569 case Builtin::BI__builtin_hlsl_elementwise_frac: {
2570 if (SemaRef.checkArgCount(Call: TheCall, DesiredArgCount: 1))
2571 return true;
2572 if (CheckAllArgTypesAreCorrect(S: &SemaRef, TheCall,
2573 Check: CheckFloatOrHalfRepresentation))
2574 return true;
2575 if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall))
2576 return true;
2577 break;
2578 }
2579 case Builtin::BI__builtin_hlsl_elementwise_isinf: {
2580 if (SemaRef.checkArgCount(Call: TheCall, DesiredArgCount: 1))
2581 return true;
2582 if (CheckAllArgTypesAreCorrect(S: &SemaRef, TheCall,
2583 Check: CheckFloatOrHalfRepresentation))
2584 return true;
2585 if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall))
2586 return true;
2587 SetElementTypeAsReturnType(&SemaRef, TheCall, getASTContext().BoolTy);
2588 break;
2589 }
2590 case Builtin::BI__builtin_hlsl_lerp: {
2591 if (SemaRef.checkArgCount(Call: TheCall, DesiredArgCount: 3))
2592 return true;
2593 if (CheckAllArgTypesAreCorrect(S: &SemaRef, TheCall,
2594 Check: CheckFloatOrHalfRepresentation))
2595 return true;
2596 if (CheckAllArgsHaveSameType(S: &SemaRef, TheCall))
2597 return true;
2598 if (SemaRef.BuiltinElementwiseTernaryMath(TheCall))
2599 return true;
2600 break;
2601 }
2602 case Builtin::BI__builtin_hlsl_mad: {
2603 if (SemaRef.BuiltinElementwiseTernaryMath(
2604 TheCall, /*ArgTyRestr=*/
2605 Sema::EltwiseBuiltinArgTyRestriction::None))
2606 return true;
2607 break;
2608 }
2609 case Builtin::BI__builtin_hlsl_normalize: {
2610 if (SemaRef.checkArgCount(Call: TheCall, DesiredArgCount: 1))
2611 return true;
2612 if (CheckAllArgTypesAreCorrect(S: &SemaRef, TheCall,
2613 Check: CheckFloatOrHalfRepresentation))
2614 return true;
2615 ExprResult A = TheCall->getArg(Arg: 0);
2616 QualType ArgTyA = A.get()->getType();
2617 // return type is the same as the input type
2618 TheCall->setType(ArgTyA);
2619 break;
2620 }
2621 case Builtin::BI__builtin_hlsl_elementwise_sign: {
2622 if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall))
2623 return true;
2624 if (CheckAllArgTypesAreCorrect(S: &SemaRef, TheCall,
2625 Check: CheckFloatingOrIntRepresentation))
2626 return true;
2627 SetElementTypeAsReturnType(&SemaRef, TheCall, getASTContext().IntTy);
2628 break;
2629 }
2630 case Builtin::BI__builtin_hlsl_step: {
2631 if (SemaRef.checkArgCount(Call: TheCall, DesiredArgCount: 2))
2632 return true;
2633 if (CheckAllArgTypesAreCorrect(S: &SemaRef, TheCall,
2634 Check: CheckFloatOrHalfRepresentation))
2635 return true;
2636
2637 ExprResult A = TheCall->getArg(Arg: 0);
2638 QualType ArgTyA = A.get()->getType();
2639 // return type is the same as the input type
2640 TheCall->setType(ArgTyA);
2641 break;
2642 }
2643 case Builtin::BI__builtin_hlsl_wave_active_max:
2644 case Builtin::BI__builtin_hlsl_wave_active_sum: {
2645 if (SemaRef.checkArgCount(Call: TheCall, DesiredArgCount: 1))
2646 return true;
2647
2648 // Ensure input expr type is a scalar/vector and the same as the return type
2649 if (CheckAnyScalarOrVector(S: &SemaRef, TheCall, ArgIndex: 0))
2650 return true;
2651 if (CheckWaveActive(S: &SemaRef, TheCall))
2652 return true;
2653 ExprResult Expr = TheCall->getArg(Arg: 0);
2654 QualType ArgTyExpr = Expr.get()->getType();
2655 TheCall->setType(ArgTyExpr);
2656 break;
2657 }
2658 // Note these are llvm builtins that we want to catch invalid intrinsic
2659 // generation. Normal handling of these builitns will occur elsewhere.
2660 case Builtin::BI__builtin_elementwise_bitreverse: {
2661 // does not include a check for number of arguments
2662 // because that is done previously
2663 if (CheckAllArgTypesAreCorrect(S: &SemaRef, TheCall,
2664 Check: CheckUnsignedIntRepresentation))
2665 return true;
2666 break;
2667 }
2668 case Builtin::BI__builtin_hlsl_wave_read_lane_at: {
2669 if (SemaRef.checkArgCount(Call: TheCall, DesiredArgCount: 2))
2670 return true;
2671
2672 // Ensure index parameter type can be interpreted as a uint
2673 ExprResult Index = TheCall->getArg(Arg: 1);
2674 QualType ArgTyIndex = Index.get()->getType();
2675 if (!ArgTyIndex->isIntegerType()) {
2676 SemaRef.Diag(TheCall->getArg(1)->getBeginLoc(),
2677 diag::err_typecheck_convert_incompatible)
2678 << ArgTyIndex << SemaRef.Context.UnsignedIntTy << 1 << 0 << 0;
2679 return true;
2680 }
2681
2682 // Ensure input expr type is a scalar/vector and the same as the return type
2683 if (CheckAnyScalarOrVector(S: &SemaRef, TheCall, ArgIndex: 0))
2684 return true;
2685
2686 ExprResult Expr = TheCall->getArg(Arg: 0);
2687 QualType ArgTyExpr = Expr.get()->getType();
2688 TheCall->setType(ArgTyExpr);
2689 break;
2690 }
2691 case Builtin::BI__builtin_hlsl_wave_get_lane_index: {
2692 if (SemaRef.checkArgCount(Call: TheCall, DesiredArgCount: 0))
2693 return true;
2694 break;
2695 }
2696 case Builtin::BI__builtin_hlsl_elementwise_splitdouble: {
2697 if (SemaRef.checkArgCount(Call: TheCall, DesiredArgCount: 3))
2698 return true;
2699
2700 if (CheckScalarOrVector(&SemaRef, TheCall, SemaRef.Context.DoubleTy, 0) ||
2701 CheckScalarOrVector(&SemaRef, TheCall, SemaRef.Context.UnsignedIntTy,
2702 1) ||
2703 CheckScalarOrVector(&SemaRef, TheCall, SemaRef.Context.UnsignedIntTy,
2704 2))
2705 return true;
2706
2707 if (CheckModifiableLValue(S: &SemaRef, TheCall, ArgIndex: 1) ||
2708 CheckModifiableLValue(S: &SemaRef, TheCall, ArgIndex: 2))
2709 return true;
2710 break;
2711 }
2712 case Builtin::BI__builtin_hlsl_elementwise_clip: {
2713 if (SemaRef.checkArgCount(Call: TheCall, DesiredArgCount: 1))
2714 return true;
2715
2716 if (CheckScalarOrVector(&SemaRef, TheCall, SemaRef.Context.FloatTy, 0))
2717 return true;
2718 break;
2719 }
2720 case Builtin::BI__builtin_elementwise_acos:
2721 case Builtin::BI__builtin_elementwise_asin:
2722 case Builtin::BI__builtin_elementwise_atan:
2723 case Builtin::BI__builtin_elementwise_atan2:
2724 case Builtin::BI__builtin_elementwise_ceil:
2725 case Builtin::BI__builtin_elementwise_cos:
2726 case Builtin::BI__builtin_elementwise_cosh:
2727 case Builtin::BI__builtin_elementwise_exp:
2728 case Builtin::BI__builtin_elementwise_exp2:
2729 case Builtin::BI__builtin_elementwise_exp10:
2730 case Builtin::BI__builtin_elementwise_floor:
2731 case Builtin::BI__builtin_elementwise_fmod:
2732 case Builtin::BI__builtin_elementwise_log:
2733 case Builtin::BI__builtin_elementwise_log2:
2734 case Builtin::BI__builtin_elementwise_log10:
2735 case Builtin::BI__builtin_elementwise_pow:
2736 case Builtin::BI__builtin_elementwise_roundeven:
2737 case Builtin::BI__builtin_elementwise_sin:
2738 case Builtin::BI__builtin_elementwise_sinh:
2739 case Builtin::BI__builtin_elementwise_sqrt:
2740 case Builtin::BI__builtin_elementwise_tan:
2741 case Builtin::BI__builtin_elementwise_tanh:
2742 case Builtin::BI__builtin_elementwise_trunc: {
2743 if (CheckAllArgTypesAreCorrect(S: &SemaRef, TheCall,
2744 Check: CheckFloatOrHalfRepresentation))
2745 return true;
2746 break;
2747 }
2748 case Builtin::BI__builtin_hlsl_buffer_update_counter: {
2749 auto checkResTy = [](const HLSLAttributedResourceType *ResTy) -> bool {
2750 return !(ResTy->getAttrs().ResourceClass == ResourceClass::UAV &&
2751 ResTy->getAttrs().RawBuffer && ResTy->hasContainedType());
2752 };
2753 if (SemaRef.checkArgCount(Call: TheCall, DesiredArgCount: 2) ||
2754 CheckResourceHandle(S: &SemaRef, TheCall, ArgIndex: 0, Check: checkResTy) ||
2755 CheckArgTypeMatches(&SemaRef, TheCall->getArg(Arg: 1),
2756 SemaRef.getASTContext().IntTy))
2757 return true;
2758 Expr *OffsetExpr = TheCall->getArg(Arg: 1);
2759 std::optional<llvm::APSInt> Offset =
2760 OffsetExpr->getIntegerConstantExpr(Ctx: SemaRef.getASTContext());
2761 if (!Offset.has_value() || std::abs(i: Offset->getExtValue()) != 1) {
2762 SemaRef.Diag(TheCall->getArg(1)->getBeginLoc(),
2763 diag::err_hlsl_expect_arg_const_int_one_or_neg_one)
2764 << 1;
2765 return true;
2766 }
2767 break;
2768 }
2769 }
2770 return false;
2771}
2772
2773static void BuildFlattenedTypeList(QualType BaseTy,
2774 llvm::SmallVectorImpl<QualType> &List) {
2775 llvm::SmallVector<QualType, 16> WorkList;
2776 WorkList.push_back(Elt: BaseTy);
2777 while (!WorkList.empty()) {
2778 QualType T = WorkList.pop_back_val();
2779 T = T.getCanonicalType().getUnqualifiedType();
2780 assert(!isa<MatrixType>(T) && "Matrix types not yet supported in HLSL");
2781 if (const auto *AT = dyn_cast<ConstantArrayType>(Val&: T)) {
2782 llvm::SmallVector<QualType, 16> ElementFields;
2783 // Generally I've avoided recursion in this algorithm, but arrays of
2784 // structs could be time-consuming to flatten and churn through on the
2785 // work list. Hopefully nesting arrays of structs containing arrays
2786 // of structs too many levels deep is unlikely.
2787 BuildFlattenedTypeList(AT->getElementType(), ElementFields);
2788 // Repeat the element's field list n times.
2789 for (uint64_t Ct = 0; Ct < AT->getZExtSize(); ++Ct)
2790 llvm::append_range(C&: List, R&: ElementFields);
2791 continue;
2792 }
2793 // Vectors can only have element types that are builtin types, so this can
2794 // add directly to the list instead of to the WorkList.
2795 if (const auto *VT = dyn_cast<VectorType>(Val&: T)) {
2796 List.insert(I: List.end(), NumToInsert: VT->getNumElements(), Elt: VT->getElementType());
2797 continue;
2798 }
2799 if (const auto *RT = dyn_cast<RecordType>(Val&: T)) {
2800 const CXXRecordDecl *RD = RT->getAsCXXRecordDecl();
2801 assert(RD && "HLSL record types should all be CXXRecordDecls!");
2802
2803 if (RD->isStandardLayout())
2804 RD = RD->getStandardLayoutBaseWithFields();
2805
2806 // For types that we shouldn't decompose (unions and non-aggregates), just
2807 // add the type itself to the list.
2808 if (RD->isUnion() || !RD->isAggregate()) {
2809 List.push_back(Elt: T);
2810 continue;
2811 }
2812
2813 llvm::SmallVector<QualType, 16> FieldTypes;
2814 for (const auto *FD : RD->fields())
2815 FieldTypes.push_back(FD->getType());
2816 // Reverse the newly added sub-range.
2817 std::reverse(first: FieldTypes.begin(), last: FieldTypes.end());
2818 llvm::append_range(C&: WorkList, R&: FieldTypes);
2819
2820 // If this wasn't a standard layout type we may also have some base
2821 // classes to deal with.
2822 if (!RD->isStandardLayout()) {
2823 FieldTypes.clear();
2824 for (const auto &Base : RD->bases())
2825 FieldTypes.push_back(Base.getType());
2826 std::reverse(first: FieldTypes.begin(), last: FieldTypes.end());
2827 llvm::append_range(C&: WorkList, R&: FieldTypes);
2828 }
2829 continue;
2830 }
2831 List.push_back(Elt: T);
2832 }
2833}
2834
2835bool SemaHLSL::IsTypedResourceElementCompatible(clang::QualType QT) {
2836 // null and array types are not allowed.
2837 if (QT.isNull() || QT->isArrayType())
2838 return false;
2839
2840 // UDT types are not allowed
2841 if (QT->isRecordType())
2842 return false;
2843
2844 if (QT->isBooleanType() || QT->isEnumeralType())
2845 return false;
2846
2847 // the only other valid builtin types are scalars or vectors
2848 if (QT->isArithmeticType()) {
2849 if (SemaRef.Context.getTypeSize(T: QT) / 8 > 16)
2850 return false;
2851 return true;
2852 }
2853
2854 if (const VectorType *VT = QT->getAs<VectorType>()) {
2855 int ArraySize = VT->getNumElements();
2856
2857 if (ArraySize > 4)
2858 return false;
2859
2860 QualType ElTy = VT->getElementType();
2861 if (ElTy->isBooleanType())
2862 return false;
2863
2864 if (SemaRef.Context.getTypeSize(T: QT) / 8 > 16)
2865 return false;
2866 return true;
2867 }
2868
2869 return false;
2870}
2871
2872bool SemaHLSL::IsScalarizedLayoutCompatible(QualType T1, QualType T2) const {
2873 if (T1.isNull() || T2.isNull())
2874 return false;
2875
2876 T1 = T1.getCanonicalType().getUnqualifiedType();
2877 T2 = T2.getCanonicalType().getUnqualifiedType();
2878
2879 // If both types are the same canonical type, they're obviously compatible.
2880 if (SemaRef.getASTContext().hasSameType(T1, T2))
2881 return true;
2882
2883 llvm::SmallVector<QualType, 16> T1Types;
2884 BuildFlattenedTypeList(BaseTy: T1, List&: T1Types);
2885 llvm::SmallVector<QualType, 16> T2Types;
2886 BuildFlattenedTypeList(BaseTy: T2, List&: T2Types);
2887
2888 // Check the flattened type list
2889 return llvm::equal(LRange&: T1Types, RRange&: T2Types,
2890 P: [this](QualType LHS, QualType RHS) -> bool {
2891 return SemaRef.IsLayoutCompatible(T1: LHS, T2: RHS);
2892 });
2893}
2894
2895bool SemaHLSL::CheckCompatibleParameterABI(FunctionDecl *New,
2896 FunctionDecl *Old) {
2897 if (New->getNumParams() != Old->getNumParams())
2898 return true;
2899
2900 bool HadError = false;
2901
2902 for (unsigned i = 0, e = New->getNumParams(); i != e; ++i) {
2903 ParmVarDecl *NewParam = New->getParamDecl(i);
2904 ParmVarDecl *OldParam = Old->getParamDecl(i);
2905
2906 // HLSL parameter declarations for inout and out must match between
2907 // declarations. In HLSL inout and out are ambiguous at the call site,
2908 // but have different calling behavior, so you cannot overload a
2909 // method based on a difference between inout and out annotations.
2910 const auto *NDAttr = NewParam->getAttr<HLSLParamModifierAttr>();
2911 unsigned NSpellingIdx = (NDAttr ? NDAttr->getSpellingListIndex() : 0);
2912 const auto *ODAttr = OldParam->getAttr<HLSLParamModifierAttr>();
2913 unsigned OSpellingIdx = (ODAttr ? ODAttr->getSpellingListIndex() : 0);
2914
2915 if (NSpellingIdx != OSpellingIdx) {
2916 SemaRef.Diag(NewParam->getLocation(),
2917 diag::err_hlsl_param_qualifier_mismatch)
2918 << NDAttr << NewParam;
2919 SemaRef.Diag(OldParam->getLocation(), diag::note_previous_declaration_as)
2920 << ODAttr;
2921 HadError = true;
2922 }
2923 }
2924 return HadError;
2925}
2926
2927// Generally follows PerformScalarCast, with cases reordered for
2928// clarity of what types are supported
2929bool SemaHLSL::CanPerformScalarCast(QualType SrcTy, QualType DestTy) {
2930
2931 if (!SrcTy->isScalarType() || !DestTy->isScalarType())
2932 return false;
2933
2934 if (SemaRef.getASTContext().hasSameUnqualifiedType(T1: SrcTy, T2: DestTy))
2935 return true;
2936
2937 switch (SrcTy->getScalarTypeKind()) {
2938 case Type::STK_Bool: // casting from bool is like casting from an integer
2939 case Type::STK_Integral:
2940 switch (DestTy->getScalarTypeKind()) {
2941 case Type::STK_Bool:
2942 case Type::STK_Integral:
2943 case Type::STK_Floating:
2944 return true;
2945 case Type::STK_CPointer:
2946 case Type::STK_ObjCObjectPointer:
2947 case Type::STK_BlockPointer:
2948 case Type::STK_MemberPointer:
2949 llvm_unreachable("HLSL doesn't support pointers.");
2950 case Type::STK_IntegralComplex:
2951 case Type::STK_FloatingComplex:
2952 llvm_unreachable("HLSL doesn't support complex types.");
2953 case Type::STK_FixedPoint:
2954 llvm_unreachable("HLSL doesn't support fixed point types.");
2955 }
2956 llvm_unreachable("Should have returned before this");
2957
2958 case Type::STK_Floating:
2959 switch (DestTy->getScalarTypeKind()) {
2960 case Type::STK_Floating:
2961 case Type::STK_Bool:
2962 case Type::STK_Integral:
2963 return true;
2964 case Type::STK_FloatingComplex:
2965 case Type::STK_IntegralComplex:
2966 llvm_unreachable("HLSL doesn't support complex types.");
2967 case Type::STK_FixedPoint:
2968 llvm_unreachable("HLSL doesn't support fixed point types.");
2969 case Type::STK_CPointer:
2970 case Type::STK_ObjCObjectPointer:
2971 case Type::STK_BlockPointer:
2972 case Type::STK_MemberPointer:
2973 llvm_unreachable("HLSL doesn't support pointers.");
2974 }
2975 llvm_unreachable("Should have returned before this");
2976
2977 case Type::STK_MemberPointer:
2978 case Type::STK_CPointer:
2979 case Type::STK_BlockPointer:
2980 case Type::STK_ObjCObjectPointer:
2981 llvm_unreachable("HLSL doesn't support pointers.");
2982
2983 case Type::STK_FixedPoint:
2984 llvm_unreachable("HLSL doesn't support fixed point types.");
2985
2986 case Type::STK_FloatingComplex:
2987 case Type::STK_IntegralComplex:
2988 llvm_unreachable("HLSL doesn't support complex types.");
2989 }
2990
2991 llvm_unreachable("Unhandled scalar cast");
2992}
2993
2994// Detect if a type contains a bitfield. Will be removed when
2995// bitfield support is added to HLSLElementwiseCast and HLSLAggregateSplatCast
2996bool SemaHLSL::ContainsBitField(QualType BaseTy) {
2997 llvm::SmallVector<QualType, 16> WorkList;
2998 WorkList.push_back(Elt: BaseTy);
2999 while (!WorkList.empty()) {
3000 QualType T = WorkList.pop_back_val();
3001 T = T.getCanonicalType().getUnqualifiedType();
3002 // only check aggregate types
3003 if (const auto *AT = dyn_cast<ConstantArrayType>(Val&: T)) {
3004 WorkList.push_back(Elt: AT->getElementType());
3005 continue;
3006 }
3007 if (const auto *RT = dyn_cast<RecordType>(Val&: T)) {
3008 const RecordDecl *RD = RT->getDecl();
3009 if (RD->isUnion())
3010 continue;
3011
3012 const CXXRecordDecl *CXXD = dyn_cast<CXXRecordDecl>(Val: RD);
3013
3014 if (CXXD && CXXD->isStandardLayout())
3015 RD = CXXD->getStandardLayoutBaseWithFields();
3016
3017 for (const auto *FD : RD->fields()) {
3018 if (FD->isBitField())
3019 return true;
3020 WorkList.push_back(Elt: FD->getType());
3021 }
3022 continue;
3023 }
3024 }
3025 return false;
3026}
3027
3028// Can perform an HLSL Aggregate splat cast if the Dest is an aggregate and the
3029// Src is a scalar or a vector of length 1
3030// Or if Dest is a vector and Src is a vector of length 1
3031bool SemaHLSL::CanPerformAggregateSplatCast(Expr *Src, QualType DestTy) {
3032
3033 QualType SrcTy = Src->getType();
3034 // Not a valid HLSL Aggregate Splat cast if Dest is a scalar or if this is
3035 // going to be a vector splat from a scalar.
3036 if ((SrcTy->isScalarType() && DestTy->isVectorType()) ||
3037 DestTy->isScalarType())
3038 return false;
3039
3040 const VectorType *SrcVecTy = SrcTy->getAs<VectorType>();
3041
3042 // Src isn't a scalar or a vector of length 1
3043 if (!SrcTy->isScalarType() && !(SrcVecTy && SrcVecTy->getNumElements() == 1))
3044 return false;
3045
3046 if (SrcVecTy)
3047 SrcTy = SrcVecTy->getElementType();
3048
3049 if (ContainsBitField(BaseTy: DestTy))
3050 return false;
3051
3052 llvm::SmallVector<QualType> DestTypes;
3053 BuildFlattenedTypeList(BaseTy: DestTy, List&: DestTypes);
3054
3055 for (unsigned I = 0, Size = DestTypes.size(); I < Size; ++I) {
3056 if (DestTypes[I]->isUnionType())
3057 return false;
3058 if (!CanPerformScalarCast(SrcTy, DestTy: DestTypes[I]))
3059 return false;
3060 }
3061 return true;
3062}
3063
3064// Can we perform an HLSL Elementwise cast?
3065// TODO: update this code when matrices are added; see issue #88060
3066bool SemaHLSL::CanPerformElementwiseCast(Expr *Src, QualType DestTy) {
3067
3068 // Don't handle casts where LHS and RHS are any combination of scalar/vector
3069 // There must be an aggregate somewhere
3070 QualType SrcTy = Src->getType();
3071 if (SrcTy->isScalarType()) // always a splat and this cast doesn't handle that
3072 return false;
3073
3074 if (SrcTy->isVectorType() &&
3075 (DestTy->isScalarType() || DestTy->isVectorType()))
3076 return false;
3077
3078 if (ContainsBitField(BaseTy: DestTy) || ContainsBitField(BaseTy: SrcTy))
3079 return false;
3080
3081 llvm::SmallVector<QualType> DestTypes;
3082 BuildFlattenedTypeList(BaseTy: DestTy, List&: DestTypes);
3083 llvm::SmallVector<QualType> SrcTypes;
3084 BuildFlattenedTypeList(BaseTy: SrcTy, List&: SrcTypes);
3085
3086 // Usually the size of SrcTypes must be greater than or equal to the size of
3087 // DestTypes.
3088 if (SrcTypes.size() < DestTypes.size())
3089 return false;
3090
3091 unsigned SrcSize = SrcTypes.size();
3092 unsigned DstSize = DestTypes.size();
3093 unsigned I;
3094 for (I = 0; I < DstSize && I < SrcSize; I++) {
3095 if (SrcTypes[I]->isUnionType() || DestTypes[I]->isUnionType())
3096 return false;
3097 if (!CanPerformScalarCast(SrcTy: SrcTypes[I], DestTy: DestTypes[I])) {
3098 return false;
3099 }
3100 }
3101
3102 // check the rest of the source type for unions.
3103 for (; I < SrcSize; I++) {
3104 if (SrcTypes[I]->isUnionType())
3105 return false;
3106 }
3107 return true;
3108}
3109
3110ExprResult SemaHLSL::ActOnOutParamExpr(ParmVarDecl *Param, Expr *Arg) {
3111 assert(Param->hasAttr<HLSLParamModifierAttr>() &&
3112 "We should not get here without a parameter modifier expression");
3113 const auto *Attr = Param->getAttr<HLSLParamModifierAttr>();
3114 if (Attr->getABI() == ParameterABI::Ordinary)
3115 return ExprResult(Arg);
3116
3117 bool IsInOut = Attr->getABI() == ParameterABI::HLSLInOut;
3118 if (!Arg->isLValue()) {
3119 SemaRef.Diag(Arg->getBeginLoc(), diag::error_hlsl_inout_lvalue)
3120 << Arg << (IsInOut ? 1 : 0);
3121 return ExprError();
3122 }
3123
3124 ASTContext &Ctx = SemaRef.getASTContext();
3125
3126 QualType Ty = Param->getType().getNonLValueExprType(Ctx);
3127
3128 // HLSL allows implicit conversions from scalars to vectors, but not the
3129 // inverse, so we need to disallow `inout` with scalar->vector or
3130 // scalar->matrix conversions.
3131 if (Arg->getType()->isScalarType() != Ty->isScalarType()) {
3132 SemaRef.Diag(Arg->getBeginLoc(), diag::error_hlsl_inout_scalar_extension)
3133 << Arg << (IsInOut ? 1 : 0);
3134 return ExprError();
3135 }
3136
3137 auto *ArgOpV = new (Ctx) OpaqueValueExpr(Param->getBeginLoc(), Arg->getType(),
3138 VK_LValue, OK_Ordinary, Arg);
3139
3140 // Parameters are initialized via copy initialization. This allows for
3141 // overload resolution of argument constructors.
3142 InitializedEntity Entity =
3143 InitializedEntity::InitializeParameter(Context&: Ctx, Type: Ty, Consumed: false);
3144 ExprResult Res =
3145 SemaRef.PerformCopyInitialization(Entity, EqualLoc: Param->getBeginLoc(), Init: ArgOpV);
3146 if (Res.isInvalid())
3147 return ExprError();
3148 Expr *Base = Res.get();
3149 // After the cast, drop the reference type when creating the exprs.
3150 Ty = Ty.getNonLValueExprType(Context: Ctx);
3151 auto *OpV = new (Ctx)
3152 OpaqueValueExpr(Param->getBeginLoc(), Ty, VK_LValue, OK_Ordinary, Base);
3153
3154 // Writebacks are performed with `=` binary operator, which allows for
3155 // overload resolution on writeback result expressions.
3156 Res = SemaRef.ActOnBinOp(S: SemaRef.getCurScope(), TokLoc: Param->getBeginLoc(),
3157 Kind: tok::equal, LHSExpr: ArgOpV, RHSExpr: OpV);
3158
3159 if (Res.isInvalid())
3160 return ExprError();
3161 Expr *Writeback = Res.get();
3162 auto *OutExpr =
3163 HLSLOutArgExpr::Create(C: Ctx, Ty, Base: ArgOpV, OpV: OpV, WB: Writeback, IsInOut);
3164
3165 return ExprResult(OutExpr);
3166}
3167
3168QualType SemaHLSL::getInoutParameterType(QualType Ty) {
3169 // If HLSL gains support for references, all the cites that use this will need
3170 // to be updated with semantic checking to produce errors for
3171 // pointers/references.
3172 assert(!Ty->isReferenceType() &&
3173 "Pointer and reference types cannot be inout or out parameters");
3174 Ty = SemaRef.getASTContext().getLValueReferenceType(T: Ty);
3175 Ty.addRestrict();
3176 return Ty;
3177}
3178
3179static bool IsDefaultBufferConstantDecl(VarDecl *VD) {
3180 QualType QT = VD->getType();
3181 return VD->getDeclContext()->isTranslationUnit() &&
3182 QT.getAddressSpace() == LangAS::Default &&
3183 VD->getStorageClass() != SC_Static &&
3184 !isInvalidConstantBufferLeafElementType(Ty: QT.getTypePtr());
3185}
3186
3187void SemaHLSL::deduceAddressSpace(VarDecl *Decl) {
3188 // The variable already has an address space (groupshared for ex).
3189 if (Decl->getType().hasAddressSpace())
3190 return;
3191
3192 if (Decl->getType()->isDependentType())
3193 return;
3194
3195 QualType Type = Decl->getType();
3196
3197 if (Decl->hasAttr<HLSLVkExtBuiltinInputAttr>()) {
3198 LangAS ImplAS = LangAS::hlsl_input;
3199 Type = SemaRef.getASTContext().getAddrSpaceQualType(T: Type, AddressSpace: ImplAS);
3200 Decl->setType(Type);
3201 return;
3202 }
3203
3204 if (Type->isSamplerT() || Type->isVoidType())
3205 return;
3206
3207 // Resource handles.
3208 if (isResourceRecordTypeOrArrayOf(Ty: Type->getUnqualifiedDesugaredType()))
3209 return;
3210
3211 // Only static globals belong to the Private address space.
3212 // Non-static globals belongs to the cbuffer.
3213 if (Decl->getStorageClass() != SC_Static && !Decl->isStaticDataMember())
3214 return;
3215
3216 LangAS ImplAS = LangAS::hlsl_private;
3217 Type = SemaRef.getASTContext().getAddrSpaceQualType(T: Type, AddressSpace: ImplAS);
3218 Decl->setType(Type);
3219}
3220
3221void SemaHLSL::ActOnVariableDeclarator(VarDecl *VD) {
3222 if (VD->hasGlobalStorage()) {
3223 // make sure the declaration has a complete type
3224 if (SemaRef.RequireCompleteType(
3225 VD->getLocation(),
3226 SemaRef.getASTContext().getBaseElementType(VD->getType()),
3227 diag::err_typecheck_decl_incomplete_type)) {
3228 VD->setInvalidDecl();
3229 deduceAddressSpace(Decl: VD);
3230 return;
3231 }
3232
3233 // Global variables outside a cbuffer block that are not a resource, static,
3234 // groupshared, or an empty array or struct belong to the default constant
3235 // buffer $Globals (to be created at the end of the translation unit).
3236 if (IsDefaultBufferConstantDecl(VD)) {
3237 // update address space to hlsl_constant
3238 QualType NewTy = getASTContext().getAddrSpaceQualType(
3239 T: VD->getType(), AddressSpace: LangAS::hlsl_constant);
3240 VD->setType(NewTy);
3241 DefaultCBufferDecls.push_back(VD);
3242 }
3243
3244 // find all resources bindings on decl
3245 if (VD->getType()->isHLSLIntangibleType())
3246 collectResourceBindingsOnVarDecl(D: VD);
3247
3248 const Type *VarType = VD->getType().getTypePtr();
3249 while (VarType->isArrayType())
3250 VarType = VarType->getArrayElementTypeNoTypeQual();
3251 if (VarType->isHLSLResourceRecord()) {
3252 // Make the variable for resources static. The global externally visible
3253 // storage is accessed through the handle, which is a member. The variable
3254 // itself is not externally visible.
3255 VD->setStorageClass(StorageClass::SC_Static);
3256 }
3257
3258 // process explicit bindings
3259 processExplicitBindingsOnDecl(D: VD);
3260 }
3261
3262 deduceAddressSpace(Decl: VD);
3263}
3264
3265static bool initVarDeclWithCtor(Sema &S, VarDecl *VD,
3266 MutableArrayRef<Expr *> Args) {
3267 InitializedEntity Entity = InitializedEntity::InitializeVariable(Var: VD);
3268 InitializationKind Kind = InitializationKind::CreateDirect(
3269 InitLoc: VD->getLocation(), LParenLoc: SourceLocation(), RParenLoc: SourceLocation());
3270
3271 InitializationSequence InitSeq(S, Entity, Kind, Args);
3272 if (InitSeq.Failed())
3273 return false;
3274
3275 ExprResult Init = InitSeq.Perform(S, Entity, Kind, Args);
3276 if (!Init.get())
3277 return false;
3278
3279 VD->setInit(S.MaybeCreateExprWithCleanups(SubExpr: Init.get()));
3280 VD->setInitStyle(VarDecl::CallInit);
3281 S.CheckCompleteVariableDeclaration(VD);
3282 return true;
3283}
3284
3285bool SemaHLSL::initGlobalResourceDecl(VarDecl *VD) {
3286 std::optional<uint32_t> RegisterSlot;
3287 uint32_t SpaceNo = 0;
3288 HLSLResourceBindingAttr *RBA = VD->getAttr<HLSLResourceBindingAttr>();
3289 if (RBA) {
3290 if (RBA->hasRegisterSlot())
3291 RegisterSlot = RBA->getSlotNumber();
3292 SpaceNo = RBA->getSpaceNumber();
3293 }
3294
3295 ASTContext &AST = SemaRef.getASTContext();
3296 uint64_t UIntTySize = AST.getTypeSize(AST.UnsignedIntTy);
3297 uint64_t IntTySize = AST.getTypeSize(AST.IntTy);
3298 IntegerLiteral *RangeSize = IntegerLiteral::Create(
3299 AST, llvm::APInt(IntTySize, 1), AST.IntTy, SourceLocation());
3300 IntegerLiteral *Index = IntegerLiteral::Create(
3301 AST, llvm::APInt(UIntTySize, 0), AST.UnsignedIntTy, SourceLocation());
3302 IntegerLiteral *Space =
3303 IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, SpaceNo),
3304 AST.UnsignedIntTy, SourceLocation());
3305 StringRef VarName = VD->getName();
3306 StringLiteral *Name = StringLiteral::Create(
3307 AST, VarName, StringLiteralKind::Ordinary, false,
3308 AST.getStringLiteralArrayType(EltTy: AST.CharTy.withConst(), Length: VarName.size()),
3309 SourceLocation());
3310
3311 // resource with explicit binding
3312 if (RegisterSlot.has_value()) {
3313 IntegerLiteral *RegSlot = IntegerLiteral::Create(
3314 AST, llvm::APInt(UIntTySize, RegisterSlot.value()), AST.UnsignedIntTy,
3315 SourceLocation());
3316 Expr *Args[] = {RegSlot, Space, RangeSize, Index, Name};
3317 return initVarDeclWithCtor(SemaRef, VD, Args);
3318 }
3319
3320 // resource with implicit binding
3321 IntegerLiteral *OrderId = IntegerLiteral::Create(
3322 AST, llvm::APInt(UIntTySize, getNextImplicitBindingOrderID()),
3323 AST.UnsignedIntTy, SourceLocation());
3324 Expr *Args[] = {Space, RangeSize, Index, OrderId, Name};
3325 return initVarDeclWithCtor(SemaRef, VD, Args);
3326}
3327
3328// Returns true if the initialization has been handled.
3329// Returns false to use default initialization.
3330bool SemaHLSL::ActOnUninitializedVarDecl(VarDecl *VD) {
3331 // Objects in the hlsl_constant address space are initialized
3332 // externally, so don't synthesize an implicit initializer.
3333 if (VD->getType().getAddressSpace() == LangAS::hlsl_constant)
3334 return true;
3335
3336 // Initialize resources
3337 if (!isResourceRecordTypeOrArrayOf(VD))
3338 return false;
3339
3340 // FIXME: We currectly support only simple resources - no arrays of resources
3341 // or resources in user defined structs.
3342 // (llvm/llvm-project#133835, llvm/llvm-project#133837)
3343 // Initialize resources at the global scope
3344 if (VD->hasGlobalStorage() && VD->getType()->isHLSLResourceRecord())
3345 return initGlobalResourceDecl(VD);
3346
3347 return false;
3348}
3349
3350// Walks though the global variable declaration, collects all resource binding
3351// requirements and adds them to Bindings
3352void SemaHLSL::collectResourceBindingsOnVarDecl(VarDecl *VD) {
3353 assert(VD->hasGlobalStorage() && VD->getType()->isHLSLIntangibleType() &&
3354 "expected global variable that contains HLSL resource");
3355
3356 // Cbuffers and Tbuffers are HLSLBufferDecl types
3357 if (const HLSLBufferDecl *CBufferOrTBuffer = dyn_cast<HLSLBufferDecl>(Val: VD)) {
3358 Bindings.addDeclBindingInfo(VD, ResClass: CBufferOrTBuffer->isCBuffer()
3359 ? ResourceClass::CBuffer
3360 : ResourceClass::SRV);
3361 return;
3362 }
3363
3364 // Unwrap arrays
3365 // FIXME: Calculate array size while unwrapping
3366 const Type *Ty = VD->getType()->getUnqualifiedDesugaredType();
3367 while (Ty->isConstantArrayType()) {
3368 const ConstantArrayType *CAT = cast<ConstantArrayType>(Val: Ty);
3369 Ty = CAT->getElementType()->getUnqualifiedDesugaredType();
3370 }
3371
3372 // Resource (or array of resources)
3373 if (const HLSLAttributedResourceType *AttrResType =
3374 HLSLAttributedResourceType::findHandleTypeOnResource(RT: Ty)) {
3375 Bindings.addDeclBindingInfo(VD, ResClass: AttrResType->getAttrs().ResourceClass);
3376 return;
3377 }
3378
3379 // User defined record type
3380 if (const RecordType *RT = dyn_cast<RecordType>(Val: Ty))
3381 collectResourceBindingsOnUserRecordDecl(VD, RT);
3382}
3383
3384// Walks though the explicit resource binding attributes on the declaration,
3385// and makes sure there is a resource that matched the binding and updates
3386// DeclBindingInfoLists
3387void SemaHLSL::processExplicitBindingsOnDecl(VarDecl *VD) {
3388 assert(VD->hasGlobalStorage() && "expected global variable");
3389
3390 bool HasBinding = false;
3391 for (Attr *A : VD->attrs()) {
3392 HLSLResourceBindingAttr *RBA = dyn_cast<HLSLResourceBindingAttr>(A);
3393 if (!RBA || !RBA->hasRegisterSlot())
3394 continue;
3395 HasBinding = true;
3396
3397 RegisterType RT = RBA->getRegisterType();
3398 assert(RT != RegisterType::I && "invalid or obsolete register type should "
3399 "never have an attribute created");
3400
3401 if (RT == RegisterType::C) {
3402 if (Bindings.hasBindingInfoForDecl(VD))
3403 SemaRef.Diag(VD->getLocation(),
3404 diag::warn_hlsl_user_defined_type_missing_member)
3405 << static_cast<int>(RT);
3406 continue;
3407 }
3408
3409 // Find DeclBindingInfo for this binding and update it, or report error
3410 // if it does not exist (user type does to contain resources with the
3411 // expected resource class).
3412 ResourceClass RC = getResourceClass(RT);
3413 if (DeclBindingInfo *BI = Bindings.getDeclBindingInfo(VD, RC)) {
3414 // update binding info
3415 BI->setBindingAttribute(RBA, BindingType::Explicit);
3416 } else {
3417 SemaRef.Diag(VD->getLocation(),
3418 diag::warn_hlsl_user_defined_type_missing_member)
3419 << static_cast<int>(RT);
3420 }
3421 }
3422
3423 if (!HasBinding && isResourceRecordTypeOrArrayOf(VD))
3424 SemaRef.Diag(VD->getLocation(), diag::warn_hlsl_implicit_binding);
3425}
3426namespace {
3427class InitListTransformer {
3428 Sema &S;
3429 ASTContext &Ctx;
3430 QualType InitTy;
3431 QualType *DstIt = nullptr;
3432 Expr **ArgIt = nullptr;
3433 // Is wrapping the destination type iterator required? This is only used for
3434 // incomplete array types where we loop over the destination type since we
3435 // don't know the full number of elements from the declaration.
3436 bool Wrap;
3437
3438 bool castInitializer(Expr *E) {
3439 assert(DstIt && "This should always be something!");
3440 if (DstIt == DestTypes.end()) {
3441 if (!Wrap) {
3442 ArgExprs.push_back(Elt: E);
3443 // This is odd, but it isn't technically a failure due to conversion, we
3444 // handle mismatched counts of arguments differently.
3445 return true;
3446 }
3447 DstIt = DestTypes.begin();
3448 }
3449 InitializedEntity Entity = InitializedEntity::InitializeParameter(
3450 Context&: Ctx, Type: *DstIt, /* Consumed (ObjC) */ Consumed: false);
3451 ExprResult Res = S.PerformCopyInitialization(Entity, EqualLoc: E->getBeginLoc(), Init: E);
3452 if (Res.isInvalid())
3453 return false;
3454 Expr *Init = Res.get();
3455 ArgExprs.push_back(Elt: Init);
3456 DstIt++;
3457 return true;
3458 }
3459
3460 bool buildInitializerListImpl(Expr *E) {
3461 // If this is an initialization list, traverse the sub initializers.
3462 if (auto *Init = dyn_cast<InitListExpr>(Val: E)) {
3463 for (auto *SubInit : Init->inits())
3464 if (!buildInitializerListImpl(E: SubInit))
3465 return false;
3466 return true;
3467 }
3468
3469 // If this is a scalar type, just enqueue the expression.
3470 QualType Ty = E->getType();
3471
3472 if (Ty->isScalarType() || (Ty->isRecordType() && !Ty->isAggregateType()))
3473 return castInitializer(E);
3474
3475 if (auto *VecTy = Ty->getAs<VectorType>()) {
3476 uint64_t Size = VecTy->getNumElements();
3477
3478 QualType SizeTy = Ctx.getSizeType();
3479 uint64_t SizeTySize = Ctx.getTypeSize(T: SizeTy);
3480 for (uint64_t I = 0; I < Size; ++I) {
3481 auto *Idx = IntegerLiteral::Create(C: Ctx, V: llvm::APInt(SizeTySize, I),
3482 type: SizeTy, l: SourceLocation());
3483
3484 ExprResult ElExpr = S.CreateBuiltinArraySubscriptExpr(
3485 Base: E, LLoc: E->getBeginLoc(), Idx, RLoc: E->getEndLoc());
3486 if (ElExpr.isInvalid())
3487 return false;
3488 if (!castInitializer(E: ElExpr.get()))
3489 return false;
3490 }
3491 return true;
3492 }
3493
3494 if (auto *ArrTy = dyn_cast<ConstantArrayType>(Val: Ty.getTypePtr())) {
3495 uint64_t Size = ArrTy->getZExtSize();
3496 QualType SizeTy = Ctx.getSizeType();
3497 uint64_t SizeTySize = Ctx.getTypeSize(T: SizeTy);
3498 for (uint64_t I = 0; I < Size; ++I) {
3499 auto *Idx = IntegerLiteral::Create(C: Ctx, V: llvm::APInt(SizeTySize, I),
3500 type: SizeTy, l: SourceLocation());
3501 ExprResult ElExpr = S.CreateBuiltinArraySubscriptExpr(
3502 Base: E, LLoc: E->getBeginLoc(), Idx, RLoc: E->getEndLoc());
3503 if (ElExpr.isInvalid())
3504 return false;
3505 if (!buildInitializerListImpl(E: ElExpr.get()))
3506 return false;
3507 }
3508 return true;
3509 }
3510
3511 if (auto *RTy = Ty->getAs<RecordType>()) {
3512 llvm::SmallVector<const RecordType *> RecordTypes;
3513 RecordTypes.push_back(Elt: RTy);
3514 while (RecordTypes.back()->getAsCXXRecordDecl()->getNumBases()) {
3515 CXXRecordDecl *D = RecordTypes.back()->getAsCXXRecordDecl();
3516 assert(D->getNumBases() == 1 &&
3517 "HLSL doesn't support multiple inheritance");
3518 RecordTypes.push_back(Elt: D->bases_begin()->getType()->getAs<RecordType>());
3519 }
3520 while (!RecordTypes.empty()) {
3521 const RecordType *RT = RecordTypes.pop_back_val();
3522 for (auto *FD : RT->getDecl()->fields()) {
3523 DeclAccessPair Found = DeclAccessPair::make(D: FD, AS: FD->getAccess());
3524 DeclarationNameInfo NameInfo(FD->getDeclName(), E->getBeginLoc());
3525 ExprResult Res = S.BuildFieldReferenceExpr(
3526 BaseExpr: E, IsArrow: false, OpLoc: E->getBeginLoc(), SS: CXXScopeSpec(), Field: FD, FoundDecl: Found, MemberNameInfo: NameInfo);
3527 if (Res.isInvalid())
3528 return false;
3529 if (!buildInitializerListImpl(E: Res.get()))
3530 return false;
3531 }
3532 }
3533 }
3534 return true;
3535 }
3536
3537 Expr *generateInitListsImpl(QualType Ty) {
3538 assert(ArgIt != ArgExprs.end() && "Something is off in iteration!");
3539 if (Ty->isScalarType() || (Ty->isRecordType() && !Ty->isAggregateType()))
3540 return *(ArgIt++);
3541
3542 llvm::SmallVector<Expr *> Inits;
3543 assert(!isa<MatrixType>(Ty) && "Matrix types not yet supported in HLSL");
3544 Ty = Ty.getDesugaredType(Context: Ctx);
3545 if (Ty->isVectorType() || Ty->isConstantArrayType()) {
3546 QualType ElTy;
3547 uint64_t Size = 0;
3548 if (auto *ATy = Ty->getAs<VectorType>()) {
3549 ElTy = ATy->getElementType();
3550 Size = ATy->getNumElements();
3551 } else {
3552 auto *VTy = cast<ConstantArrayType>(Val: Ty.getTypePtr());
3553 ElTy = VTy->getElementType();
3554 Size = VTy->getZExtSize();
3555 }
3556 for (uint64_t I = 0; I < Size; ++I)
3557 Inits.push_back(Elt: generateInitListsImpl(Ty: ElTy));
3558 }
3559 if (auto *RTy = Ty->getAs<RecordType>()) {
3560 llvm::SmallVector<const RecordType *> RecordTypes;
3561 RecordTypes.push_back(Elt: RTy);
3562 while (RecordTypes.back()->getAsCXXRecordDecl()->getNumBases()) {
3563 CXXRecordDecl *D = RecordTypes.back()->getAsCXXRecordDecl();
3564 assert(D->getNumBases() == 1 &&
3565 "HLSL doesn't support multiple inheritance");
3566 RecordTypes.push_back(Elt: D->bases_begin()->getType()->getAs<RecordType>());
3567 }
3568 while (!RecordTypes.empty()) {
3569 const RecordType *RT = RecordTypes.pop_back_val();
3570 for (auto *FD : RT->getDecl()->fields()) {
3571 Inits.push_back(Elt: generateInitListsImpl(Ty: FD->getType()));
3572 }
3573 }
3574 }
3575 auto *NewInit = new (Ctx) InitListExpr(Ctx, Inits.front()->getBeginLoc(),
3576 Inits, Inits.back()->getEndLoc());
3577 NewInit->setType(Ty);
3578 return NewInit;
3579 }
3580
3581public:
3582 llvm::SmallVector<QualType, 16> DestTypes;
3583 llvm::SmallVector<Expr *, 16> ArgExprs;
3584 InitListTransformer(Sema &SemaRef, const InitializedEntity &Entity)
3585 : S(SemaRef), Ctx(SemaRef.getASTContext()),
3586 Wrap(Entity.getType()->isIncompleteArrayType()) {
3587 InitTy = Entity.getType().getNonReferenceType();
3588 // When we're generating initializer lists for incomplete array types we
3589 // need to wrap around both when building the initializers and when
3590 // generating the final initializer lists.
3591 if (Wrap) {
3592 assert(InitTy->isIncompleteArrayType());
3593 const IncompleteArrayType *IAT = Ctx.getAsIncompleteArrayType(InitTy);
3594 InitTy = IAT->getElementType();
3595 }
3596 BuildFlattenedTypeList(InitTy, DestTypes);
3597 DstIt = DestTypes.begin();
3598 }
3599
3600 bool buildInitializerList(Expr *E) { return buildInitializerListImpl(E); }
3601
3602 Expr *generateInitLists() {
3603 assert(!ArgExprs.empty() &&
3604 "Call buildInitializerList to generate argument expressions.");
3605 ArgIt = ArgExprs.begin();
3606 if (!Wrap)
3607 return generateInitListsImpl(InitTy);
3608 llvm::SmallVector<Expr *> Inits;
3609 while (ArgIt != ArgExprs.end())
3610 Inits.push_back(generateInitListsImpl(InitTy));
3611
3612 auto *NewInit = new (Ctx) InitListExpr(Ctx, Inits.front()->getBeginLoc(),
3613 Inits, Inits.back()->getEndLoc());
3614 llvm::APInt ArySize(64, Inits.size());
3615 NewInit->setType(Ctx.getConstantArrayType(InitTy, ArySize, nullptr,
3616 ArraySizeModifier::Normal, 0));
3617 return NewInit;
3618 }
3619};
3620} // namespace
3621
3622bool SemaHLSL::transformInitList(const InitializedEntity &Entity,
3623 InitListExpr *Init) {
3624 // If the initializer is a scalar, just return it.
3625 if (Init->getType()->isScalarType())
3626 return true;
3627 ASTContext &Ctx = SemaRef.getASTContext();
3628 InitListTransformer ILT(SemaRef, Entity);
3629
3630 for (unsigned I = 0; I < Init->getNumInits(); ++I) {
3631 Expr *E = Init->getInit(Init: I);
3632 if (E->HasSideEffects(Ctx)) {
3633 QualType Ty = E->getType();
3634 if (Ty->isRecordType())
3635 E = new (Ctx) MaterializeTemporaryExpr(Ty, E, E->isLValue());
3636 E = new (Ctx) OpaqueValueExpr(E->getBeginLoc(), Ty, E->getValueKind(),
3637 E->getObjectKind(), E);
3638 Init->setInit(Init: I, expr: E);
3639 }
3640 if (!ILT.buildInitializerList(E))
3641 return false;
3642 }
3643 size_t ExpectedSize = ILT.DestTypes.size();
3644 size_t ActualSize = ILT.ArgExprs.size();
3645 // For incomplete arrays it is completely arbitrary to choose whether we think
3646 // the user intended fewer or more elements. This implementation assumes that
3647 // the user intended more, and errors that there are too few initializers to
3648 // complete the final element.
3649 if (Entity.getType()->isIncompleteArrayType())
3650 ExpectedSize =
3651 ((ActualSize + ExpectedSize - 1) / ExpectedSize) * ExpectedSize;
3652
3653 // An initializer list might be attempting to initialize a reference or
3654 // rvalue-reference. When checking the initializer we should look through
3655 // the reference.
3656 QualType InitTy = Entity.getType().getNonReferenceType();
3657 if (InitTy.hasAddressSpace())
3658 InitTy = SemaRef.getASTContext().removeAddrSpaceQualType(T: InitTy);
3659 if (ExpectedSize != ActualSize) {
3660 int TooManyOrFew = ActualSize > ExpectedSize ? 1 : 0;
3661 SemaRef.Diag(Init->getBeginLoc(), diag::err_hlsl_incorrect_num_initializers)
3662 << TooManyOrFew << InitTy << ExpectedSize << ActualSize;
3663 return false;
3664 }
3665
3666 // generateInitListsImpl will always return an InitListExpr here, because the
3667 // scalar case is handled above.
3668 auto *NewInit = cast<InitListExpr>(Val: ILT.generateInitLists());
3669 Init->resizeInits(Context: Ctx, NumInits: NewInit->getNumInits());
3670 for (unsigned I = 0; I < NewInit->getNumInits(); ++I)
3671 Init->updateInit(C: Ctx, Init: I, expr: NewInit->getInit(Init: I));
3672 return true;
3673}
3674

Provided by KDAB

Privacy Policy
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more

source code of clang/lib/Sema/SemaHLSL.cpp