clang 24.0.0git
SemaHLSL.cpp
Go to the documentation of this file.
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"
14#include "clang/AST/Attr.h"
15#include "clang/AST/Decl.h"
16#include "clang/AST/DeclBase.h"
17#include "clang/AST/DeclCXX.h"
20#include "clang/AST/Expr.h"
22#include "clang/AST/Type.h"
23#include "clang/AST/TypeBase.h"
24#include "clang/AST/TypeLoc.h"
28#include "clang/Basic/LLVM.h"
33#include "clang/Sema/Lookup.h"
35#include "clang/Sema/Sema.h"
36#include "clang/Sema/Template.h"
37#include "llvm/ADT/ArrayRef.h"
38#include "llvm/ADT/STLExtras.h"
39#include "llvm/ADT/SmallVector.h"
40#include "llvm/ADT/StringExtras.h"
41#include "llvm/ADT/StringRef.h"
42#include "llvm/ADT/Twine.h"
43#include "llvm/Frontend/HLSL/HLSLBinding.h"
44#include "llvm/Frontend/HLSL/RootSignatureValidations.h"
45#include "llvm/Support/Casting.h"
46#include "llvm/Support/DXILABI.h"
47#include "llvm/Support/ErrorHandling.h"
48#include "llvm/Support/FormatVariadic.h"
49#include "llvm/TargetParser/Triple.h"
50#include <cmath>
51#include <cstddef>
52#include <iterator>
53#include <utility>
54
55using namespace clang;
56using namespace clang::hlsl;
57using llvm::hlsl::IOType;
58using llvm::hlsl::SemanticStageInfo;
59using SemanticKind = llvm::dxbc::PSV::SemanticKind;
60using RegisterType = HLSLResourceBindingAttr::RegisterType;
61
63 CXXRecordDecl *StructDecl);
64
66 switch (RC) {
67 case ResourceClass::SRV:
68 return RegisterType::SRV;
69 case ResourceClass::UAV:
70 return RegisterType::UAV;
71 case ResourceClass::CBuffer:
72 return RegisterType::CBuffer;
73 case ResourceClass::Sampler:
74 return RegisterType::Sampler;
75 }
76 llvm_unreachable("unexpected ResourceClass value");
77}
78
79static RegisterType getRegisterType(const HLSLAttributedResourceType *ResTy) {
80 return getRegisterType(ResTy->getAttrs().ResourceClass);
81}
82
84 switch (RC) {
85 case ResourceClass::SRV:
86 case ResourceClass::UAV:
88 case ResourceClass::CBuffer:
90 case ResourceClass::Sampler:
92 }
93 llvm_unreachable("unexpected ResourceClass value");
94}
95
96// Converts the first letter of string Slot to RegisterType.
97// Returns false if the letter does not correspond to a valid register type.
98static bool convertToRegisterType(StringRef Slot, RegisterType *RT) {
99 assert(RT != nullptr);
100 switch (Slot[0]) {
101 case 't':
102 case 'T':
103 *RT = RegisterType::SRV;
104 return true;
105 case 'u':
106 case 'U':
107 *RT = RegisterType::UAV;
108 return true;
109 case 'b':
110 case 'B':
111 *RT = RegisterType::CBuffer;
112 return true;
113 case 's':
114 case 'S':
115 *RT = RegisterType::Sampler;
116 return true;
117 case 'c':
118 case 'C':
119 *RT = RegisterType::C;
120 return true;
121 case 'i':
122 case 'I':
123 *RT = RegisterType::I;
124 return true;
125 default:
126 return false;
127 }
128}
129
131 switch (RT) {
132 case RegisterType::SRV:
133 return 't';
134 case RegisterType::UAV:
135 return 'u';
136 case RegisterType::CBuffer:
137 return 'b';
138 case RegisterType::Sampler:
139 return 's';
140 case RegisterType::C:
141 return 'c';
142 case RegisterType::I:
143 return 'i';
144 }
145 llvm_unreachable("unexpected RegisterType value");
146}
147
149 switch (RT) {
150 case RegisterType::SRV:
151 return ResourceClass::SRV;
152 case RegisterType::UAV:
153 return ResourceClass::UAV;
154 case RegisterType::CBuffer:
155 return ResourceClass::CBuffer;
156 case RegisterType::Sampler:
157 return ResourceClass::Sampler;
158 case RegisterType::C:
159 case RegisterType::I:
160 // Deliberately falling through to the unreachable below.
161 break;
162 }
163 llvm_unreachable("unexpected RegisterType value");
164}
165
167 const auto *BT = dyn_cast<BuiltinType>(Type);
168 if (!BT) {
169 if (!Type->isEnumeralType())
170 return Builtin::NotBuiltin;
171 return Builtin::BI__builtin_get_spirv_spec_constant_int;
172 }
173
174 switch (BT->getKind()) {
175 case BuiltinType::Bool:
176 return Builtin::BI__builtin_get_spirv_spec_constant_bool;
177 case BuiltinType::Short:
178 return Builtin::BI__builtin_get_spirv_spec_constant_short;
179 case BuiltinType::Int:
180 return Builtin::BI__builtin_get_spirv_spec_constant_int;
181 case BuiltinType::LongLong:
182 return Builtin::BI__builtin_get_spirv_spec_constant_longlong;
183 case BuiltinType::UShort:
184 return Builtin::BI__builtin_get_spirv_spec_constant_ushort;
185 case BuiltinType::UInt:
186 return Builtin::BI__builtin_get_spirv_spec_constant_uint;
187 case BuiltinType::ULongLong:
188 return Builtin::BI__builtin_get_spirv_spec_constant_ulonglong;
189 case BuiltinType::Half:
190 return Builtin::BI__builtin_get_spirv_spec_constant_half;
191 case BuiltinType::Float:
192 return Builtin::BI__builtin_get_spirv_spec_constant_float;
193 case BuiltinType::Double:
194 return Builtin::BI__builtin_get_spirv_spec_constant_double;
195 default:
196 return Builtin::NotBuiltin;
197 }
198}
199
200static StringRef createRegisterString(ASTContext &AST, RegisterType RegType,
201 unsigned N) {
203 llvm::raw_svector_ostream OS(Buffer);
204 OS << getRegisterTypeChar(RegType);
205 OS << N;
206 return AST.backupStr(OS.str());
207}
208
210 ResourceClass ResClass) {
211 assert(getDeclBindingInfo(VD, ResClass) == nullptr &&
212 "DeclBindingInfo already added");
213 assert(!hasBindingInfoForDecl(VD) || BindingsList.back().Decl == VD);
214 // VarDecl may have multiple entries for different resource classes.
215 // DeclToBindingListIndex stores the index of the first binding we saw
216 // for this decl. If there are any additional ones then that index
217 // shouldn't be updated.
218 DeclToBindingListIndex.try_emplace(VD, BindingsList.size());
219 return &BindingsList.emplace_back(VD, ResClass);
220}
221
223 ResourceClass ResClass) {
224 auto Entry = DeclToBindingListIndex.find(VD);
225 if (Entry != DeclToBindingListIndex.end()) {
226 for (unsigned Index = Entry->getSecond();
227 Index < BindingsList.size() && BindingsList[Index].Decl == VD;
228 ++Index) {
229 if (BindingsList[Index].ResClass == ResClass)
230 return &BindingsList[Index];
231 }
232 }
233 return nullptr;
234}
235
237 return DeclToBindingListIndex.contains(VD);
238}
239
241
242Decl *SemaHLSL::ActOnStartBuffer(Scope *BufferScope, bool CBuffer,
243 SourceLocation KwLoc, IdentifierInfo *Ident,
244 SourceLocation IdentLoc,
245 SourceLocation LBrace) {
246 // For anonymous namespace, take the location of the left brace.
247 DeclContext *LexicalParent = SemaRef.getCurLexicalContext();
249 getASTContext(), LexicalParent, CBuffer, KwLoc, Ident, IdentLoc, LBrace);
250
251 // if CBuffer is false, then it's a TBuffer
252 auto RC = CBuffer ? llvm::hlsl::ResourceClass::CBuffer
253 : llvm::hlsl::ResourceClass::SRV;
254 Result->addAttr(HLSLResourceClassAttr::CreateImplicit(getASTContext(), RC));
255
256 SemaRef.PushOnScopeChains(Result, BufferScope);
257 SemaRef.PushDeclContext(BufferScope, Result);
258
259 return Result;
260}
261
262static unsigned calculateLegacyCbufferFieldAlign(const ASTContext &Context,
263 QualType T) {
264 // Arrays, Matrices, and Structs are always aligned to new buffer rows
265 if (T->isArrayType() || T->isStructureType() || T->isConstantMatrixType())
266 return 16;
267
268 // Vectors are aligned to the type they contain
269 if (const VectorType *VT = T->getAs<VectorType>())
270 return calculateLegacyCbufferFieldAlign(Context, VT->getElementType());
271
272 assert(Context.getTypeSize(T) <= 64 &&
273 "Scalar bit widths larger than 64 not supported");
274
275 // Scalar types are aligned to their byte width
276 return Context.getTypeSize(T) / 8;
277}
278
279// Calculate the size of a legacy cbuffer type in bytes based on
280// https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-packing-rules
281static unsigned calculateLegacyCbufferSize(const ASTContext &Context,
282 QualType T) {
283 constexpr unsigned CBufferAlign = 16;
284 if (const auto *RD = T->getAsRecordDecl()) {
285 unsigned Size = 0;
286 for (const FieldDecl *Field : RD->fields()) {
287 QualType Ty = Field->getType();
288 unsigned FieldSize = calculateLegacyCbufferSize(Context, Ty);
289 unsigned FieldAlign = calculateLegacyCbufferFieldAlign(Context, Ty);
290
291 // If the field crosses the row boundary after alignment it drops to the
292 // next row
293 unsigned AlignSize = llvm::alignTo(Size, FieldAlign);
294 if ((AlignSize % CBufferAlign) + FieldSize > CBufferAlign) {
295 FieldAlign = CBufferAlign;
296 }
297
298 Size = llvm::alignTo(Size, FieldAlign);
299 Size += FieldSize;
300 }
301 return Size;
302 }
303
304 if (const ConstantArrayType *AT = Context.getAsConstantArrayType(T)) {
305 unsigned ElementCount = AT->getSize().getZExtValue();
306 if (ElementCount == 0)
307 return 0;
308
309 unsigned ElementSize =
310 calculateLegacyCbufferSize(Context, AT->getElementType());
311 unsigned AlignedElementSize = llvm::alignTo(ElementSize, CBufferAlign);
312 return AlignedElementSize * (ElementCount - 1) + ElementSize;
313 }
314
315 if (const VectorType *VT = T->getAs<VectorType>()) {
316 unsigned ElementCount = VT->getNumElements();
317 unsigned ElementSize =
318 calculateLegacyCbufferSize(Context, VT->getElementType());
319 return ElementSize * ElementCount;
320 }
321
322 return Context.getTypeSize(T) / 8;
323}
324
325// Validate packoffset:
326// - if packoffset it used it must be set on all declarations inside the buffer
327// - packoffset ranges must not overlap
328static void validatePackoffset(Sema &S, HLSLBufferDecl *BufDecl) {
330
331 // Make sure the packoffset annotations are either on all declarations
332 // or on none.
333 bool HasPackOffset = false;
334 bool HasNonPackOffset = false;
335 for (auto *Field : BufDecl->buffer_decls()) {
336 VarDecl *Var = dyn_cast<VarDecl>(Field);
337 if (!Var)
338 continue;
339 if (Field->hasAttr<HLSLPackOffsetAttr>()) {
340 PackOffsetVec.emplace_back(Var, Field->getAttr<HLSLPackOffsetAttr>());
341 HasPackOffset = true;
342 } else {
343 HasNonPackOffset = true;
344 }
345 }
346
347 if (!HasPackOffset)
348 return;
349
350 if (HasNonPackOffset)
351 S.Diag(BufDecl->getLocation(), diag::warn_hlsl_packoffset_mix);
352
353 // Make sure there is no overlap in packoffset - sort PackOffsetVec by offset
354 // and compare adjacent values.
355 bool IsValid = true;
356 ASTContext &Context = S.getASTContext();
357 std::sort(PackOffsetVec.begin(), PackOffsetVec.end(),
358 [](const std::pair<VarDecl *, HLSLPackOffsetAttr *> &LHS,
359 const std::pair<VarDecl *, HLSLPackOffsetAttr *> &RHS) {
360 return LHS.second->getOffsetInBytes() <
361 RHS.second->getOffsetInBytes();
362 });
363 for (unsigned i = 0; i < PackOffsetVec.size() - 1; i++) {
364 VarDecl *Var = PackOffsetVec[i].first;
365 HLSLPackOffsetAttr *Attr = PackOffsetVec[i].second;
366 unsigned Size = calculateLegacyCbufferSize(Context, Var->getType());
367 unsigned Begin = Attr->getOffsetInBytes();
368 unsigned End = Begin + Size;
369 unsigned NextBegin = PackOffsetVec[i + 1].second->getOffsetInBytes();
370 if (End > NextBegin) {
371 VarDecl *NextVar = PackOffsetVec[i + 1].first;
372 S.Diag(NextVar->getLocation(), diag::err_hlsl_packoffset_overlap)
373 << NextVar << Var;
374 IsValid = false;
375 }
376 }
377 BufDecl->setHasValidPackoffset(IsValid);
378}
379
380// Returns true if the array has a zero size = if any of the dimensions is 0
381static bool isZeroSizedArray(const ConstantArrayType *CAT) {
382 while (CAT && !CAT->isZeroSize())
383 CAT = dyn_cast<ConstantArrayType>(
385 return CAT != nullptr;
386}
387
391
395
396static const HLSLAttributedResourceType *
398 assert(QT->isHLSLResourceRecordArray() &&
399 "expected array of resource records");
400 const Type *Ty = QT->getUnqualifiedDesugaredType();
401 while (const ArrayType *AT = dyn_cast<ArrayType>(Ty))
403 return HLSLAttributedResourceType::findHandleTypeOnResource(Ty);
404}
405
406static const HLSLAttributedResourceType *
410
411// Returns true if the type is a leaf element type that is not valid to be
412// included in HLSL Buffer, such as a resource class, empty struct, zero-sized
413// array, or a builtin intangible type. Returns false it is a valid leaf element
414// type or if it is a record type that needs to be inspected further.
418 return true;
419 if (const auto *RD = Ty->getAsCXXRecordDecl())
420 return RD->isEmpty();
421 if (Ty->isConstantArrayType() &&
423 return true;
425 return true;
426 return false;
427}
428
429// Returns true if the struct contains at least one element that prevents it
430// from being included inside HLSL Buffer as is, such as an intangible type,
431// empty struct, or zero-sized array. If it does, a new implicit layout struct
432// needs to be created for HLSL Buffer use that will exclude these unwanted
433// declarations (see createHostLayoutStruct function).
435 if (RD->isHLSLIntangible() || RD->isEmpty())
436 return true;
437 // check fields
438 for (const FieldDecl *Field : RD->fields()) {
439 QualType Ty = Field->getType();
441 return true;
442 if (const auto *RD = Ty->getAsCXXRecordDecl();
444 return true;
445 }
446 // check bases
447 for (const CXXBaseSpecifier &Base : RD->bases())
449 Base.getType()->castAsCXXRecordDecl()))
450 return true;
451 return false;
452}
453
455 DeclContext *DC) {
456 CXXRecordDecl *RD = nullptr;
457 for (NamedDecl *Decl :
459 if (CXXRecordDecl *FoundRD = dyn_cast<CXXRecordDecl>(Decl)) {
460 assert(RD == nullptr &&
461 "there should be at most 1 record by a given name in a scope");
462 RD = FoundRD;
463 }
464 }
465 return RD;
466}
467
468// Creates a name for buffer layout struct using the provide name base.
469// If the name must be unique (not previously defined), a suffix is added
470// until a unique name is found.
472 bool MustBeUnique) {
473 ASTContext &AST = S.getASTContext();
474
475 IdentifierInfo *NameBaseII = BaseDecl->getIdentifier();
476 llvm::SmallString<64> Name("__cblayout_");
477 if (NameBaseII) {
478 Name.append(NameBaseII->getName());
479 } else {
480 // anonymous struct
481 Name.append("anon");
482 MustBeUnique = true;
483 }
484
485 size_t NameLength = Name.size();
486 IdentifierInfo *II = &AST.Idents.get(Name, tok::TokenKind::identifier);
487 if (!MustBeUnique)
488 return II;
489
490 unsigned suffix = 0;
491 while (true) {
492 if (suffix != 0) {
493 Name.append("_");
494 Name.append(llvm::Twine(suffix).str());
495 II = &AST.Idents.get(Name, tok::TokenKind::identifier);
496 }
497 if (!findRecordDeclInContext(II, BaseDecl->getDeclContext()))
498 return II;
499 // declaration with that name already exists - increment suffix and try
500 // again until unique name is found
501 suffix++;
502 Name.truncate(NameLength);
503 };
504}
505
506static const Type *createHostLayoutType(Sema &S, const Type *Ty) {
507 ASTContext &AST = S.getASTContext();
508 if (auto *RD = Ty->getAsCXXRecordDecl()) {
510 return Ty;
511 RD = createHostLayoutStruct(S, RD);
512 if (!RD)
513 return nullptr;
514 return AST.getCanonicalTagType(RD)->getTypePtr();
515 }
516
517 if (const auto *CAT = dyn_cast<ConstantArrayType>(Ty)) {
518 const Type *ElementTy = createHostLayoutType(
519 S, CAT->getElementType()->getUnqualifiedDesugaredType());
520 if (!ElementTy)
521 return nullptr;
522 return AST
523 .getConstantArrayType(QualType(ElementTy, 0), CAT->getSize(), nullptr,
524 CAT->getSizeModifier(),
525 CAT->getIndexTypeCVRQualifiers())
526 .getTypePtr();
527 }
528 return Ty;
529}
530
531// Returns the type to use for a host layout struct field. For most types this
532// is the unqualified desugared type. Matrix types, however, retain their sugar
533// so that the row_major/column_major orientation (carried as an AttributedType)
534// is preserved; the orientation determines the in-memory cbuffer layout.
536 const Type *Desugared = QT->getUnqualifiedDesugaredType();
537 if (Desugared->isConstantMatrixType())
538 return QT.getTypePtr();
539 return Desugared;
540}
541
542// Creates a field declaration of given name and type for HLSL buffer layout
543// struct. Returns nullptr if the type cannot be use in HLSL Buffer layout.
545 IdentifierInfo *II,
546 CXXRecordDecl *LayoutStruct) {
548 return nullptr;
549
550 Ty = createHostLayoutType(S, Ty);
551 if (!Ty)
552 return nullptr;
553
554 QualType QT = QualType(Ty, 0);
555 ASTContext &AST = S.getASTContext();
557 auto *Field = FieldDecl::Create(AST, LayoutStruct, SourceLocation(),
558 SourceLocation(), II, QT, TSI, nullptr, false,
560 Field->setAccess(AccessSpecifier::AS_public);
561 return Field;
562}
563
564// Creates host layout struct for a struct included in HLSL Buffer.
565// The layout struct will include only fields that are allowed in HLSL buffer.
566// These fields will be filtered out:
567// - resource classes
568// - empty structs
569// - zero-sized arrays
570// Returns nullptr if the resulting layout struct would be empty.
572 CXXRecordDecl *StructDecl) {
573 assert(requiresImplicitBufferLayoutStructure(StructDecl) &&
574 "struct is already HLSL buffer compatible");
575
576 ASTContext &AST = S.getASTContext();
577 DeclContext *DC = StructDecl->getDeclContext();
578 IdentifierInfo *II = getHostLayoutStructName(S, StructDecl, false);
579
580 // reuse existing if the layout struct if it already exists
581 if (CXXRecordDecl *RD = findRecordDeclInContext(II, DC))
582 return RD;
583
584 CXXRecordDecl *LS =
585 CXXRecordDecl::Create(AST, TagDecl::TagKind::Struct, DC, SourceLocation(),
586 SourceLocation(), II);
587 LS->setImplicit(true);
588 LS->addAttr(PackedAttr::CreateImplicit(AST));
589 LS->startDefinition();
590
591 // copy base struct, create HLSL Buffer compatible version if needed
592 if (unsigned NumBases = StructDecl->getNumBases()) {
593 assert(NumBases == 1 && "HLSL supports only one base type");
594 (void)NumBases;
595 CXXBaseSpecifier Base = *StructDecl->bases_begin();
596 CXXRecordDecl *BaseDecl = Base.getType()->castAsCXXRecordDecl();
598 BaseDecl = createHostLayoutStruct(S, BaseDecl);
599 if (BaseDecl) {
600 TypeSourceInfo *TSI =
602 Base = CXXBaseSpecifier(SourceRange(), false, StructDecl->isClass(),
603 AS_none, TSI, SourceLocation());
604 }
605 }
606 if (BaseDecl) {
607 const CXXBaseSpecifier *BasesArray[1] = {&Base};
608 LS->setBases(BasesArray, 1);
609 }
610 }
611
612 // filter struct fields
613 for (const FieldDecl *FD : StructDecl->fields()) {
614 const Type *Ty = getHostLayoutFieldType(FD->getType());
615 if (FieldDecl *NewFD =
616 createFieldForHostLayoutStruct(S, Ty, FD->getIdentifier(), LS))
617 LS->addDecl(NewFD);
618 }
619 LS->completeDefinition();
620
621 if (LS->field_empty() && LS->getNumBases() == 0)
622 return nullptr;
623
624 DC->addDecl(LS);
625 return LS;
626}
627
628// Creates host layout struct for HLSL Buffer. The struct will include only
629// fields of types that are allowed in HLSL buffer and it will filter out:
630// - static or groupshared variable declarations
631// - resource classes
632// - empty structs
633// - zero-sized arrays
634// - non-variable declarations
635// The layout struct will be added to the HLSLBufferDecl declarations.
637 ASTContext &AST = S.getASTContext();
638 IdentifierInfo *II = getHostLayoutStructName(S, BufDecl, true);
639
640 CXXRecordDecl *LS =
641 CXXRecordDecl::Create(AST, TagDecl::TagKind::Struct, BufDecl,
643 LS->addAttr(PackedAttr::CreateImplicit(AST));
644 LS->setImplicit(true);
645 LS->startDefinition();
646
647 for (Decl *D : BufDecl->buffer_decls()) {
648 VarDecl *VD = dyn_cast<VarDecl>(D);
649 if (!VD || VD->getStorageClass() == SC_Static ||
651 continue;
652 const Type *Ty = getHostLayoutFieldType(VD->getType());
653
654 FieldDecl *FD =
656 // Declarations collected for the default $Globals constant buffer have
657 // already been checked to have non-empty cbuffer layout, so
658 // createFieldForHostLayoutStruct should always succeed. These declarations
659 // already have their address space set to hlsl_constant.
660 // For declarations in a named cbuffer block
661 // createFieldForHostLayoutStruct can still return nullptr if the type
662 // is empty (does not have a cbuffer layout).
663 assert((FD || VD->getType().getAddressSpace() != LangAS::hlsl_constant) &&
664 "host layout field for $Globals decl failed to be created");
665 if (FD) {
666 // Add the field decl to the layout struct.
667 LS->addDecl(FD);
669 // Update address space of the original decl to hlsl_constant.
670 QualType NewTy =
672 VD->setType(NewTy);
673 }
674 }
675 }
676 LS->completeDefinition();
677 BufDecl->addLayoutStruct(LS);
678}
679
681 uint32_t ImplicitBindingOrderID) {
682 auto *Attr =
683 HLSLResourceBindingAttr::CreateImplicit(S.getASTContext(), "", "0", {});
684 Attr->setBinding(RT, std::nullopt, 0);
685 Attr->setImplicitBindingOrderID(ImplicitBindingOrderID);
686 D->addAttr(Attr);
687}
688
689// Handle end of cbuffer/tbuffer declaration
691 auto *BufDecl = cast<HLSLBufferDecl>(Dcl);
692 BufDecl->setRBraceLoc(RBrace);
693
694 validatePackoffset(SemaRef, BufDecl);
695
697
698 // Handle implicit binding if needed.
699 ResourceBindingAttrs ResourceAttrs(Dcl);
700 if (!ResourceAttrs.isExplicit()) {
701 SemaRef.Diag(Dcl->getLocation(), diag::warn_hlsl_implicit_binding);
702 // Use HLSLResourceBindingAttr to transfer implicit binding order_ID
703 // to codegen. If it does not exist, create an implicit attribute.
704 uint32_t OrderID = getNextImplicitBindingOrderID();
705 if (ResourceAttrs.hasBinding())
706 ResourceAttrs.setImplicitOrderID(OrderID);
707 else
709 BufDecl->isCBuffer() ? RegisterType::CBuffer
710 : RegisterType::SRV,
711 OrderID);
712 }
713
714 SemaRef.PopDeclContext();
715}
716
717HLSLNumThreadsAttr *SemaHLSL::mergeNumThreadsAttr(Decl *D,
718 const AttributeCommonInfo &AL,
719 int X, int Y, int Z) {
720 if (HLSLNumThreadsAttr *NT = D->getAttr<HLSLNumThreadsAttr>()) {
721 if (NT->getX() != X || NT->getY() != Y || NT->getZ() != Z) {
722 Diag(NT->getLocation(), diag::err_hlsl_attribute_param_mismatch) << AL;
723 Diag(AL.getLoc(), diag::note_conflicting_attribute);
724 }
725 return nullptr;
726 }
727 return ::new (getASTContext())
728 HLSLNumThreadsAttr(getASTContext(), AL, X, Y, Z);
729}
730
732 const AttributeCommonInfo &AL,
733 int Min, int Max, int Preferred,
734 int SpelledArgsCount) {
735 if (HLSLWaveSizeAttr *WS = D->getAttr<HLSLWaveSizeAttr>()) {
736 if (WS->getMin() != Min || WS->getMax() != Max ||
737 WS->getPreferred() != Preferred ||
738 WS->getSpelledArgsCount() != SpelledArgsCount) {
739 Diag(WS->getLocation(), diag::err_hlsl_attribute_param_mismatch) << AL;
740 Diag(AL.getLoc(), diag::note_conflicting_attribute);
741 }
742 return nullptr;
743 }
744 HLSLWaveSizeAttr *Result = ::new (getASTContext())
745 HLSLWaveSizeAttr(getASTContext(), AL, Min, Max, Preferred);
746 Result->setSpelledArgsCount(SpelledArgsCount);
747 return Result;
748}
749
750HLSLVkConstantIdAttr *
752 int Id) {
753
755 if (TargetInfo.getTriple().getArch() != llvm::Triple::spirv) {
756 Diag(AL.getLoc(), diag::warn_attribute_ignored) << AL;
757 return nullptr;
758 }
759
760 auto *VD = cast<VarDecl>(D);
761
762 if (getSpecConstBuiltinId(VD->getType()->getUnqualifiedDesugaredType()) ==
764 Diag(VD->getLocation(), diag::err_specialization_const);
765 return nullptr;
766 }
767
768 if (!VD->getType().isConstQualified()) {
769 Diag(VD->getLocation(), diag::err_specialization_const);
770 return nullptr;
771 }
772
773 if (HLSLVkConstantIdAttr *CI = D->getAttr<HLSLVkConstantIdAttr>()) {
774 if (CI->getId() != Id) {
775 Diag(CI->getLocation(), diag::err_hlsl_attribute_param_mismatch) << AL;
776 Diag(AL.getLoc(), diag::note_conflicting_attribute);
777 }
778 return nullptr;
779 }
780
781 HLSLVkConstantIdAttr *Result =
782 ::new (getASTContext()) HLSLVkConstantIdAttr(getASTContext(), AL, Id);
783 return Result;
784}
785
786HLSLShaderAttr *
788 llvm::Triple::EnvironmentType ShaderType) {
789 if (HLSLShaderAttr *NT = D->getAttr<HLSLShaderAttr>()) {
790 if (NT->getType() != ShaderType) {
791 Diag(NT->getLocation(), diag::err_hlsl_attribute_param_mismatch) << AL;
792 Diag(AL.getLoc(), diag::note_conflicting_attribute);
793 }
794 return nullptr;
795 }
796 return HLSLShaderAttr::Create(getASTContext(), ShaderType, AL);
797}
798
799HLSLParamModifierAttr *
801 HLSLParamModifierAttr::Spelling Spelling) {
802 // We can only merge an `in` attribute with an `out` attribute. All other
803 // combinations of duplicated attributes are ill-formed.
804 if (HLSLParamModifierAttr *PA = D->getAttr<HLSLParamModifierAttr>()) {
805 if ((PA->isIn() && Spelling == HLSLParamModifierAttr::Keyword_out) ||
806 (PA->isOut() && Spelling == HLSLParamModifierAttr::Keyword_in)) {
807 D->dropAttr<HLSLParamModifierAttr>();
808 SourceRange AdjustedRange = {PA->getLocation(), AL.getRange().getEnd()};
809 return HLSLParamModifierAttr::Create(
810 getASTContext(), /*MergedSpelling=*/true, AdjustedRange,
811 HLSLParamModifierAttr::Keyword_inout);
812 }
813 Diag(AL.getLoc(), diag::err_hlsl_duplicate_parameter_modifier) << AL;
814 Diag(PA->getLocation(), diag::note_conflicting_attribute);
815 return nullptr;
816 }
817 return HLSLParamModifierAttr::Create(getASTContext(), AL);
818}
819
822
824 return;
825
826 // If we have specified a root signature to override the entry function then
827 // attach it now
828 HLSLRootSignatureDecl *SignatureDecl =
830 if (SignatureDecl) {
831 FD->dropAttr<RootSignatureAttr>();
832 // We could look up the SourceRange of the macro here as well
833 AttributeCommonInfo AL(RootSigOverrideIdent, AttributeScopeInfo(),
834 SourceRange(), ParsedAttr::Form::Microsoft());
835 FD->addAttr(::new (getASTContext()) RootSignatureAttr(
836 getASTContext(), AL, RootSigOverrideIdent, SignatureDecl));
837 }
838
839 llvm::Triple::EnvironmentType Env = TargetInfo.getTriple().getEnvironment();
840 if (HLSLShaderAttr::isValidShaderType(Env) && Env != llvm::Triple::Library) {
841 if (const auto *Shader = FD->getAttr<HLSLShaderAttr>()) {
842 // The entry point is already annotated - check that it matches the
843 // triple.
844 if (Shader->getType() != Env) {
845 Diag(Shader->getLocation(), diag::err_hlsl_entry_shader_attr_mismatch)
846 << Shader;
847 FD->setInvalidDecl();
848 }
849 } else {
850 // Implicitly add the shader attribute if the entry function isn't
851 // explicitly annotated.
852 FD->addAttr(HLSLShaderAttr::CreateImplicit(getASTContext(), Env,
853 FD->getBeginLoc()));
854 }
855 } else {
856 switch (Env) {
857 case llvm::Triple::UnknownEnvironment:
858 case llvm::Triple::Library:
859 break;
860 case llvm::Triple::RootSignature:
861 llvm_unreachable("rootsig environment has no functions");
862 default:
863 llvm_unreachable("Unhandled environment in triple");
864 }
865 }
866}
867
868static bool isVkPipelineBuiltin(const ASTContext &AstContext, FunctionDecl *FD,
869 HLSLAppliedSemanticAttr *Semantic,
870 bool IsInput) {
871 if (AstContext.getTargetInfo().getTriple().getOS() != llvm::Triple::Vulkan)
872 return false;
873
874 const auto *ShaderAttr = FD->getAttr<HLSLShaderAttr>();
875 assert(ShaderAttr && "Entry point has no shader attribute");
876 llvm::Triple::EnvironmentType ST = ShaderAttr->getType();
877 SemanticKind Kind = llvm::hlsl::getSemanticKind(Semantic->getSemanticName());
878
879 switch (Kind) {
880 case SemanticKind::Position:
881 // The SV_Position semantic is lowered to:
882 // - Position built-in for vertex output.
883 // - FragCoord built-in for fragment input.
884 return (ST == llvm::Triple::Vertex && !IsInput) ||
885 (ST == llvm::Triple::Pixel && IsInput);
886 case SemanticKind::VertexID:
887 return true;
888 case SemanticKind::InstanceID:
889 return ST == llvm::Triple::Vertex && IsInput;
890 default:
891 return false;
892 }
893}
894
895bool SemaHLSL::determineActiveSemanticOnScalar(FunctionDecl *FD,
896 DeclaratorDecl *OutputDecl,
898 SemanticInfo &ActiveSemantic,
899 SemaHLSL::SemanticContext &SC) {
900 if (ActiveSemantic.Semantic == nullptr) {
901 ActiveSemantic.Semantic = D->getAttr<HLSLParsedSemanticAttr>();
902 if (ActiveSemantic.Semantic)
903 ActiveSemantic.Index = ActiveSemantic.Semantic->getSemanticIndex();
904 }
905
906 if (!ActiveSemantic.Semantic) {
907 Diag(D->getLocation(), diag::err_hlsl_missing_semantic_annotation);
908 return false;
909 }
910
911 auto *A = ::new (getASTContext())
912 HLSLAppliedSemanticAttr(getASTContext(), *ActiveSemantic.Semantic,
913 ActiveSemantic.Semantic->getAttrName()->getName(),
914 ActiveSemantic.Index.value_or(0));
915 if (!A)
917
918 checkSemanticAnnotation(FD, D, A, SC);
919 OutputDecl->addAttr(A);
920
921 unsigned Location = ActiveSemantic.Index.value_or(0);
922
924 any(SC.CurrentIOType & IOType::In))) {
925 bool HasVkLocation = false;
926 if (auto *A = D->getAttr<HLSLVkLocationAttr>()) {
927 HasVkLocation = true;
928 Location = A->getLocation();
929 }
930
931 if (SC.UsesExplicitVkLocations.value_or(HasVkLocation) != HasVkLocation) {
932 Diag(D->getLocation(), diag::err_hlsl_semantic_partial_explicit_indexing);
933 return false;
934 }
935 SC.UsesExplicitVkLocations = HasVkLocation;
936 }
937
938 const ConstantArrayType *AT = dyn_cast<ConstantArrayType>(D->getType());
939 unsigned ElementCount = AT ? AT->getZExtSize() : 1;
940 ActiveSemantic.Index = Location + ElementCount;
941
942 Twine BaseName = Twine(ActiveSemantic.Semantic->getAttrName()->getName());
943 for (unsigned I = 0; I < ElementCount; ++I) {
944 Twine VariableName = BaseName.concat(Twine(Location + I));
945
946 auto [_, Inserted] = SC.ActiveSemantics.insert(VariableName.str());
947 if (!Inserted) {
948 Diag(D->getLocation(), diag::err_hlsl_semantic_index_overlap)
949 << VariableName.str();
950 return false;
951 }
952 }
953
954 return true;
955}
956
957bool SemaHLSL::determineActiveSemantic(FunctionDecl *FD,
958 DeclaratorDecl *OutputDecl,
960 SemanticInfo &ActiveSemantic,
961 SemaHLSL::SemanticContext &SC) {
962 if (ActiveSemantic.Semantic == nullptr) {
963 ActiveSemantic.Semantic = D->getAttr<HLSLParsedSemanticAttr>();
964 if (ActiveSemantic.Semantic)
965 ActiveSemantic.Index = ActiveSemantic.Semantic->getSemanticIndex();
966 }
967
968 const Type *T = D == FD ? &*FD->getReturnType() : &*D->getType();
970
971 const RecordType *RT = dyn_cast<RecordType>(T);
972 if (!RT)
973 return determineActiveSemanticOnScalar(FD, OutputDecl, D, ActiveSemantic,
974 SC);
975
976 const RecordDecl *RD = RT->getDecl();
977 for (FieldDecl *Field : RD->fields()) {
978 SemanticInfo Info = ActiveSemantic;
979 if (!determineActiveSemantic(FD, OutputDecl, Field, Info, SC)) {
980 Diag(Field->getLocation(), diag::note_hlsl_semantic_used_here) << Field;
981 return false;
982 }
983 if (ActiveSemantic.Semantic)
984 ActiveSemantic = Info;
985 }
986
987 return true;
988}
989
991 const auto *ShaderAttr = FD->getAttr<HLSLShaderAttr>();
992 assert(ShaderAttr && "Entry point has no shader attribute");
993 llvm::Triple::EnvironmentType ST = ShaderAttr->getType();
995 VersionTuple Ver = TargetInfo.getTriple().getOSVersion();
996 switch (ST) {
997 case llvm::Triple::Pixel:
998 case llvm::Triple::Vertex:
999 case llvm::Triple::Geometry:
1000 case llvm::Triple::Hull:
1001 case llvm::Triple::Domain:
1002 case llvm::Triple::RayGeneration:
1003 case llvm::Triple::Intersection:
1004 case llvm::Triple::AnyHit:
1005 case llvm::Triple::ClosestHit:
1006 case llvm::Triple::Miss:
1007 case llvm::Triple::Callable:
1008 if (const auto *NT = FD->getAttr<HLSLNumThreadsAttr>()) {
1009 diagnoseAttrStageMismatch(NT, ST,
1010 {llvm::Triple::Compute,
1011 llvm::Triple::Amplification,
1012 llvm::Triple::Mesh});
1013 FD->setInvalidDecl();
1014 }
1015 if (const auto *WS = FD->getAttr<HLSLWaveSizeAttr>()) {
1016 diagnoseAttrStageMismatch(WS, ST,
1017 {llvm::Triple::Compute,
1018 llvm::Triple::Amplification,
1019 llvm::Triple::Mesh});
1020 FD->setInvalidDecl();
1021 }
1022 break;
1023
1024 case llvm::Triple::Compute:
1025 case llvm::Triple::Amplification:
1026 case llvm::Triple::Mesh:
1027 if (!FD->hasAttr<HLSLNumThreadsAttr>()) {
1028 Diag(FD->getLocation(), diag::err_hlsl_missing_numthreads)
1029 << llvm::Triple::getEnvironmentTypeName(ST);
1030 FD->setInvalidDecl();
1031 }
1032 if (const auto *WS = FD->getAttr<HLSLWaveSizeAttr>()) {
1033 if (TargetInfo.getTriple().isSPIRV()) {
1034 Diag(WS->getLocation(), diag::warn_hlsl_wavesize_unsupported_spirv);
1035 } else if (Ver < VersionTuple(6, 6)) {
1036 Diag(WS->getLocation(), diag::err_hlsl_attribute_in_wrong_shader_model)
1037 << WS << "6.6";
1038 FD->setInvalidDecl();
1039 } else if (WS->getSpelledArgsCount() > 1 && Ver < VersionTuple(6, 8)) {
1040 Diag(
1041 WS->getLocation(),
1042 diag::err_hlsl_attribute_number_arguments_insufficient_shader_model)
1043 << WS << WS->getSpelledArgsCount() << "6.8";
1044 FD->setInvalidDecl();
1045 }
1046 }
1047 break;
1048 case llvm::Triple::RootSignature:
1049 llvm_unreachable("rootsig environment has no function entry point");
1050 default:
1051 llvm_unreachable("Unhandled environment in triple");
1052 }
1053
1054 SemaHLSL::SemanticContext InputSC = {};
1055 InputSC.CurrentIOType = IOType::In;
1056 SemaHLSL::SemanticContext OutputSC = {};
1057 OutputSC.CurrentIOType = IOType::Out;
1058
1059 for (ParmVarDecl *Param : FD->parameters()) {
1060 SemanticInfo ActiveSemantic;
1061 ActiveSemantic.Semantic = Param->getAttr<HLSLParsedSemanticAttr>();
1062 if (ActiveSemantic.Semantic)
1063 ActiveSemantic.Index = ActiveSemantic.Semantic->getSemanticIndex();
1064
1065 // FIXME: An `inout` parameter is part of both signatures, but it is only
1066 // verified against the output one here.
1067 const auto *MA = Param->getAttr<HLSLParamModifierAttr>();
1068 SemanticContext &SC = MA && MA->isAnyOut() ? OutputSC : InputSC;
1069
1070 if (!determineActiveSemantic(FD, Param, Param, ActiveSemantic, SC)) {
1071 Diag(Param->getLocation(), diag::note_previous_decl) << Param;
1072 FD->setInvalidDecl();
1073 }
1074 }
1075
1076 SemanticInfo ActiveSemantic;
1077 ActiveSemantic.Semantic = FD->getAttr<HLSLParsedSemanticAttr>();
1078 if (ActiveSemantic.Semantic)
1079 ActiveSemantic.Index = ActiveSemantic.Semantic->getSemanticIndex();
1080 if (!FD->getReturnType()->isVoidType())
1081 determineActiveSemantic(FD, FD, FD, ActiveSemantic, OutputSC);
1082}
1083
1084void SemaHLSL::checkSemanticAnnotation(
1085 FunctionDecl *EntryPoint, const Decl *Param,
1086 const HLSLAppliedSemanticAttr *SemanticAttr, const SemanticContext &SC) {
1087 auto *ShaderAttr = EntryPoint->getAttr<HLSLShaderAttr>();
1088 assert(ShaderAttr && "Entry point has no shader attribute");
1089 llvm::Triple::EnvironmentType ST = ShaderAttr->getType();
1090
1091 SemanticKind Kind =
1092 llvm::hlsl::getSemanticKind(SemanticAttr->getSemanticName());
1093 llvm::hlsl::SemanticInterpretation Interpretation =
1094 llvm::hlsl::getInterpretationKind(Kind, ST, SC.CurrentIOType);
1095 if (Interpretation == llvm::hlsl::SemanticInterpretation::Invalid)
1096 diagnoseSemanticStageMismatch(SemanticAttr, ST, SC.CurrentIOType, Kind);
1097
1098 switch (Kind) {
1099 case SemanticKind::DispatchThreadID:
1100 case SemanticKind::GroupID:
1101 case SemanticKind::GroupIndex:
1102 case SemanticKind::GroupThreadID:
1103 case SemanticKind::InstanceID:
1104 if (SemanticAttr->getSemanticIndex() != 0) {
1105 std::string PrettyName =
1106 "'" + SemanticAttr->getSemanticName().str() + "'";
1107 Diag(SemanticAttr->getLoc(),
1108 diag::err_hlsl_semantic_indexing_not_supported)
1109 << PrettyName;
1110 }
1111 break;
1112 default:
1113 break;
1114 }
1115}
1116
1117void SemaHLSL::diagnoseAttrStageMismatch(
1118 const Attr *A, llvm::Triple::EnvironmentType Stage,
1119 std::initializer_list<llvm::Triple::EnvironmentType> AllowedStages) {
1120 SmallVector<StringRef, 8> StageStrings;
1121 llvm::transform(AllowedStages, std::back_inserter(StageStrings),
1122 [](llvm::Triple::EnvironmentType ST) {
1123 return StringRef(
1124 HLSLShaderAttr::ConvertEnvironmentTypeToStr(ST));
1125 });
1126 Diag(A->getLoc(), diag::err_hlsl_attr_unsupported_in_stage)
1127 << A->getAttrName() << llvm::Triple::getEnvironmentTypeName(Stage)
1128 << (AllowedStages.size() != 1) << join(StageStrings, ", ");
1129}
1130
1131void SemaHLSL::diagnoseSemanticStageMismatch(
1132 const Attr *A, llvm::Triple::EnvironmentType Stage, IOType CurrentIOType,
1133 SemanticKind Kind) {
1134
1135 ArrayRef<SemanticStageInfo> Allowed = llvm::hlsl::getAvailableStages(Kind);
1136 auto It = llvm::find_if(Allowed, [&Stage](const SemanticStageInfo &Info) {
1137 return Info.Stage == Stage;
1138 });
1139
1140 StringRef CurrentIOTypeName = "patch constants or primitives";
1141 if (any(CurrentIOType & IOType::In))
1142 CurrentIOTypeName = "inputs";
1143 else if (any(CurrentIOType & IOType::Out))
1144 CurrentIOTypeName = "outputs";
1145
1146 // The semantic is not available in this shader stage at all.
1147 if (It == Allowed.end()) {
1148 Diag(A->getLoc(), diag::err_hlsl_semantic_unsupported_iotype_for_stage)
1149 << A->getAttrName() << llvm::Triple::getEnvironmentTypeName(Stage)
1150 << CurrentIOTypeName;
1151 return;
1152 }
1153
1154 IOType AllowedIOTypes = It->AllowedIOTypesMask;
1155 if (!(AllowedIOTypes & CurrentIOType)) {
1156 Diag(A->getLoc(), diag::err_hlsl_semantic_unsupported_iotype_for_stage)
1157 << A->getAttrName() << llvm::Triple::getEnvironmentTypeName(Stage)
1158 << CurrentIOTypeName;
1159 return;
1160 }
1161}
1162
1163template <CastKind Kind>
1164static void castVector(Sema &S, ExprResult &E, QualType &Ty, unsigned Sz) {
1165 if (const auto *VTy = Ty->getAs<VectorType>())
1166 Ty = VTy->getElementType();
1167 Ty = S.getASTContext().getExtVectorType(Ty, Sz);
1168 E = S.ImpCastExprToType(E.get(), Ty, Kind);
1169}
1170
1171template <CastKind Kind>
1173 E = S.ImpCastExprToType(E.get(), Ty, Kind);
1174 return Ty;
1175}
1176
1178 Sema &SemaRef, ExprResult &LHS, ExprResult &RHS, QualType LHSType,
1179 QualType RHSType, QualType LElTy, QualType RElTy, bool IsCompAssign) {
1180 bool LHSFloat = LElTy->isRealFloatingType();
1181 bool RHSFloat = RElTy->isRealFloatingType();
1182
1183 if (LHSFloat && RHSFloat) {
1184 if (IsCompAssign ||
1185 SemaRef.getASTContext().getFloatingTypeOrder(LElTy, RElTy) > 0)
1186 return castElement<CK_FloatingCast>(SemaRef, RHS, LHSType);
1187
1188 return castElement<CK_FloatingCast>(SemaRef, LHS, RHSType);
1189 }
1190
1191 if (LHSFloat)
1192 return castElement<CK_IntegralToFloating>(SemaRef, RHS, LHSType);
1193
1194 assert(RHSFloat);
1195 if (IsCompAssign)
1196 return castElement<clang::CK_FloatingToIntegral>(SemaRef, RHS, LHSType);
1197
1198 return castElement<CK_IntegralToFloating>(SemaRef, LHS, RHSType);
1199}
1200
1202 Sema &SemaRef, ExprResult &LHS, ExprResult &RHS, QualType LHSType,
1203 QualType RHSType, QualType LElTy, QualType RElTy, bool IsCompAssign) {
1204
1205 int IntOrder = SemaRef.Context.getIntegerTypeOrder(LElTy, RElTy);
1206 bool LHSSigned = LElTy->hasSignedIntegerRepresentation();
1207 bool RHSSigned = RElTy->hasSignedIntegerRepresentation();
1208 auto &Ctx = SemaRef.getASTContext();
1209
1210 // If both types have the same signedness, use the higher ranked type.
1211 if (LHSSigned == RHSSigned) {
1212 if (IsCompAssign || IntOrder >= 0)
1213 return castElement<CK_IntegralCast>(SemaRef, RHS, LHSType);
1214
1215 return castElement<CK_IntegralCast>(SemaRef, LHS, RHSType);
1216 }
1217
1218 // If the unsigned type has greater than or equal rank of the signed type, use
1219 // the unsigned type.
1220 if (IntOrder != (LHSSigned ? 1 : -1)) {
1221 if (IsCompAssign || RHSSigned)
1222 return castElement<CK_IntegralCast>(SemaRef, RHS, LHSType);
1223 return castElement<CK_IntegralCast>(SemaRef, LHS, RHSType);
1224 }
1225
1226 // At this point the signed type has higher rank than the unsigned type, which
1227 // means it will be the same size or bigger. If the signed type is bigger, it
1228 // can represent all the values of the unsigned type, so select it.
1229 if (Ctx.getIntWidth(LElTy) != Ctx.getIntWidth(RElTy)) {
1230 if (IsCompAssign || LHSSigned)
1231 return castElement<CK_IntegralCast>(SemaRef, RHS, LHSType);
1232 return castElement<CK_IntegralCast>(SemaRef, LHS, RHSType);
1233 }
1234
1235 // This is a bit of an odd duck case in HLSL. It shouldn't happen, but can due
1236 // to C/C++ leaking through. The place this happens today is long vs long
1237 // long. When arguments are vector<unsigned long, N> and vector<long long, N>,
1238 // the long long has higher rank than long even though they are the same size.
1239
1240 // If this is a compound assignment cast the right hand side to the left hand
1241 // side's type.
1242 if (IsCompAssign)
1243 return castElement<CK_IntegralCast>(SemaRef, RHS, LHSType);
1244
1245 // If this isn't a compound assignment we convert to unsigned long long.
1246 QualType ElTy = Ctx.getCorrespondingUnsignedType(LHSSigned ? LElTy : RElTy);
1247 QualType NewTy = Ctx.getExtVectorType(
1248 ElTy, RHSType->castAs<VectorType>()->getNumElements());
1249 (void)castElement<CK_IntegralCast>(SemaRef, RHS, NewTy);
1250
1251 return castElement<CK_IntegralCast>(SemaRef, LHS, NewTy);
1252}
1253
1255 QualType SrcTy) {
1256 if (DestTy->isRealFloatingType() && SrcTy->isRealFloatingType())
1257 return CK_FloatingCast;
1258 if (DestTy->isIntegralType(Ctx) && SrcTy->isIntegralType(Ctx))
1259 return CK_IntegralCast;
1260 if (DestTy->isRealFloatingType())
1261 return CK_IntegralToFloating;
1262 assert(SrcTy->isRealFloatingType() && DestTy->isIntegralType(Ctx));
1263 return CK_FloatingToIntegral;
1264}
1265
1267 QualType LHSType,
1268 QualType RHSType,
1269 bool IsCompAssign) {
1270 const auto *LVecTy = LHSType->getAs<VectorType>();
1271 const auto *RVecTy = RHSType->getAs<VectorType>();
1272 auto &Ctx = getASTContext();
1273
1274 // If the LHS is not a vector and this is a compound assignment, we truncate
1275 // the argument to a scalar then convert it to the LHS's type.
1276 if (!LVecTy && IsCompAssign) {
1277 QualType RElTy = RHSType->castAs<VectorType>()->getElementType();
1278 RHS = SemaRef.ImpCastExprToType(RHS.get(), RElTy, CK_HLSLVectorTruncation);
1279 RHSType = RHS.get()->getType();
1280 if (Ctx.hasSameUnqualifiedType(LHSType, RHSType))
1281 return LHSType;
1282 RHS = SemaRef.ImpCastExprToType(RHS.get(), LHSType,
1283 getScalarCastKind(Ctx, LHSType, RHSType));
1284 return LHSType;
1285 }
1286
1287 unsigned EndSz = std::numeric_limits<unsigned>::max();
1288 unsigned LSz = 0;
1289 if (LVecTy)
1290 LSz = EndSz = LVecTy->getNumElements();
1291 if (RVecTy)
1292 EndSz = std::min(RVecTy->getNumElements(), EndSz);
1293 assert(EndSz != std::numeric_limits<unsigned>::max() &&
1294 "one of the above should have had a value");
1295
1296 // In a compound assignment, the left operand does not change type, the right
1297 // operand is converted to the type of the left operand.
1298 if (IsCompAssign && LSz != EndSz) {
1299 Diag(LHS.get()->getBeginLoc(),
1300 diag::err_hlsl_vector_compound_assignment_truncation)
1301 << LHSType << RHSType;
1302 return QualType();
1303 }
1304
1305 if (RVecTy && RVecTy->getNumElements() > EndSz)
1306 castVector<CK_HLSLVectorTruncation>(SemaRef, RHS, RHSType, EndSz);
1307 if (!IsCompAssign && LVecTy && LVecTy->getNumElements() > EndSz)
1308 castVector<CK_HLSLVectorTruncation>(SemaRef, LHS, LHSType, EndSz);
1309
1310 if (!RVecTy)
1311 castVector<CK_VectorSplat>(SemaRef, RHS, RHSType, EndSz);
1312 if (!IsCompAssign && !LVecTy)
1313 castVector<CK_VectorSplat>(SemaRef, LHS, LHSType, EndSz);
1314
1315 // If we're at the same type after resizing we can stop here.
1316 if (Ctx.hasSameUnqualifiedType(LHSType, RHSType))
1317 return Ctx.getCommonSugaredType(LHSType, RHSType);
1318
1319 QualType LElTy = LHSType->castAs<VectorType>()->getElementType();
1320 QualType RElTy = RHSType->castAs<VectorType>()->getElementType();
1321
1322 // Handle conversion for floating point vectors.
1323 if (LElTy->isRealFloatingType() || RElTy->isRealFloatingType())
1324 return handleFloatVectorBinOpConversion(SemaRef, LHS, RHS, LHSType, RHSType,
1325 LElTy, RElTy, IsCompAssign);
1326
1327 assert(LElTy->isIntegralType(Ctx) && RElTy->isIntegralType(Ctx) &&
1328 "HLSL Vectors can only contain integer or floating point types");
1329 return handleIntegerVectorBinOpConversion(SemaRef, LHS, RHS, LHSType, RHSType,
1330 LElTy, RElTy, IsCompAssign);
1331}
1332
1334 BinaryOperatorKind Opc) {
1335 assert((Opc == BO_LOr || Opc == BO_LAnd) &&
1336 "Called with non-logical operator");
1338 llvm::raw_svector_ostream OS(Buff);
1339 PrintingPolicy PP(SemaRef.getLangOpts());
1340 StringRef NewFnName = Opc == BO_LOr ? "or" : "and";
1341 OS << NewFnName << "(";
1342 LHS->printPretty(OS, nullptr, PP);
1343 OS << ", ";
1344 RHS->printPretty(OS, nullptr, PP);
1345 OS << ")";
1346 SourceRange FullRange = SourceRange(LHS->getBeginLoc(), RHS->getEndLoc());
1347 SemaRef.Diag(LHS->getBeginLoc(), diag::note_function_suggestion)
1348 << NewFnName << FixItHint::CreateReplacement(FullRange, OS.str());
1349}
1350
1351std::pair<IdentifierInfo *, bool>
1353 llvm::hash_code Hash = llvm::hash_value(Signature);
1354 std::string IdStr = "__hlsl_rootsig_decl_" + std::to_string(Hash);
1355 IdentifierInfo *DeclIdent = &(getASTContext().Idents.get(IdStr));
1356
1357 // Check if we have already found a decl of the same name.
1358 LookupResult R(SemaRef, DeclIdent, SourceLocation(),
1360 bool Found = SemaRef.LookupQualifiedName(R, SemaRef.CurContext);
1361 return {DeclIdent, Found};
1362}
1363
1365 SourceLocation Loc, IdentifierInfo *DeclIdent,
1367
1368 if (handleRootSignatureElements(RootElements))
1369 return;
1370
1372 for (auto &RootSigElement : RootElements)
1373 Elements.push_back(RootSigElement.getElement());
1374
1375 auto *SignatureDecl = HLSLRootSignatureDecl::Create(
1376 SemaRef.getASTContext(), /*DeclContext=*/SemaRef.CurContext, Loc,
1377 DeclIdent, SemaRef.getLangOpts().HLSLRootSigVer, Elements);
1378
1379 SignatureDecl->setImplicit();
1380 SemaRef.PushOnScopeChains(SignatureDecl, SemaRef.getCurScope());
1381}
1382
1385 if (RootSigOverrideIdent) {
1386 LookupResult R(SemaRef, RootSigOverrideIdent, SourceLocation(),
1388 if (SemaRef.LookupQualifiedName(R, DC))
1389 return dyn_cast<HLSLRootSignatureDecl>(R.getFoundDecl());
1390 }
1391
1392 return nullptr;
1393}
1394
1395namespace {
1396
1397struct PerVisibilityBindingChecker {
1398 SemaHLSL *S;
1399 // We need one builder per `llvm::dxbc::ShaderVisibility` value.
1400 std::array<llvm::hlsl::BindingInfoBuilder, 8> Builders;
1401
1402 struct ElemInfo {
1403 const hlsl::RootSignatureElement *Elem;
1404 llvm::dxbc::ShaderVisibility Vis;
1405 bool Diagnosed;
1406 };
1407 llvm::SmallVector<ElemInfo> ElemInfoMap;
1408
1409 PerVisibilityBindingChecker(SemaHLSL *S) : S(S) {}
1410
1411 void trackBinding(llvm::dxbc::ShaderVisibility Visibility,
1412 llvm::dxil::ResourceClass RC, uint32_t Space,
1413 uint32_t LowerBound, uint32_t UpperBound,
1414 const hlsl::RootSignatureElement *Elem) {
1415 uint32_t BuilderIndex = llvm::to_underlying(Visibility);
1416 assert(BuilderIndex < Builders.size() &&
1417 "Not enough builders for visibility type");
1418 Builders[BuilderIndex].trackBinding(RC, Space, LowerBound, UpperBound,
1419 static_cast<const void *>(Elem));
1420
1421 static_assert(llvm::to_underlying(llvm::dxbc::ShaderVisibility::All) == 0,
1422 "'All' visibility must come first");
1423 if (Visibility == llvm::dxbc::ShaderVisibility::All)
1424 for (size_t I = 1, E = Builders.size(); I < E; ++I)
1425 Builders[I].trackBinding(RC, Space, LowerBound, UpperBound,
1426 static_cast<const void *>(Elem));
1427
1428 ElemInfoMap.push_back({Elem, Visibility, false});
1429 }
1430
1431 ElemInfo &getInfo(const hlsl::RootSignatureElement *Elem) {
1432 auto It = llvm::lower_bound(
1433 ElemInfoMap, Elem,
1434 [](const auto &LHS, const auto &RHS) { return LHS.Elem < RHS; });
1435 assert(It->Elem == Elem && "Element not in map");
1436 return *It;
1437 }
1438
1439 bool checkOverlap() {
1440 llvm::sort(ElemInfoMap, [](const auto &LHS, const auto &RHS) {
1441 return LHS.Elem < RHS.Elem;
1442 });
1443
1444 bool HadOverlap = false;
1445
1446 using llvm::hlsl::BindingInfoBuilder;
1447 auto ReportOverlap = [this,
1448 &HadOverlap](const BindingInfoBuilder &Builder,
1449 const llvm::hlsl::Binding &Reported) {
1450 HadOverlap = true;
1451
1452 const auto *Elem =
1453 static_cast<const hlsl::RootSignatureElement *>(Reported.Cookie);
1454 const llvm::hlsl::Binding &Previous = Builder.findOverlapping(Reported);
1455 const auto *PrevElem =
1456 static_cast<const hlsl::RootSignatureElement *>(Previous.Cookie);
1457
1458 ElemInfo &Info = getInfo(Elem);
1459 // We will have already diagnosed this binding if there's overlap in the
1460 // "All" visibility as well as any particular visibility.
1461 if (Info.Diagnosed)
1462 return;
1463 Info.Diagnosed = true;
1464
1465 ElemInfo &PrevInfo = getInfo(PrevElem);
1466 llvm::dxbc::ShaderVisibility CommonVis =
1467 Info.Vis == llvm::dxbc::ShaderVisibility::All ? PrevInfo.Vis
1468 : Info.Vis;
1469
1470 this->S->Diag(Elem->getLocation(), diag::err_hlsl_resource_range_overlap)
1471 << llvm::to_underlying(Reported.RC) << Reported.LowerBound
1472 << Reported.isUnbounded() << Reported.UpperBound
1473 << llvm::to_underlying(Previous.RC) << Previous.LowerBound
1474 << Previous.isUnbounded() << Previous.UpperBound << Reported.Space
1475 << CommonVis;
1476
1477 this->S->Diag(PrevElem->getLocation(),
1478 diag::note_hlsl_resource_range_here);
1479 };
1480
1481 for (BindingInfoBuilder &Builder : Builders)
1482 Builder.calculateBindingInfo(ReportOverlap);
1483
1484 return HadOverlap;
1485 }
1486};
1487
1488static CXXMethodDecl *lookupMethod(Sema &S, CXXRecordDecl *RecordDecl,
1489 StringRef Name, SourceLocation Loc) {
1490 DeclarationName DeclName(&S.getASTContext().Idents.get(Name));
1491 LookupResult Result(S, DeclName, Loc, Sema::LookupMemberName);
1492 if (!S.LookupQualifiedName(Result, static_cast<DeclContext *>(RecordDecl)))
1493 return nullptr;
1494 return cast<CXXMethodDecl>(Result.getFoundDecl());
1495}
1496
1497} // end anonymous namespace
1498
1501 // Define some common error handling functions
1502 bool HadError = false;
1503 auto ReportError = [this, &HadError](SourceLocation Loc, uint32_t LowerBound,
1504 uint32_t UpperBound) {
1505 HadError = true;
1506 this->Diag(Loc, diag::err_hlsl_invalid_rootsig_value)
1507 << LowerBound << UpperBound;
1508 };
1509
1510 auto ReportFloatError = [this, &HadError](SourceLocation Loc,
1511 float LowerBound,
1512 float UpperBound) {
1513 HadError = true;
1514 this->Diag(Loc, diag::err_hlsl_invalid_rootsig_value)
1515 << llvm::formatv("{0:f}", LowerBound).sstr<6>()
1516 << llvm::formatv("{0:f}", UpperBound).sstr<6>();
1517 };
1518
1519 auto VerifyRegister = [ReportError](SourceLocation Loc, uint32_t Register) {
1520 if (!llvm::hlsl::rootsig::verifyRegisterValue(Register))
1521 ReportError(Loc, 0, 0xfffffffe);
1522 };
1523
1524 auto VerifySpace = [ReportError](SourceLocation Loc, uint32_t Space) {
1525 if (!llvm::hlsl::rootsig::verifyRegisterSpace(Space))
1526 ReportError(Loc, 0, 0xffffffef);
1527 };
1528
1529 const uint32_t Version =
1530 llvm::to_underlying(SemaRef.getLangOpts().HLSLRootSigVer);
1531 const uint32_t VersionEnum = Version - 1;
1532 auto ReportFlagError = [this, &HadError, VersionEnum](SourceLocation Loc) {
1533 HadError = true;
1534 this->Diag(Loc, diag::err_hlsl_invalid_rootsig_flag)
1535 << /*version minor*/ VersionEnum;
1536 };
1537
1538 // Iterate through the elements and do basic validations
1539 for (const hlsl::RootSignatureElement &RootSigElem : Elements) {
1540 SourceLocation Loc = RootSigElem.getLocation();
1541 const llvm::hlsl::rootsig::RootElement &Elem = RootSigElem.getElement();
1542 if (const auto *Descriptor =
1543 std::get_if<llvm::hlsl::rootsig::RootDescriptor>(&Elem)) {
1544 VerifyRegister(Loc, Descriptor->Reg.Number);
1545 VerifySpace(Loc, Descriptor->Space);
1546
1547 if (!llvm::hlsl::rootsig::verifyRootDescriptorFlag(Version,
1548 Descriptor->Flags))
1549 ReportFlagError(Loc);
1550 } else if (const auto *Constants =
1551 std::get_if<llvm::hlsl::rootsig::RootConstants>(&Elem)) {
1552 VerifyRegister(Loc, Constants->Reg.Number);
1553 VerifySpace(Loc, Constants->Space);
1554 } else if (const auto *Sampler =
1555 std::get_if<llvm::hlsl::rootsig::StaticSampler>(&Elem)) {
1556 VerifyRegister(Loc, Sampler->Reg.Number);
1557 VerifySpace(Loc, Sampler->Space);
1558
1559 assert(!std::isnan(Sampler->MaxLOD) && !std::isnan(Sampler->MinLOD) &&
1560 "By construction, parseFloatParam can't produce a NaN from a "
1561 "float_literal token");
1562
1563 if (!llvm::hlsl::rootsig::verifyMaxAnisotropy(Sampler->MaxAnisotropy))
1564 ReportError(Loc, 0, 16);
1565 if (!llvm::hlsl::rootsig::verifyMipLODBias(Sampler->MipLODBias))
1566 ReportFloatError(Loc, -16.f, 15.99f);
1567 } else if (const auto *Clause =
1568 std::get_if<llvm::hlsl::rootsig::DescriptorTableClause>(
1569 &Elem)) {
1570 VerifyRegister(Loc, Clause->Reg.Number);
1571 VerifySpace(Loc, Clause->Space);
1572
1573 if (!llvm::hlsl::rootsig::verifyNumDescriptors(Clause->NumDescriptors)) {
1574 // NumDescriptor could techincally be ~0u but that is reserved for
1575 // unbounded, so the diagnostic will not report that as a valid int
1576 // value
1577 ReportError(Loc, 1, 0xfffffffe);
1578 }
1579
1580 if (!llvm::hlsl::rootsig::verifyDescriptorRangeFlag(Version, Clause->Type,
1581 Clause->Flags))
1582 ReportFlagError(Loc);
1583 }
1584 }
1585
1586 PerVisibilityBindingChecker BindingChecker(this);
1587 SmallVector<std::pair<const llvm::hlsl::rootsig::DescriptorTableClause *,
1589 UnboundClauses;
1590
1591 for (const hlsl::RootSignatureElement &RootSigElem : Elements) {
1592 const llvm::hlsl::rootsig::RootElement &Elem = RootSigElem.getElement();
1593 if (const auto *Descriptor =
1594 std::get_if<llvm::hlsl::rootsig::RootDescriptor>(&Elem)) {
1595 uint32_t LowerBound(Descriptor->Reg.Number);
1596 uint32_t UpperBound(LowerBound); // inclusive range
1597
1598 BindingChecker.trackBinding(
1599 Descriptor->Visibility,
1600 static_cast<llvm::dxil::ResourceClass>(Descriptor->Type),
1601 Descriptor->Space, LowerBound, UpperBound, &RootSigElem);
1602 } else if (const auto *Constants =
1603 std::get_if<llvm::hlsl::rootsig::RootConstants>(&Elem)) {
1604 uint32_t LowerBound(Constants->Reg.Number);
1605 uint32_t UpperBound(LowerBound); // inclusive range
1606
1607 BindingChecker.trackBinding(
1608 Constants->Visibility, llvm::dxil::ResourceClass::CBuffer,
1609 Constants->Space, LowerBound, UpperBound, &RootSigElem);
1610 } else if (const auto *Sampler =
1611 std::get_if<llvm::hlsl::rootsig::StaticSampler>(&Elem)) {
1612 uint32_t LowerBound(Sampler->Reg.Number);
1613 uint32_t UpperBound(LowerBound); // inclusive range
1614
1615 BindingChecker.trackBinding(
1616 Sampler->Visibility, llvm::dxil::ResourceClass::Sampler,
1617 Sampler->Space, LowerBound, UpperBound, &RootSigElem);
1618 } else if (const auto *Clause =
1619 std::get_if<llvm::hlsl::rootsig::DescriptorTableClause>(
1620 &Elem)) {
1621 // We'll process these once we see the table element.
1622 UnboundClauses.emplace_back(Clause, &RootSigElem);
1623 } else if (const auto *Table =
1624 std::get_if<llvm::hlsl::rootsig::DescriptorTable>(&Elem)) {
1625 assert(UnboundClauses.size() == Table->NumClauses &&
1626 "Number of unbound elements must match the number of clauses");
1627 bool HasAnySampler = false;
1628 bool HasAnyNonSampler = false;
1629 uint64_t Offset = 0;
1630 bool IsPrevUnbound = false;
1631 for (const auto &[Clause, ClauseElem] : UnboundClauses) {
1632 SourceLocation Loc = ClauseElem->getLocation();
1633 if (Clause->Type == llvm::dxil::ResourceClass::Sampler)
1634 HasAnySampler = true;
1635 else
1636 HasAnyNonSampler = true;
1637
1638 if (HasAnySampler && HasAnyNonSampler)
1639 Diag(Loc, diag::err_hlsl_invalid_mixed_resources);
1640
1641 // Relevant error will have already been reported above and needs to be
1642 // fixed before we can conduct further analysis, so shortcut error
1643 // return
1644 if (Clause->NumDescriptors == 0)
1645 return true;
1646
1647 bool IsAppending =
1648 Clause->Offset == llvm::hlsl::rootsig::DescriptorTableOffsetAppend;
1649 if (!IsAppending)
1650 Offset = Clause->Offset;
1651
1652 uint64_t RangeBound = llvm::hlsl::rootsig::computeRangeBound(
1653 Offset, Clause->NumDescriptors);
1654
1655 if (IsPrevUnbound && IsAppending)
1656 Diag(Loc, diag::err_hlsl_appending_onto_unbound);
1657 else if (!llvm::hlsl::rootsig::verifyNoOverflowedOffset(RangeBound))
1658 Diag(Loc, diag::err_hlsl_offset_overflow) << Offset << RangeBound;
1659
1660 // Update offset to be 1 past this range's bound
1661 Offset = RangeBound + 1;
1662 IsPrevUnbound = Clause->NumDescriptors ==
1663 llvm::hlsl::rootsig::NumDescriptorsUnbounded;
1664
1665 // Compute the register bounds and track resource binding
1666 uint32_t LowerBound(Clause->Reg.Number);
1667 uint32_t UpperBound = llvm::hlsl::rootsig::computeRangeBound(
1668 LowerBound, Clause->NumDescriptors);
1669
1670 BindingChecker.trackBinding(
1671 Table->Visibility,
1672 static_cast<llvm::dxil::ResourceClass>(Clause->Type), Clause->Space,
1673 LowerBound, UpperBound, ClauseElem);
1674 }
1675 UnboundClauses.clear();
1676 }
1677 }
1678
1679 return BindingChecker.checkOverlap();
1680}
1681
1683 if (AL.getNumArgs() != 1) {
1684 Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1;
1685 return;
1686 }
1687
1689 if (auto *RS = D->getAttr<RootSignatureAttr>()) {
1690 if (RS->getSignatureIdent() != Ident) {
1691 Diag(AL.getLoc(), diag::err_disallowed_duplicate_attribute) << RS;
1692 return;
1693 }
1694
1695 Diag(AL.getLoc(), diag::warn_duplicate_attribute_exact) << RS;
1696 return;
1697 }
1698
1700 if (SemaRef.LookupQualifiedName(R, D->getDeclContext()))
1701 if (auto *SignatureDecl =
1702 dyn_cast<HLSLRootSignatureDecl>(R.getFoundDecl())) {
1703 D->addAttr(::new (getASTContext()) RootSignatureAttr(
1704 getASTContext(), AL, Ident, SignatureDecl));
1705 }
1706}
1707
1709 llvm::VersionTuple SMVersion =
1710 getASTContext().getTargetInfo().getTriple().getOSVersion();
1711 bool IsDXIL = getASTContext().getTargetInfo().getTriple().getArch() ==
1712 llvm::Triple::dxil;
1713
1714 uint32_t ZMax = 1024;
1715 uint32_t ThreadMax = 1024;
1716 if (IsDXIL && SMVersion.getMajor() <= 4) {
1717 ZMax = 1;
1718 ThreadMax = 768;
1719 } else if (IsDXIL && SMVersion.getMajor() == 5) {
1720 ZMax = 64;
1721 ThreadMax = 1024;
1722 }
1723
1724 uint32_t X;
1725 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), X))
1726 return;
1727 if (X > 1024) {
1728 Diag(AL.getArgAsExpr(0)->getExprLoc(),
1729 diag::err_hlsl_numthreads_argument_oor)
1730 << 0 << 1024;
1731 return;
1732 }
1733 uint32_t Y;
1734 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(1), Y))
1735 return;
1736 if (Y > 1024) {
1737 Diag(AL.getArgAsExpr(1)->getExprLoc(),
1738 diag::err_hlsl_numthreads_argument_oor)
1739 << 1 << 1024;
1740 return;
1741 }
1742 uint32_t Z;
1743 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(2), Z))
1744 return;
1745 if (Z > ZMax) {
1746 SemaRef.Diag(AL.getArgAsExpr(2)->getExprLoc(),
1747 diag::err_hlsl_numthreads_argument_oor)
1748 << 2 << ZMax;
1749 return;
1750 }
1751
1752 if (X * Y * Z > ThreadMax) {
1753 Diag(AL.getLoc(), diag::err_hlsl_numthreads_invalid) << ThreadMax;
1754 return;
1755 }
1756
1757 HLSLNumThreadsAttr *NewAttr = mergeNumThreadsAttr(D, AL, X, Y, Z);
1758 if (NewAttr)
1759 D->addAttr(NewAttr);
1760}
1761
1762static bool isValidWaveSizeValue(unsigned Value) {
1763 return llvm::isPowerOf2_32(Value) && Value >= 4 && Value <= 128;
1764}
1765
1767 // validate that the wavesize argument is a power of 2 between 4 and 128
1768 // inclusive
1769 unsigned SpelledArgsCount = AL.getNumArgs();
1770 if (SpelledArgsCount == 0 || SpelledArgsCount > 3)
1771 return;
1772
1773 uint32_t Min;
1774 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), Min))
1775 return;
1776
1777 uint32_t Max = 0;
1778 if (SpelledArgsCount > 1 &&
1779 !SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(1), Max))
1780 return;
1781
1782 uint32_t Preferred = 0;
1783 if (SpelledArgsCount > 2 &&
1784 !SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(2), Preferred))
1785 return;
1786
1787 if (SpelledArgsCount > 2) {
1788 if (!isValidWaveSizeValue(Preferred)) {
1789 Diag(AL.getArgAsExpr(2)->getExprLoc(),
1790 diag::err_attribute_power_of_two_in_range)
1791 << AL << llvm::dxil::MinWaveSize << llvm::dxil::MaxWaveSize
1792 << Preferred;
1793 return;
1794 }
1795 // Preferred not in range.
1796 if (Preferred < Min || Preferred > Max) {
1797 Diag(AL.getArgAsExpr(2)->getExprLoc(),
1798 diag::err_attribute_power_of_two_in_range)
1799 << AL << Min << Max << Preferred;
1800 return;
1801 }
1802 } else if (SpelledArgsCount > 1) {
1803 if (!isValidWaveSizeValue(Max)) {
1804 Diag(AL.getArgAsExpr(1)->getExprLoc(),
1805 diag::err_attribute_power_of_two_in_range)
1806 << AL << llvm::dxil::MinWaveSize << llvm::dxil::MaxWaveSize << Max;
1807 return;
1808 }
1809 if (Max < Min) {
1810 Diag(AL.getLoc(), diag::err_attribute_argument_invalid) << AL << 1;
1811 return;
1812 } else if (Max == Min) {
1813 Diag(AL.getLoc(), diag::warn_attr_min_eq_max) << AL;
1814 }
1815 } else {
1816 if (!isValidWaveSizeValue(Min)) {
1817 Diag(AL.getArgAsExpr(0)->getExprLoc(),
1818 diag::err_attribute_power_of_two_in_range)
1819 << AL << llvm::dxil::MinWaveSize << llvm::dxil::MaxWaveSize << Min;
1820 return;
1821 }
1822 }
1823
1824 HLSLWaveSizeAttr *NewAttr =
1825 mergeWaveSizeAttr(D, AL, Min, Max, Preferred, SpelledArgsCount);
1826 if (NewAttr)
1827 D->addAttr(NewAttr);
1828}
1829
1831 uint32_t ID;
1832 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), ID))
1833 return;
1834 D->addAttr(::new (getASTContext())
1835 HLSLVkExtBuiltinInputAttr(getASTContext(), AL, ID));
1836}
1837
1839 uint32_t ID;
1840 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), ID))
1841 return;
1842 D->addAttr(::new (getASTContext())
1843 HLSLVkExtBuiltinOutputAttr(getASTContext(), AL, ID));
1844}
1845
1847 D->addAttr(::new (getASTContext())
1848 HLSLVkPushConstantAttr(getASTContext(), AL));
1849}
1850
1852 uint32_t Id;
1853 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), Id))
1854 return;
1855 HLSLVkConstantIdAttr *NewAttr = mergeVkConstantIdAttr(D, AL, Id);
1856 if (NewAttr)
1857 D->addAttr(NewAttr);
1858}
1859
1861 uint32_t Binding = 0;
1862 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), Binding))
1863 return;
1864 uint32_t Set = 0;
1865 if (AL.getNumArgs() > 1 &&
1866 !SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(1), Set))
1867 return;
1868
1869 D->addAttr(::new (getASTContext())
1870 HLSLVkBindingAttr(getASTContext(), AL, Binding, Set));
1871}
1872
1874 uint32_t Location;
1875 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), Location))
1876 return;
1877
1878 D->addAttr(::new (getASTContext())
1879 HLSLVkLocationAttr(getASTContext(), AL, Location));
1880}
1881
1883 const auto *VT = T->getAs<VectorType>();
1884
1885 if (!T->hasUnsignedIntegerRepresentation() ||
1886 (VT && VT->getNumElements() > 3)) {
1887 Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type)
1888 << AL << "uint/uint2/uint3";
1889 return false;
1890 }
1891
1892 return true;
1893}
1894
1896 const auto *VT = T->getAs<VectorType>();
1897 if (!T->hasFloatingRepresentation() || (VT && VT->getNumElements() > 4)) {
1898 Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type)
1899 << AL << "float/float1/float2/float3/float4";
1900 return false;
1901 }
1902
1903 return true;
1904}
1905
1907 SemanticKind Kind,
1908 std::optional<unsigned> Index) {
1909 auto *VD = cast<ValueDecl>(D);
1910 QualType ValueType = VD->getType();
1911 if (auto *FD = dyn_cast<FunctionDecl>(D))
1912 ValueType = FD->getReturnType();
1913
1914 // `out` and `inout` parameters are passed by reference.
1915 if (HLSLParamModifierAttr *MA = D->getAttr<HLSLParamModifierAttr>())
1916 if (MA->isAnyOut())
1917 ValueType = cast<ReferenceType>(ValueType)->getPointeeType();
1918
1919 switch (Kind) {
1920 case SemanticKind::DispatchThreadID:
1921 case SemanticKind::GroupThreadID:
1922 case SemanticKind::GroupID:
1923 diagnoseIndexType(ValueType, AL);
1924 break;
1925 case SemanticKind::GroupIndex:
1926 break;
1927 case SemanticKind::Position:
1928 case SemanticKind::Target:
1929 diagnoseFloatType(ValueType, AL);
1930 break;
1931 case SemanticKind::VertexID: {
1932 uint64_t SizeInBits = SemaRef.Context.getTypeSize(ValueType);
1933 if (!ValueType->isUnsignedIntegerType() || SizeInBits != 32)
1934 Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type) << AL << "uint";
1935 break;
1936 }
1937 case SemanticKind::InstanceID: {
1938 uint64_t SizeInBits = SemaRef.Context.getTypeSize(ValueType);
1939 // DXIL permits U32 or U16. SPIR-V requires a 32-bit scalar per
1940 // VUID-InstanceIndex-InstanceIndex-04265.
1941 bool IsSPIRV = getASTContext().getTargetInfo().getTriple().isSPIRV();
1942 if (!ValueType->isUnsignedIntegerType() ||
1943 !(SizeInBits == 32 || (!IsSPIRV && SizeInBits == 16)))
1944 Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type) << AL << "uint";
1945 break;
1946 }
1947 default:
1948 Diag(AL.getLoc(), diag::err_hlsl_unknown_semantic) << AL;
1949 return;
1950 }
1951
1953}
1954
1956 uint32_t IndexValue(0), ExplicitIndex(0);
1957 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), IndexValue) ||
1958 !SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(1), ExplicitIndex)) {
1959 assert(0 && "HLSLUnparsedSemantic is expected to have 2 int arguments.");
1960 }
1961 assert(IndexValue > 0 ? ExplicitIndex : true);
1962 std::optional<unsigned> Index =
1963 ExplicitIndex ? std::optional<unsigned>(IndexValue) : std::nullopt;
1964
1965 SemanticKind Kind = llvm::hlsl::getSemanticKind(AL.getAttrName()->getName());
1966 if (Kind == SemanticKind::Arbitrary)
1968 else
1969 diagnoseSystemSemanticAttr(D, AL, Kind, Index);
1970}
1971
1974 Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_ast_node)
1975 << AL << "shader constant in a constant buffer";
1976 return;
1977 }
1978
1979 uint32_t SubComponent;
1980 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), SubComponent))
1981 return;
1982 uint32_t Component;
1983 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(1), Component))
1984 return;
1985
1986 QualType T = cast<VarDecl>(D)->getType().getCanonicalType();
1987 // Check if T is an array or struct type.
1988 // TODO: mark matrix type as aggregate type.
1989 bool IsAggregateTy = (T->isArrayType() || T->isStructureType());
1990
1991 // Check Component is valid for T.
1992 if (Component) {
1993 unsigned Size = getASTContext().getTypeSize(T);
1994 if (IsAggregateTy) {
1995 Diag(AL.getLoc(), diag::err_hlsl_invalid_register_or_packoffset);
1996 return;
1997 } else {
1998 // Make sure Component + sizeof(T) <= 4.
1999 if ((Component * 32 + Size) > 128) {
2000 Diag(AL.getLoc(), diag::err_hlsl_packoffset_cross_reg_boundary);
2001 return;
2002 }
2003 QualType EltTy = T;
2004 if (const auto *VT = T->getAs<VectorType>())
2005 EltTy = VT->getElementType();
2006 unsigned Align = getASTContext().getTypeAlign(EltTy);
2007 if (Align > 32 && Component == 1) {
2008 // NOTE: Component 3 will hit err_hlsl_packoffset_cross_reg_boundary.
2009 // So we only need to check Component 1 here.
2010 Diag(AL.getLoc(), diag::err_hlsl_packoffset_alignment_mismatch)
2011 << Align << EltTy;
2012 return;
2013 }
2014 }
2015 }
2016
2017 D->addAttr(::new (getASTContext()) HLSLPackOffsetAttr(
2018 getASTContext(), AL, SubComponent, Component));
2019}
2020
2022 StringRef Str;
2023 SourceLocation ArgLoc;
2024 if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
2025 return;
2026
2027 llvm::Triple::EnvironmentType ShaderType;
2028 if (!HLSLShaderAttr::ConvertStrToEnvironmentType(Str, ShaderType)) {
2029 Diag(AL.getLoc(), diag::warn_attribute_type_not_supported)
2030 << AL << Str << ArgLoc;
2031 return;
2032 }
2033
2034 // FIXME: check function match the shader stage.
2035
2036 HLSLShaderAttr *NewAttr = mergeShaderAttr(D, AL, ShaderType);
2037 if (NewAttr)
2038 D->addAttr(NewAttr);
2039}
2040
2042 Sema &S, QualType Wrapped, ArrayRef<const Attr *> AttrList,
2043 QualType &ResType, HLSLAttributedResourceLocInfo *LocInfo,
2044 Expr *SampleCountExpr) {
2045 assert(AttrList.size() && "expected list of resource attributes");
2046
2047 QualType ContainedTy = QualType();
2048 TypeSourceInfo *ContainedTyInfo = nullptr;
2049 SourceLocation LocBegin = AttrList[0]->getRange().getBegin();
2050 SourceLocation LocEnd = AttrList[0]->getRange().getEnd();
2051
2052 HLSLAttributedResourceType::Attributes ResAttrs;
2053
2054 bool HasResourceClass = false;
2055 bool HasResourceDimension = false;
2056 for (const Attr *A : AttrList) {
2057 if (!A)
2058 continue;
2059 LocEnd = A->getRange().getEnd();
2060 switch (A->getKind()) {
2061 case attr::HLSLResourceClass: {
2062 ResourceClass RC = cast<HLSLResourceClassAttr>(A)->getResourceClass();
2063 if (HasResourceClass) {
2064 S.Diag(A->getLocation(), ResAttrs.ResourceClass == RC
2065 ? diag::warn_duplicate_attribute_exact
2066 : diag::warn_duplicate_attribute)
2067 << A;
2068 return false;
2069 }
2070 ResAttrs.ResourceClass = RC;
2071 HasResourceClass = true;
2072 break;
2073 }
2074 case attr::HLSLResourceDimension: {
2075 llvm::dxil::ResourceDimension RD =
2076 cast<HLSLResourceDimensionAttr>(A)->getDimension();
2077 if (HasResourceDimension) {
2078 S.Diag(A->getLocation(), ResAttrs.ResourceDimension == RD
2079 ? diag::warn_duplicate_attribute_exact
2080 : diag::warn_duplicate_attribute)
2081 << A;
2082 return false;
2083 }
2084 ResAttrs.ResourceDimension = RD;
2085 HasResourceDimension = true;
2086 break;
2087 }
2088 case attr::HLSLIsROV:
2089 if (ResAttrs.IsROV) {
2090 S.Diag(A->getLocation(), diag::warn_duplicate_attribute_exact) << A;
2091 return false;
2092 }
2093 ResAttrs.IsROV = true;
2094 break;
2095 case attr::HLSLRawBuffer:
2096 if (ResAttrs.RawBuffer) {
2097 S.Diag(A->getLocation(), diag::warn_duplicate_attribute_exact) << A;
2098 return false;
2099 }
2100 ResAttrs.RawBuffer = true;
2101 break;
2102 case attr::HLSLIsArray:
2103 if (ResAttrs.IsArray) {
2104 S.Diag(A->getLocation(), diag::warn_duplicate_attribute_exact) << A;
2105 return false;
2106 }
2107 ResAttrs.IsArray = true;
2108 break;
2109 case attr::HLSLIsMultiSampled:
2110 if (ResAttrs.SampleCountExpr) {
2111 S.Diag(A->getLocation(), diag::warn_duplicate_attribute_exact) << A;
2112 return false;
2113 }
2114 // A bare [[hlsl::is_ms]] carries no count, so default it to 0, the same
2115 // value Texture2DMS<T> gets from its template parameter.
2116 ResAttrs.SampleCountExpr =
2117 SampleCountExpr
2118 ? SampleCountExpr
2119 : IntegerLiteral::Create(S.Context, llvm::APInt(32, 0),
2120 S.Context.IntTy, A->getLocation());
2121 break;
2122 case attr::HLSLIsCounter:
2123 if (ResAttrs.IsCounter) {
2124 S.Diag(A->getLocation(), diag::warn_duplicate_attribute_exact) << A;
2125 return false;
2126 }
2127 ResAttrs.IsCounter = true;
2128 break;
2129 case attr::HLSLContainedType: {
2130 const HLSLContainedTypeAttr *CTAttr = cast<HLSLContainedTypeAttr>(A);
2131 QualType Ty = CTAttr->getType();
2132 if (!ContainedTy.isNull()) {
2133 S.Diag(A->getLocation(), ContainedTy == Ty
2134 ? diag::warn_duplicate_attribute_exact
2135 : diag::warn_duplicate_attribute)
2136 << A;
2137 return false;
2138 }
2139 ContainedTy = Ty;
2140 ContainedTyInfo = CTAttr->getTypeLoc();
2141 break;
2142 }
2143 default:
2144 llvm_unreachable("unhandled resource attribute type");
2145 }
2146 }
2147
2148 if (!HasResourceClass) {
2149 S.Diag(AttrList.back()->getRange().getEnd(),
2150 diag::err_hlsl_missing_resource_class);
2151 return false;
2152 }
2153
2155 Wrapped, ContainedTy, ResAttrs);
2156
2157 if (LocInfo && ContainedTyInfo) {
2158 LocInfo->Range = SourceRange(LocBegin, LocEnd);
2159 LocInfo->ContainedTyInfo = ContainedTyInfo;
2160 }
2161 return true;
2162}
2163
2164// Validates and creates an HLSL attribute that is applied as type attribute on
2165// HLSL resource. The attributes are collected in HLSLResourcesTypeAttrs and at
2166// the end of the declaration they are applied to the declaration type by
2167// wrapping it in HLSLAttributedResourceType.
2169 // only allow resource type attributes on intangible types
2170 if (!T->isHLSLResourceType()) {
2171 Diag(AL.getLoc(), diag::err_hlsl_attribute_needs_intangible_type)
2172 << AL << getASTContext().HLSLResourceTy;
2173 return false;
2174 }
2175
2176 // validate number of arguments
2177 if (!AL.checkExactlyNumArgs(SemaRef, AL.getMinArgs()))
2178 return false;
2179
2180 Attr *A = nullptr;
2181
2185 {
2186 AttributeCommonInfo::AS_CXX11, 0, false /*IsAlignas*/,
2187 false /*IsRegularKeywordAttribute*/
2188 });
2189
2190 switch (AL.getKind()) {
2191 case ParsedAttr::AT_HLSLResourceClass: {
2192 StringRef Identifier;
2193 SourceLocation ArgLoc;
2194 if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Identifier, &ArgLoc))
2195 return false;
2196
2197 // Validate resource class value
2198 ResourceClass RC;
2199 if (!HLSLResourceClassAttr::ConvertStrToResourceClass(Identifier, RC)) {
2200 Diag(ArgLoc, diag::warn_attribute_type_not_supported)
2201 << "ResourceClass" << Identifier;
2202 return false;
2203 }
2204 A = HLSLResourceClassAttr::Create(getASTContext(), RC, ACI);
2205 break;
2206 }
2207
2208 case ParsedAttr::AT_HLSLResourceDimension: {
2209 StringRef Identifier;
2210 SourceLocation ArgLoc;
2211 if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Identifier, &ArgLoc))
2212 return false;
2213
2214 // Validate resource dimension value
2215 llvm::dxil::ResourceDimension RD;
2216 if (!HLSLResourceDimensionAttr::ConvertStrToResourceDimension(Identifier,
2217 RD)) {
2218 Diag(ArgLoc, diag::warn_attribute_type_not_supported)
2219 << "ResourceDimension" << Identifier;
2220 return false;
2221 }
2222 A = HLSLResourceDimensionAttr::Create(getASTContext(), RD, ACI);
2223 break;
2224 }
2225
2226 case ParsedAttr::AT_HLSLIsROV:
2227 A = HLSLIsROVAttr::Create(getASTContext(), ACI);
2228 break;
2229
2230 case ParsedAttr::AT_HLSLRawBuffer:
2231 A = HLSLRawBufferAttr::Create(getASTContext(), ACI);
2232 break;
2233
2234 case ParsedAttr::AT_HLSLIsCounter:
2235 A = HLSLIsCounterAttr::Create(getASTContext(), ACI);
2236 break;
2237
2238 case ParsedAttr::AT_HLSLIsArray:
2239 A = HLSLIsArrayAttr::Create(getASTContext(), ACI);
2240 break;
2241
2242 case ParsedAttr::AT_HLSLIsMultiSampled:
2243 A = HLSLIsMultiSampledAttr::Create(getASTContext(), ACI);
2244 break;
2245
2246 case ParsedAttr::AT_HLSLContainedType: {
2247 if (AL.getNumArgs() != 1 && !AL.hasParsedType()) {
2248 Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1;
2249 return false;
2250 }
2251
2252 TypeSourceInfo *TSI = nullptr;
2253 QualType QT = SemaRef.GetTypeFromParser(AL.getTypeArg(), &TSI);
2254 assert(TSI && "no type source info for attribute argument");
2255 if (SemaRef.RequireCompleteType(TSI->getTypeLoc().getBeginLoc(), QT,
2256 diag::err_incomplete_type))
2257 return false;
2258 A = HLSLContainedTypeAttr::Create(getASTContext(), TSI, ACI);
2259 break;
2260 }
2261
2262 default:
2263 llvm_unreachable("unhandled HLSL attribute");
2264 }
2265
2266 HLSLResourcesTypeAttrs.emplace_back(A);
2267 return true;
2268}
2269
2270// Combines all resource type attributes and creates HLSLAttributedResourceType.
2272 if (!HLSLResourcesTypeAttrs.size())
2273 return CurrentType;
2274
2275 QualType QT = CurrentType;
2278 HLSLResourcesTypeAttrs, QT, &LocInfo)) {
2279 const HLSLAttributedResourceType *RT =
2281
2282 // Temporarily store TypeLoc information for the new type.
2283 // It will be transferred to HLSLAttributesResourceTypeLoc
2284 // shortly after the type is created by TypeSpecLocFiller which
2285 // will call the TakeLocForHLSLAttribute method below.
2286 LocsForHLSLAttributedResources.insert(std::pair(RT, LocInfo));
2287 }
2288 HLSLResourcesTypeAttrs.clear();
2289 return QT;
2290}
2291
2292// Returns source location for the HLSLAttributedResourceType
2294SemaHLSL::TakeLocForHLSLAttribute(const HLSLAttributedResourceType *RT) {
2295 HLSLAttributedResourceLocInfo LocInfo = {};
2296 auto I = LocsForHLSLAttributedResources.find(RT);
2297 if (I != LocsForHLSLAttributedResources.end()) {
2298 LocInfo = I->second;
2299 LocsForHLSLAttributedResources.erase(I);
2300 return LocInfo;
2301 }
2302 LocInfo.Range = SourceRange();
2303 return LocInfo;
2304}
2305
2306// Walks though the global variable declaration, collects all resource binding
2307// requirements and adds them to Bindings
2308void SemaHLSL::collectResourceBindingsOnUserRecordDecl(const VarDecl *VD,
2309 const RecordType *RT) {
2310 const RecordDecl *RD = RT->getDecl()->getDefinitionOrSelf();
2311 for (FieldDecl *FD : RD->fields()) {
2312 const Type *Ty = FD->getType()->getUnqualifiedDesugaredType();
2313
2314 // Unwrap arrays
2315 // FIXME: Calculate array size while unwrapping
2316 assert(!Ty->isIncompleteArrayType() &&
2317 "incomplete arrays inside user defined types are not supported");
2318 while (Ty->isConstantArrayType()) {
2321 }
2322
2323 if (!Ty->isRecordType())
2324 continue;
2325
2326 if (const HLSLAttributedResourceType *AttrResType =
2327 HLSLAttributedResourceType::findHandleTypeOnResource(Ty)) {
2328 // Add a new DeclBindingInfo to Bindings if it does not already exist
2329 ResourceClass RC = AttrResType->getAttrs().ResourceClass;
2330 DeclBindingInfo *DBI = Bindings.getDeclBindingInfo(VD, RC);
2331 if (!DBI)
2332 Bindings.addDeclBindingInfo(VD, RC);
2333 } else if (const RecordType *RT = dyn_cast<RecordType>(Ty)) {
2334 // Recursively scan embedded struct or class; it would be nice to do this
2335 // without recursion, but tricky to correctly calculate the size of the
2336 // binding, which is something we are probably going to need to do later
2337 // on. Hopefully nesting of structs in structs too many levels is
2338 // unlikely.
2339 collectResourceBindingsOnUserRecordDecl(VD, RT);
2340 }
2341 }
2342}
2343
2344// Diagnose localized register binding errors for a single binding; does not
2345// diagnose resource binding on user record types, that will be done later
2346// in processResourceBindingOnDecl based on the information collected in
2347// collectResourceBindingsOnVarDecl.
2348// Returns false if the register binding is not valid.
2350 Decl *D, RegisterType RegType,
2351 bool SpecifiedSpace) {
2352 int RegTypeNum = static_cast<int>(RegType);
2353
2354 // check if the decl type is groupshared
2355 if (D->hasAttr<HLSLGroupSharedAddressSpaceAttr>()) {
2356 S.Diag(ArgLoc, diag::err_hlsl_binding_type_mismatch) << RegTypeNum;
2357 return false;
2358 }
2359
2360 // Cbuffers and Tbuffers are HLSLBufferDecl types
2361 if (HLSLBufferDecl *CBufferOrTBuffer = dyn_cast<HLSLBufferDecl>(D)) {
2362 ResourceClass RC = CBufferOrTBuffer->isCBuffer() ? ResourceClass::CBuffer
2363 : ResourceClass::SRV;
2364 if (RegType == getRegisterType(RC))
2365 return true;
2366
2367 S.Diag(D->getLocation(), diag::err_hlsl_binding_type_mismatch)
2368 << RegTypeNum;
2369 return false;
2370 }
2371
2372 // Samplers, UAVs, and SRVs are VarDecl types
2373 assert(isa<VarDecl>(D) && "D is expected to be VarDecl or HLSLBufferDecl");
2374 VarDecl *VD = cast<VarDecl>(D);
2375
2376 // Resource
2377 if (const HLSLAttributedResourceType *AttrResType =
2378 HLSLAttributedResourceType::findHandleTypeOnResource(
2379 VD->getType().getTypePtr())) {
2380 if (RegType == getRegisterType(AttrResType))
2381 return true;
2382
2383 S.Diag(D->getLocation(), diag::err_hlsl_binding_type_mismatch)
2384 << RegTypeNum;
2385 return false;
2386 }
2387
2388 const clang::Type *Ty = VD->getType().getTypePtr();
2389 while (Ty->isArrayType())
2391
2392 // Basic types
2393 if (Ty->isArithmeticType() || Ty->isVectorType()) {
2394 bool DeclaredInCOrTBuffer = isa<HLSLBufferDecl>(D->getDeclContext());
2395 if (SpecifiedSpace && !DeclaredInCOrTBuffer)
2396 S.Diag(ArgLoc, diag::err_hlsl_space_on_global_constant);
2397
2398 if (!DeclaredInCOrTBuffer && (Ty->isIntegralType(S.getASTContext()) ||
2399 Ty->isFloatingType() || Ty->isVectorType())) {
2400 // Register annotation on default constant buffer declaration ($Globals)
2401 if (RegType == RegisterType::CBuffer)
2402 S.Diag(ArgLoc, diag::warn_hlsl_deprecated_register_type_b);
2403 else if (RegType != RegisterType::C)
2404 S.Diag(ArgLoc, diag::err_hlsl_binding_type_mismatch) << RegTypeNum;
2405 else
2406 return true;
2407 } else {
2408 if (RegType == RegisterType::C)
2409 S.Diag(ArgLoc, diag::warn_hlsl_register_type_c_packoffset);
2410 else
2411 S.Diag(ArgLoc, diag::err_hlsl_binding_type_mismatch) << RegTypeNum;
2412 }
2413 return false;
2414 }
2415 if (Ty->isRecordType())
2416 // RecordTypes will be diagnosed in processResourceBindingOnDecl
2417 // that is called from ActOnVariableDeclarator
2418 return true;
2419
2420 // Anything else is an error
2421 S.Diag(ArgLoc, diag::err_hlsl_binding_type_mismatch) << RegTypeNum;
2422 return false;
2423}
2424
2426 RegisterType regType) {
2427 // make sure that there are no two register annotations
2428 // applied to the decl with the same register type
2429 bool RegisterTypesDetected[5] = {false};
2430 RegisterTypesDetected[static_cast<int>(regType)] = true;
2431
2432 for (auto it = TheDecl->attr_begin(); it != TheDecl->attr_end(); ++it) {
2433 if (HLSLResourceBindingAttr *attr =
2434 dyn_cast<HLSLResourceBindingAttr>(*it)) {
2435
2436 RegisterType otherRegType = attr->getRegisterType();
2437 if (RegisterTypesDetected[static_cast<int>(otherRegType)]) {
2438 int otherRegTypeNum = static_cast<int>(otherRegType);
2439 S.Diag(TheDecl->getLocation(),
2440 diag::err_hlsl_duplicate_register_annotation)
2441 << otherRegTypeNum;
2442 return false;
2443 }
2444 RegisterTypesDetected[static_cast<int>(otherRegType)] = true;
2445 }
2446 }
2447 return true;
2448}
2449
2451 Decl *D, RegisterType RegType,
2452 bool SpecifiedSpace) {
2453
2454 // exactly one of these two types should be set
2455 assert(((isa<VarDecl>(D) && !isa<HLSLBufferDecl>(D)) ||
2456 (!isa<VarDecl>(D) && isa<HLSLBufferDecl>(D))) &&
2457 "expecting VarDecl or HLSLBufferDecl");
2458
2459 // check if the declaration contains resource matching the register type
2460 if (!DiagnoseLocalRegisterBinding(S, ArgLoc, D, RegType, SpecifiedSpace))
2461 return false;
2462
2463 // next, if multiple register annotations exist, check that none conflict.
2464 return ValidateMultipleRegisterAnnotations(S, D, RegType);
2465}
2466
2467// return false if the slot count exceeds the limit, true otherwise
2468static bool AccumulateHLSLResourceSlots(QualType Ty, uint64_t &StartSlot,
2469 const uint64_t &Limit,
2470 const ResourceClass ResClass,
2471 ASTContext &Ctx,
2472 uint64_t ArrayCount = 1) {
2473 Ty = Ty.getCanonicalType();
2474 const Type *T = Ty.getTypePtr();
2475
2476 // Early exit if already overflowed
2477 if (StartSlot > Limit)
2478 return false;
2479
2480 // Case 1: array type
2481 if (const auto *AT = dyn_cast<ArrayType>(T)) {
2482 uint64_t Count = 1;
2483
2484 if (const auto *CAT = dyn_cast<ConstantArrayType>(AT))
2485 Count = CAT->getSize().getZExtValue();
2486
2487 QualType ElemTy = AT->getElementType();
2488 return AccumulateHLSLResourceSlots(ElemTy, StartSlot, Limit, ResClass, Ctx,
2489 ArrayCount * Count);
2490 }
2491
2492 // Case 2: resource leaf
2493 if (auto ResTy = dyn_cast<HLSLAttributedResourceType>(T)) {
2494 // First ensure this resource counts towards the corresponding
2495 // register type limit.
2496 if (ResTy->getAttrs().ResourceClass != ResClass)
2497 return true;
2498
2499 // Validate highest slot used
2500 uint64_t EndSlot = StartSlot + ArrayCount - 1;
2501 if (EndSlot > Limit)
2502 return false;
2503
2504 // Advance SlotCount past the consumed range
2505 StartSlot = EndSlot + 1;
2506 return true;
2507 }
2508
2509 // Case 3: struct / record
2510 if (const auto *RT = dyn_cast<RecordType>(T)) {
2511 const RecordDecl *RD = RT->getDecl();
2512
2513 if (const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
2514 for (const CXXBaseSpecifier &Base : CXXRD->bases()) {
2515 if (!AccumulateHLSLResourceSlots(Base.getType(), StartSlot, Limit,
2516 ResClass, Ctx, ArrayCount))
2517 return false;
2518 }
2519 }
2520
2521 for (const FieldDecl *Field : RD->fields()) {
2522 if (!AccumulateHLSLResourceSlots(Field->getType(), StartSlot, Limit,
2523 ResClass, Ctx, ArrayCount))
2524 return false;
2525 }
2526
2527 return true;
2528 }
2529
2530 // Case 4: everything else
2531 return true;
2532}
2533
2534// return true if there is something invalid, false otherwise
2535static bool ValidateRegisterNumber(uint64_t SlotNum, Decl *TheDecl,
2536 ASTContext &Ctx, RegisterType RegTy) {
2537 const uint64_t Limit = UINT32_MAX;
2538 if (SlotNum > Limit)
2539 return true;
2540
2541 // after verifying the number doesn't exceed uint32max, we don't need
2542 // to look further into c or i register types
2543 if (RegTy == RegisterType::C || RegTy == RegisterType::I)
2544 return false;
2545
2546 if (VarDecl *VD = dyn_cast<VarDecl>(TheDecl)) {
2547 uint64_t BaseSlot = SlotNum;
2548
2549 if (!AccumulateHLSLResourceSlots(VD->getType(), SlotNum, Limit,
2550 getResourceClass(RegTy), Ctx))
2551 return true;
2552
2553 // After AccumulateHLSLResourceSlots runs, SlotNum is now
2554 // the first free slot; last used was SlotNum - 1
2555 return (BaseSlot > Limit);
2556 }
2557 // handle the cbuffer/tbuffer case
2558 if (isa<HLSLBufferDecl>(TheDecl))
2559 // resources cannot be put within a cbuffer, so no need
2560 // to analyze the structure since the register number
2561 // won't be pushed any higher.
2562 return (SlotNum > Limit);
2563
2564 // we don't expect any other decl type, so fail
2565 llvm_unreachable("unexpected decl type");
2566}
2567
2569 if (VarDecl *VD = dyn_cast<VarDecl>(TheDecl)) {
2570 QualType Ty = VD->getType();
2571 if (const auto *IAT = dyn_cast<IncompleteArrayType>(Ty))
2572 Ty = IAT->getElementType();
2573 if (SemaRef.RequireCompleteType(TheDecl->getBeginLoc(), Ty,
2574 diag::err_incomplete_type))
2575 return;
2576 }
2577
2578 StringRef Slot = "";
2579 StringRef Space = "";
2580 SourceLocation SlotLoc, SpaceLoc;
2581
2582 if (!AL.isArgIdent(0)) {
2583 Diag(AL.getLoc(), diag::err_attribute_argument_type)
2584 << AL << AANT_ArgumentIdentifier;
2585 return;
2586 }
2587 IdentifierLoc *Loc = AL.getArgAsIdent(0);
2588
2589 if (AL.getNumArgs() == 2) {
2590 Slot = Loc->getIdentifierInfo()->getName();
2591 SlotLoc = Loc->getLoc();
2592 if (!AL.isArgIdent(1)) {
2593 Diag(AL.getLoc(), diag::err_attribute_argument_type)
2594 << AL << AANT_ArgumentIdentifier;
2595 return;
2596 }
2597 Loc = AL.getArgAsIdent(1);
2598 Space = Loc->getIdentifierInfo()->getName();
2599 SpaceLoc = Loc->getLoc();
2600 } else {
2601 StringRef Str = Loc->getIdentifierInfo()->getName();
2602 if (Str.starts_with("space")) {
2603 Space = Str;
2604 SpaceLoc = Loc->getLoc();
2605 } else {
2606 Slot = Str;
2607 SlotLoc = Loc->getLoc();
2608 Space = "space0";
2609 }
2610 }
2611
2612 RegisterType RegType = RegisterType::SRV;
2613 std::optional<unsigned> SlotNum;
2614 unsigned SpaceNum = 0;
2615
2616 // Validate slot
2617 if (!Slot.empty()) {
2618 if (!convertToRegisterType(Slot, &RegType)) {
2619 Diag(SlotLoc, diag::err_hlsl_binding_type_invalid) << Slot.substr(0, 1);
2620 return;
2621 }
2622 if (RegType == RegisterType::I) {
2623 Diag(SlotLoc, diag::warn_hlsl_deprecated_register_type_i);
2624 return;
2625 }
2626 const StringRef SlotNumStr = Slot.substr(1);
2627
2628 uint64_t N;
2629
2630 // validate that the slot number is a non-empty number
2631 if (SlotNumStr.getAsInteger(10, N)) {
2632 Diag(SlotLoc, diag::err_hlsl_unsupported_register_number);
2633 return;
2634 }
2635
2636 // Validate register number. It should not exceed UINT32_MAX,
2637 // including if the resource type is an array that starts
2638 // before UINT32_MAX, but ends afterwards.
2639 if (ValidateRegisterNumber(N, TheDecl, getASTContext(), RegType)) {
2640 Diag(SlotLoc, diag::err_hlsl_register_number_too_large);
2641 return;
2642 }
2643
2644 // the slot number has been validated and does not exceed UINT32_MAX
2645 SlotNum = (unsigned)N;
2646 }
2647
2648 // Validate space
2649 if (!Space.starts_with("space")) {
2650 Diag(SpaceLoc, diag::err_hlsl_expected_space) << Space;
2651 return;
2652 }
2653 StringRef SpaceNumStr = Space.substr(5);
2654 if (SpaceNumStr.getAsInteger(10, SpaceNum)) {
2655 Diag(SpaceLoc, diag::err_hlsl_expected_space) << Space;
2656 return;
2657 }
2658
2659 // If we have slot, diagnose it is the right register type for the decl
2660 if (SlotNum.has_value())
2661 if (!DiagnoseHLSLRegisterAttribute(SemaRef, SlotLoc, TheDecl, RegType,
2662 !SpaceLoc.isInvalid()))
2663 return;
2664
2665 HLSLResourceBindingAttr *NewAttr =
2666 HLSLResourceBindingAttr::Create(getASTContext(), Slot, Space, AL);
2667 if (NewAttr) {
2668 NewAttr->setBinding(RegType, SlotNum, SpaceNum);
2669 TheDecl->addAttr(NewAttr);
2670 }
2671}
2672
2674 HLSLParamModifierAttr *NewAttr = mergeParamModifierAttr(
2675 D, AL,
2676 static_cast<HLSLParamModifierAttr::Spelling>(AL.getSemanticSpelling()));
2677 if (NewAttr)
2678 D->addAttr(NewAttr);
2679}
2680
2681static bool isMatrixOrArrayOfMatrix(const ASTContext &Ctx, QualType QT) {
2682 const Type *Ty = QT->getUnqualifiedDesugaredType();
2683 while (isa<ArrayType>(Ty))
2685 return Ty->isDependentType() || Ty->isConstantMatrixType();
2686}
2687
2688/// Walks the existing AttributedType sugar of \p T looking for a previously
2689/// applied HLSLRowMajor/HLSLColumnMajor marker. If one is found, populates
2690/// \p ExistingKind with its attr::Kind and returns true.
2692 attr::Kind &ExistingKind) {
2693 QualType Cur = T;
2694 while (const auto *AT = Cur->getAs<AttributedType>()) {
2695 attr::Kind K = AT->getAttrKind();
2696 if (K == attr::HLSLRowMajor || K == attr::HLSLColumnMajor) {
2697 ExistingKind = K;
2698 return true;
2699 }
2700 Cur = AT->getModifiedType();
2701 }
2702 return false;
2703}
2704
2706 if (T.isNull())
2707 return nullptr;
2708
2709 ASTContext &Ctx = getASTContext();
2710 attr::Kind AttrK = AL.getKind() == ParsedAttr::AT_HLSLRowMajor
2711 ? attr::HLSLRowMajor
2712 : attr::HLSLColumnMajor;
2713
2714 // For non-dependent types, the operand must be a matrix (or array of
2715 // matrices).
2716 if (!T->isDependentType() && !isMatrixOrArrayOfMatrix(Ctx, T)) {
2717 Diag(AL.getLoc(), diag::err_hlsl_matrix_layout_non_matrix)
2718 << AL.getAttrName();
2719 AL.setInvalid();
2720 return nullptr;
2721 }
2722
2723 // Conflict / duplicate detection by walking existing sugar.
2724 attr::Kind ExistingKind;
2725 if (findExistingMatrixLayoutMarker(T, ExistingKind)) {
2726 if (ExistingKind == AttrK) {
2727 Diag(AL.getLoc(), diag::warn_duplicate_attribute_exact)
2728 << AL.getAttrName();
2729 Diag(AL.getLoc(), diag::note_previous_attribute);
2730 return nullptr;
2731 }
2732 IdentifierInfo *ExistingII = &Ctx.Idents.get(
2733 ExistingKind == attr::HLSLRowMajor ? "row_major" : "column_major");
2734 Diag(AL.getLoc(), diag::err_hlsl_matrix_layout_conflict)
2735 << AL.getAttrName() << ExistingII;
2736 Diag(AL.getLoc(), diag::note_conflicting_attribute);
2737 AL.setInvalid();
2738 return nullptr;
2739 }
2740
2741 if (AttrK == attr::HLSLRowMajor)
2742 return ::new (Ctx) HLSLRowMajorAttr(Ctx, AL);
2743 return ::new (Ctx) HLSLColumnMajorAttr(Ctx, AL);
2744}
2745
2746// Re-validates an HLSL `row_major` / `column_major` attribute after template
2747// substitution. The parse-time check in `buildMatrixLayoutTypeAttr` is skipped
2748// for dependent types; `TransformAttributedType` calls this once the type is
2749// concrete. Returns `true` (and emits a diagnostic) if the substituted type is
2750// not a matrix or array of matrices, signaling the caller to abort the
2751// transform.
2753 SourceLocation Loc) {
2754 if (K != attr::HLSLRowMajor && K != attr::HLSLColumnMajor)
2755 return false;
2756 if (T.isNull() || T->isDependentType())
2757 return false;
2759 return false;
2761 K == attr::HLSLRowMajor ? "row_major" : "column_major");
2762 Diag(Loc, diag::err_hlsl_matrix_layout_non_matrix) << II;
2763 return true;
2764}
2765
2766// Transpose and matrix mul need to read the destination layout.
2767// Elementwise builtins reuse the operand layout instead.
2768static bool isLayoutAdaptingMatrixBuiltin(unsigned BuiltinID) {
2769 switch (BuiltinID) {
2770 case Builtin::BI__builtin_hlsl_mul:
2771 case Builtin::BI__builtin_hlsl_transpose:
2772 return true;
2773 default:
2774 return false;
2775 }
2776}
2777
2779 if (!E || DestType.isNull())
2780 return;
2781 const auto *DestMat = DestType->getAs<ConstantMatrixType>();
2782 if (!DestMat)
2783 return;
2784 auto *Call = dyn_cast<CallExpr>(E->IgnoreParenImpCasts());
2785 if (!Call)
2786 return;
2787 const FunctionDecl *Callee = Call->getDirectCallee();
2788 if (!Callee || !isLayoutAdaptingMatrixBuiltin(Callee->getBuiltinID()))
2789 return;
2790 const auto *CallMat = Call->getType()->getAs<ConstantMatrixType>();
2791 if (!CallMat || CallMat->getNumRows() != DestMat->getNumRows() ||
2792 CallMat->getNumColumns() != DestMat->getNumColumns())
2793 return;
2794 // Re-type the call with the destination sugar so CodeGen lowers into that
2795 // layout, not the TU default.
2796 Call->setType(DestType.getUnqualifiedType());
2797}
2798
2799namespace {
2800
2801/// This class implements HLSL availability diagnostics for default
2802/// and relaxed mode
2803///
2804/// The goal of this diagnostic is to emit an error or warning when an
2805/// unavailable API is found in code that is reachable from the shader
2806/// entry function or from an exported function (when compiling a shader
2807/// library).
2808///
2809/// This is done by traversing the AST of all shader entry point functions
2810/// and of all exported functions, and any functions that are referenced
2811/// from this AST. In other words, any functions that are reachable from
2812/// the entry points.
2813class DiagnoseHLSLAvailability : public DynamicRecursiveASTVisitor {
2814 Sema &SemaRef;
2815
2816 // Stack of functions to be scaned
2818
2819 // Tracks which environments functions have been scanned in.
2820 //
2821 // Maps FunctionDecl to an unsigned number that represents the set of shader
2822 // environments the function has been scanned for.
2823 // The llvm::Triple::EnvironmentType enum values for shader stages guaranteed
2824 // to be numbered from llvm::Triple::Pixel to llvm::Triple::Amplification
2825 // (verified by static_asserts in Triple.cpp), we can use it to index
2826 // individual bits in the set, as long as we shift the values to start with 0
2827 // by subtracting the value of llvm::Triple::Pixel first.
2828 //
2829 // The N'th bit in the set will be set if the function has been scanned
2830 // in shader environment whose llvm::Triple::EnvironmentType integer value
2831 // equals (llvm::Triple::Pixel + N).
2832 //
2833 // For example, if a function has been scanned in compute and pixel stage
2834 // environment, the value will be 0x21 (100001 binary) because:
2835 //
2836 // (int)(llvm::Triple::Pixel - llvm::Triple::Pixel) == 0
2837 // (int)(llvm::Triple::Compute - llvm::Triple::Pixel) == 5
2838 //
2839 // A FunctionDecl is mapped to 0 (or not included in the map) if it has not
2840 // been scanned in any environment.
2841 llvm::DenseMap<const FunctionDecl *, unsigned> ScannedDecls;
2842
2843 // Do not access these directly, use the get/set methods below to make
2844 // sure the values are in sync
2845 llvm::Triple::EnvironmentType CurrentShaderEnvironment;
2846 unsigned CurrentShaderStageBit;
2847
2848 // True if scanning a function that was already scanned in a different
2849 // shader stage context, and therefore we should not report issues that
2850 // depend only on shader model version because they would be duplicate.
2851 bool ReportOnlyShaderStageIssues;
2852
2853 // Helper methods for dealing with current stage context / environment
2854 void SetShaderStageContext(llvm::Triple::EnvironmentType ShaderType) {
2855 static_assert(sizeof(unsigned) >= 4);
2856 assert(HLSLShaderAttr::isValidShaderType(ShaderType));
2857 assert((unsigned)(ShaderType - llvm::Triple::Pixel) < 31 &&
2858 "ShaderType is too big for this bitmap"); // 31 is reserved for
2859 // "unknown"
2860
2861 unsigned bitmapIndex = ShaderType - llvm::Triple::Pixel;
2862 CurrentShaderEnvironment = ShaderType;
2863 CurrentShaderStageBit = (1 << bitmapIndex);
2864 }
2865
2866 void SetUnknownShaderStageContext() {
2867 CurrentShaderEnvironment = llvm::Triple::UnknownEnvironment;
2868 CurrentShaderStageBit = (1 << 31);
2869 }
2870
2871 llvm::Triple::EnvironmentType GetCurrentShaderEnvironment() const {
2872 return CurrentShaderEnvironment;
2873 }
2874
2875 bool InUnknownShaderStageContext() const {
2876 return CurrentShaderEnvironment == llvm::Triple::UnknownEnvironment;
2877 }
2878
2879 // Helper methods for dealing with shader stage bitmap
2880 void AddToScannedFunctions(const FunctionDecl *FD) {
2881 unsigned &ScannedStages = ScannedDecls[FD];
2882 ScannedStages |= CurrentShaderStageBit;
2883 }
2884
2885 unsigned GetScannedStages(const FunctionDecl *FD) { return ScannedDecls[FD]; }
2886
2887 bool WasAlreadyScannedInCurrentStage(const FunctionDecl *FD) {
2888 return WasAlreadyScannedInCurrentStage(GetScannedStages(FD));
2889 }
2890
2891 bool WasAlreadyScannedInCurrentStage(unsigned ScannerStages) {
2892 return ScannerStages & CurrentShaderStageBit;
2893 }
2894
2895 static bool NeverBeenScanned(unsigned ScannedStages) {
2896 return ScannedStages == 0;
2897 }
2898
2899 // Scanning methods
2900 void HandleFunctionOrMethodRef(FunctionDecl *FD, Expr *RefExpr);
2901 void CheckDeclAvailability(NamedDecl *D, const AvailabilityAttr *AA,
2902 SourceRange Range);
2903 const AvailabilityAttr *FindAvailabilityAttr(const Decl *D);
2904 bool HasMatchingEnvironmentOrNone(const AvailabilityAttr *AA);
2905
2906public:
2907 DiagnoseHLSLAvailability(Sema &SemaRef)
2908 : SemaRef(SemaRef),
2909 CurrentShaderEnvironment(llvm::Triple::UnknownEnvironment),
2910 CurrentShaderStageBit(0), ReportOnlyShaderStageIssues(false) {}
2911
2912 // AST traversal methods
2913 void RunOnTranslationUnit(const TranslationUnitDecl *TU);
2914 void RunOnFunction(const FunctionDecl *FD);
2915
2916 bool VisitDeclRefExpr(DeclRefExpr *DRE) override {
2917 FunctionDecl *FD = llvm::dyn_cast<FunctionDecl>(DRE->getDecl());
2918 if (FD)
2919 HandleFunctionOrMethodRef(FD, DRE);
2920 return true;
2921 }
2922
2923 bool VisitMemberExpr(MemberExpr *ME) override {
2924 FunctionDecl *FD = llvm::dyn_cast<FunctionDecl>(ME->getMemberDecl());
2925 if (FD)
2926 HandleFunctionOrMethodRef(FD, ME);
2927 return true;
2928 }
2929};
2930
2931void DiagnoseHLSLAvailability::HandleFunctionOrMethodRef(FunctionDecl *FD,
2932 Expr *RefExpr) {
2933 assert((isa<DeclRefExpr>(RefExpr) || isa<MemberExpr>(RefExpr)) &&
2934 "expected DeclRefExpr or MemberExpr");
2935
2936 if (const AvailabilityAttr *AA = FindAvailabilityAttr(FD))
2937 CheckDeclAvailability(
2938 FD, AA, SourceRange(RefExpr->getBeginLoc(), RefExpr->getEndLoc()));
2939
2940 // has a definition -> add to stack to be scanned
2941 const FunctionDecl *FDWithBody = nullptr;
2942 if (FD->hasBody(FDWithBody) && !WasAlreadyScannedInCurrentStage(FDWithBody))
2943 DeclsToScan.push_back(FDWithBody);
2944}
2945
2946void DiagnoseHLSLAvailability::RunOnTranslationUnit(
2947 const TranslationUnitDecl *TU) {
2948 const TargetInfo &TargetInfo = SemaRef.getASTContext().getTargetInfo();
2949 std::string &EntryName = TargetInfo.getTargetOpts().HLSLEntry;
2950 bool IsLibraryShader = TargetInfo.getTriple().getEnvironment() ==
2951 llvm::Triple::EnvironmentType::Library;
2952 SourceLocation EntryLoc{};
2953
2954 // Iterate over all shader entry functions and library exports, and for those
2955 // that have a body (definiton), run diag scan on each, setting appropriate
2956 // shader environment context based on whether it is a shader entry function
2957 // or an exported function. Exported functions can be in namespaces and in
2958 // export declarations so we need to scan those declaration contexts as well.
2960 DeclContextsToScan.push_back(TU);
2961
2962 while (!DeclContextsToScan.empty()) {
2963 const DeclContext *DC = DeclContextsToScan.pop_back_val();
2964 for (auto &D : DC->decls()) {
2965 // do not scan implicit declaration generated by the implementation
2966 if (D->isImplicit())
2967 continue;
2968
2969 // for namespace or export declaration add the context to the list to be
2970 // scanned later
2971 if (llvm::dyn_cast<NamespaceDecl>(D) || llvm::dyn_cast<ExportDecl>(D)) {
2972 DeclContextsToScan.push_back(llvm::dyn_cast<DeclContext>(D));
2973 continue;
2974 }
2975
2976 // skip over other decls or function decls without body
2977 const FunctionDecl *FD = llvm::dyn_cast<FunctionDecl>(D);
2978 if (!FD || !FD->isThisDeclarationADefinition())
2979 continue;
2980
2981 // shader entry point
2982 if (HLSLShaderAttr *ShaderAttr = FD->getAttr<HLSLShaderAttr>()) {
2983 if (!IsLibraryShader && FD->getName() == EntryName) {
2984 if (EntryLoc.isValid()) {
2985 SemaRef.Diag(FD->getLocation(),
2986 diag::err_hlsl_ambiguous_entry_point)
2987 << EntryName;
2988 SemaRef.Diag(EntryLoc, diag::note_previous_declaration_as)
2989 << EntryName;
2990 return;
2991 }
2992 EntryLoc = FD->getLocation();
2993 }
2994 SetShaderStageContext(ShaderAttr->getType());
2995 RunOnFunction(FD);
2996 continue;
2997 }
2998 // exported library function
2999 // FIXME: replace this loop with external linkage check once issue #92071
3000 // is resolved
3001 bool isExport = FD->isInExportDeclContext();
3002 if (!isExport) {
3003 for (const auto *Redecl : FD->redecls()) {
3004 if (Redecl->isInExportDeclContext()) {
3005 isExport = true;
3006 break;
3007 }
3008 }
3009 }
3010 if (isExport) {
3011 SetUnknownShaderStageContext();
3012 RunOnFunction(FD);
3013 continue;
3014 }
3015 }
3016 }
3017
3018 if (!IsLibraryShader && EntryLoc.isInvalid()) {
3019 SemaRef.Diag(TU->getLocation(), diag::err_hlsl_missing_entry_point)
3020 << EntryName;
3021 return;
3022 }
3023}
3024
3025void DiagnoseHLSLAvailability::RunOnFunction(const FunctionDecl *FD) {
3026 assert(DeclsToScan.empty() && "DeclsToScan should be empty");
3027 DeclsToScan.push_back(FD);
3028
3029 while (!DeclsToScan.empty()) {
3030 // Take one decl from the stack and check it by traversing its AST.
3031 // For any CallExpr found during the traversal add it's callee to the top of
3032 // the stack to be processed next. Functions already processed are stored in
3033 // ScannedDecls.
3034 const FunctionDecl *FD = DeclsToScan.pop_back_val();
3035
3036 // Decl was already scanned
3037 const unsigned ScannedStages = GetScannedStages(FD);
3038 if (WasAlreadyScannedInCurrentStage(ScannedStages))
3039 continue;
3040
3041 ReportOnlyShaderStageIssues = !NeverBeenScanned(ScannedStages);
3042
3043 AddToScannedFunctions(FD);
3044 TraverseStmt(FD->getBody());
3045 }
3046}
3047
3048bool DiagnoseHLSLAvailability::HasMatchingEnvironmentOrNone(
3049 const AvailabilityAttr *AA) {
3050 const IdentifierInfo *IIEnvironment = AA->getEnvironment();
3051 if (!IIEnvironment)
3052 return true;
3053
3054 llvm::Triple::EnvironmentType CurrentEnv = GetCurrentShaderEnvironment();
3055 if (CurrentEnv == llvm::Triple::UnknownEnvironment)
3056 return false;
3057
3058 llvm::Triple::EnvironmentType AttrEnv =
3059 AvailabilityAttr::getEnvironmentType(IIEnvironment->getName());
3060
3061 return CurrentEnv == AttrEnv;
3062}
3063
3064const AvailabilityAttr *
3065DiagnoseHLSLAvailability::FindAvailabilityAttr(const Decl *D) {
3066 AvailabilityAttr const *PartialMatch = nullptr;
3067 // Check each AvailabilityAttr to find the one for this platform.
3068 // For multiple attributes with the same platform try to find one for this
3069 // environment.
3070 for (const auto *A : D->attrs()) {
3071 if (const auto *Avail = dyn_cast<AvailabilityAttr>(A)) {
3072 const AvailabilityAttr *EffectiveAvail = Avail->getEffectiveAttr();
3073 StringRef AttrPlatform = EffectiveAvail->getPlatform()->getName();
3074 StringRef TargetPlatform =
3076
3077 // Match the platform name.
3078 if (AttrPlatform == TargetPlatform) {
3079 // Find the best matching attribute for this environment
3080 if (HasMatchingEnvironmentOrNone(EffectiveAvail))
3081 return Avail;
3082 PartialMatch = Avail;
3083 }
3084 }
3085 }
3086 return PartialMatch;
3087}
3088
3089// Check availability against target shader model version and current shader
3090// stage and emit diagnostic
3091void DiagnoseHLSLAvailability::CheckDeclAvailability(NamedDecl *D,
3092 const AvailabilityAttr *AA,
3093 SourceRange Range) {
3094
3095 const IdentifierInfo *IIEnv = AA->getEnvironment();
3096
3097 if (!IIEnv) {
3098 // The availability attribute does not have environment -> it depends only
3099 // on shader model version and not on specific the shader stage.
3100
3101 // Skip emitting the diagnostics if the diagnostic mode is set to
3102 // strict (-fhlsl-strict-availability) because all relevant diagnostics
3103 // were already emitted in the DiagnoseUnguardedAvailability scan
3104 // (SemaAvailability.cpp).
3105 if (SemaRef.getLangOpts().HLSLStrictAvailability)
3106 return;
3107
3108 // Do not report shader-stage-independent issues if scanning a function
3109 // that was already scanned in a different shader stage context (they would
3110 // be duplicate)
3111 if (ReportOnlyShaderStageIssues)
3112 return;
3113
3114 } else {
3115 // The availability attribute has environment -> we need to know
3116 // the current stage context to property diagnose it.
3117 if (InUnknownShaderStageContext())
3118 return;
3119 }
3120
3121 // Check introduced version and if environment matches
3122 bool EnvironmentMatches = HasMatchingEnvironmentOrNone(AA);
3123 VersionTuple Introduced = AA->getIntroduced();
3124 VersionTuple TargetVersion =
3126
3127 if (TargetVersion >= Introduced && EnvironmentMatches)
3128 return;
3129
3130 // Emit diagnostic message
3131 const TargetInfo &TI = SemaRef.getASTContext().getTargetInfo();
3132 llvm::StringRef PlatformName(
3133 AvailabilityAttr::getPrettyPlatformName(TI.getPlatformName()));
3134
3135 llvm::StringRef CurrentEnvStr =
3136 llvm::Triple::getEnvironmentTypeName(GetCurrentShaderEnvironment());
3137
3138 llvm::StringRef AttrEnvStr =
3139 AA->getEnvironment() ? AA->getEnvironment()->getName() : "";
3140 bool UseEnvironment = !AttrEnvStr.empty();
3141
3142 if (EnvironmentMatches) {
3143 SemaRef.Diag(Range.getBegin(), diag::warn_hlsl_availability)
3144 << Range << D << PlatformName << Introduced.getAsString()
3145 << UseEnvironment << CurrentEnvStr;
3146 } else {
3147 SemaRef.Diag(Range.getBegin(), diag::warn_hlsl_availability_unavailable)
3148 << Range << D;
3149 }
3150
3151 SemaRef.Diag(D->getLocation(), diag::note_partial_availability_specified_here)
3152 << D << PlatformName << Introduced.getAsString()
3153 << SemaRef.Context.getTargetInfo().getPlatformMinVersion().getAsString()
3154 << UseEnvironment << AttrEnvStr << CurrentEnvStr;
3155}
3156
3157} // namespace
3158
3160 // process default CBuffer - create buffer layout struct and invoke codegenCGH
3161 if (!DefaultCBufferDecls.empty()) {
3163 SemaRef.getASTContext(), SemaRef.getCurLexicalContext(),
3164 DefaultCBufferDecls);
3165 addImplicitBindingAttrToDecl(SemaRef, DefaultCBuffer, RegisterType::CBuffer,
3167 SemaRef.getCurLexicalContext()->addDecl(DefaultCBuffer);
3169
3170 // Set HasValidPackoffset if any of the decls has a register(c#) annotation;
3171 for (const Decl *VD : DefaultCBufferDecls) {
3172 const HLSLResourceBindingAttr *RBA =
3173 VD->getAttr<HLSLResourceBindingAttr>();
3174 if (RBA && RBA->hasRegisterSlot() &&
3175 RBA->getRegisterType() == HLSLResourceBindingAttr::RegisterType::C) {
3176 DefaultCBuffer->setHasValidPackoffset(true);
3177 break;
3178 }
3179 }
3180
3181 DeclGroupRef DG(DefaultCBuffer);
3182 SemaRef.Consumer.HandleTopLevelDecl(DG);
3183 }
3184 diagnoseAvailabilityViolations(TU);
3185}
3186
3187// For resource member access through a global struct array, verify that the
3188// array index selecting the struct element is a constant integer expression.
3189// Returns false if the member expression is invalid.
3191 assert((ME->getType()->isHLSLResourceRecord() ||
3193 "expected member expr to have resource record type or array of them");
3194
3195 // Walk the AST from MemberExpr to the VarDecl of the parent struct instance
3196 // and take note of any non-constant array indexing along the way. If the
3197 // VarDecl we find is a global variable, report error if there was any
3198 // non-constant array index in the resource member access along the way.
3199 const Expr *NonConstIndexExpr = nullptr;
3200 const Expr *E = ME->getBase();
3201 while (E) {
3202 if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
3203 if (!NonConstIndexExpr)
3204 return true;
3205
3206 const VarDecl *VD = cast<VarDecl>(DRE->getDecl());
3207 if (!VD->hasGlobalStorage())
3208 return true;
3209
3210 SemaRef.Diag(NonConstIndexExpr->getExprLoc(),
3211 diag::err_hlsl_resource_member_array_access_not_constant);
3212 return false;
3213 }
3214
3215 if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(E)) {
3216 const Expr *IdxExpr = ASE->getIdx();
3217 if (!IdxExpr->isIntegerConstantExpr(SemaRef.getASTContext()))
3218 NonConstIndexExpr = IdxExpr;
3219 E = ASE->getBase();
3220 } else if (const auto *SubME = dyn_cast<MemberExpr>(E)) {
3221 E = SubME->getBase();
3222 } else if (const auto *ICE = dyn_cast<ImplicitCastExpr>(E)) {
3223 E = ICE->getSubExpr();
3224 } else {
3225 llvm_unreachable("unexpected expr type in resource member access");
3226 }
3227 }
3228 return true;
3229}
3230
3232 CXXRecordDecl *RD) {
3233 QualType AddrSpaceType =
3234 SemaRef.Context.getCanonicalType(SemaRef.Context.getAddrSpaceQualType(
3235 Type.withConst(), LangAS::hlsl_constant));
3236 QualType ReturnTy = SemaRef.Context.getCanonicalType(
3237 SemaRef.Context.getLValueReferenceType(AddrSpaceType));
3238
3239 DeclarationName ConvName =
3240 SemaRef.Context.DeclarationNames.getCXXConversionFunctionName(
3241 CanQualType::CreateUnsafe(ReturnTy));
3242 LookupResult ConvR(SemaRef, ConvName, SourceLocation(),
3244 [[maybe_unused]] bool LookupSucceeded =
3245 SemaRef.LookupQualifiedName(ConvR, RD);
3246 assert(LookupSucceeded);
3247
3248 for (NamedDecl *D : ConvR) {
3250 return D;
3251 }
3252 return nullptr;
3253}
3254
3255std::optional<ExprResult>
3257 QualType BaseType = BaseExpr->getType();
3258 const HLSLAttributedResourceType *ResTy =
3259 HLSLAttributedResourceType::findHandleTypeOnResource(
3260 BaseType.getTypePtr());
3261 if (!ResTy ||
3262 ResTy->getAttrs().ResourceClass != llvm::dxil::ResourceClass::CBuffer)
3263 return std::nullopt;
3264
3265 QualType TemplateType = ResTy->getContainedType();
3266
3267 NamedDecl *NamedConversionDecl = getConstantBufferConversionFunction(
3268 TemplateType, BaseType->getAsCXXRecordDecl());
3269 assert(NamedConversionDecl &&
3270 "Could not find conversion function for ConstantBuffer.");
3271 auto *ConversionDecl =
3272 cast<CXXConversionDecl>(NamedConversionDecl->getUnderlyingDecl());
3273
3274 return SemaRef.BuildCXXMemberCallExpr(BaseExpr, NamedConversionDecl,
3275 ConversionDecl,
3276 /*HadMultipleCandidates=*/false);
3277}
3278
3279void SemaHLSL::diagnoseAvailabilityViolations(TranslationUnitDecl *TU) {
3280 // Skip running the diagnostics scan if the diagnostic mode is
3281 // strict (-fhlsl-strict-availability) and the target shader stage is known
3282 // because all relevant diagnostics were already emitted in the
3283 // DiagnoseUnguardedAvailability scan (SemaAvailability.cpp).
3285 if (SemaRef.getLangOpts().HLSLStrictAvailability &&
3286 TI.getTriple().getEnvironment() != llvm::Triple::EnvironmentType::Library)
3287 return;
3288
3289 DiagnoseHLSLAvailability(SemaRef).RunOnTranslationUnit(TU);
3290}
3291
3292static bool CheckAllArgsHaveSameType(Sema *S, CallExpr *TheCall) {
3293 assert(TheCall->getNumArgs() > 1);
3294 QualType ArgTy0 = TheCall->getArg(0)->getType();
3295
3296 for (unsigned I = 1, N = TheCall->getNumArgs(); I < N; ++I) {
3298 ArgTy0, TheCall->getArg(I)->getType())) {
3299 S->Diag(TheCall->getBeginLoc(), diag::err_vec_builtin_incompatible_vector)
3300 << TheCall->getDirectCallee() << /*useAllTerminology*/ true
3301 << SourceRange(TheCall->getArg(0)->getBeginLoc(),
3302 TheCall->getArg(N - 1)->getEndLoc());
3303 return true;
3304 }
3305 }
3306 return false;
3307}
3308
3310 QualType ArgType = Arg->getType();
3312 S->Diag(Arg->getBeginLoc(), diag::err_typecheck_convert_incompatible)
3313 << ArgType << ExpectedType << 1 << 0 << 0;
3314 return true;
3315 }
3316 return false;
3317}
3318
3320 Sema *S, CallExpr *TheCall,
3321 llvm::function_ref<bool(Sema *S, SourceLocation Loc, int ArgOrdinal,
3322 clang::QualType PassedType)>
3323 Check) {
3324 for (unsigned I = 0; I < TheCall->getNumArgs(); ++I) {
3325 Expr *Arg = TheCall->getArg(I);
3326 if (Check(S, Arg->getBeginLoc(), I + 1, Arg->getType()))
3327 return true;
3328 }
3329 return false;
3330}
3331
3333 int ArgOrdinal,
3334 clang::QualType PassedType) {
3335 clang::QualType BaseType =
3336 PassedType->isVectorType()
3337 ? PassedType->castAs<clang::VectorType>()->getElementType()
3338 : PassedType;
3339 if (!BaseType->isFloat32Type())
3340 return S->Diag(Loc, diag::err_builtin_invalid_arg_type)
3341 << ArgOrdinal << /* scalar or vector of */ 5 << /* no int */ 0
3342 << /* float */ 1 << PassedType;
3343 return false;
3344}
3345
3347 int ArgOrdinal,
3348 clang::QualType PassedType) {
3349 clang::QualType BaseType = PassedType;
3350 if (const auto *VT = PassedType->getAs<clang::VectorType>())
3351 BaseType = VT->getElementType();
3352 else if (const auto *MT = PassedType->getAs<clang::MatrixType>())
3353 BaseType = MT->getElementType();
3354
3355 if (!BaseType->isHalfType() && !BaseType->isFloat32Type())
3356 return S->Diag(Loc, diag::err_builtin_invalid_arg_type)
3357 << ArgOrdinal << /* scalar or vector of */ 5 << /* no int */ 0
3358 << /* half or float */ 2 << PassedType;
3359 return false;
3360}
3361
3363 int ArgOrdinal,
3364 clang::QualType PassedType) {
3365 clang::QualType BaseType =
3366 PassedType->isVectorType()
3367 ? PassedType->castAs<clang::VectorType>()->getElementType()
3368 : PassedType->isMatrixType()
3369 ? PassedType->castAs<clang::MatrixType>()->getElementType()
3370 : PassedType;
3371 if (!BaseType->isDoubleType()) {
3372 // FIXME: adopt standard `err_builtin_invalid_arg_type` instead of using
3373 // this custom error.
3374 return S->Diag(Loc, diag::err_builtin_requires_double_type)
3375 << ArgOrdinal << PassedType;
3376 }
3377
3378 return false;
3379}
3380
3381static bool CheckModifiableLValue(Sema *S, CallExpr *TheCall,
3382 unsigned ArgIndex) {
3383 auto *Arg = TheCall->getArg(ArgIndex);
3384 SourceLocation OrigLoc = Arg->getExprLoc();
3385 if (Arg->IgnoreCasts()->isModifiableLvalue(S->Context, &OrigLoc) ==
3387 return false;
3388 S->Diag(OrigLoc, diag::error_hlsl_inout_lvalue) << Arg << 0;
3389 return true;
3390}
3391
3392// Verifies that the argument at `ArgIndex` of `TheCall` refers to memory in
3393// one of `AllowedSpaces`. Intended for HLSL builtins (e.g. atomics).
3394static bool CheckArgAddrSpaceOneOf(Sema *S, CallExpr *TheCall,
3395 unsigned ArgIndex,
3396 ArrayRef<LangAS> AllowedSpaces) {
3397 Expr *Arg = TheCall->getArg(ArgIndex);
3398 QualType LValueTy = Arg->IgnoreCasts()->getType();
3399 if (llvm::is_contained(AllowedSpaces, LValueTy.getAddressSpace()))
3400 return false;
3401 S->Diag(Arg->getBeginLoc(), diag::err_hlsl_atomic_arg_addr_space)
3402 << (ArgIndex + 1) << LValueTy;
3403 return true;
3404}
3405
3406static bool CheckNoDoubleVectors(Sema *S, SourceLocation Loc, int ArgOrdinal,
3407 clang::QualType PassedType) {
3408 const auto *VecTy = PassedType->getAs<VectorType>();
3409 if (!VecTy)
3410 return false;
3411
3412 if (VecTy->getElementType()->isDoubleType())
3413 return S->Diag(Loc, diag::err_builtin_invalid_arg_type)
3414 << ArgOrdinal << /* scalar */ 1 << /* no int */ 0 << /* fp */ 1
3415 << PassedType;
3416 return false;
3417}
3418
3420 int ArgOrdinal,
3421 clang::QualType PassedType) {
3422 if (!PassedType->hasIntegerRepresentation() &&
3423 !PassedType->hasFloatingRepresentation())
3424 return S->Diag(Loc, diag::err_builtin_invalid_arg_type)
3425 << ArgOrdinal << /* scalar or vector of */ 5 << /* integer */ 1
3426 << /* fp */ 1 << PassedType;
3427 return false;
3428}
3429
3431 int ArgOrdinal,
3432 clang::QualType PassedType) {
3433 if (auto *VecTy = PassedType->getAs<VectorType>())
3434 if (VecTy->getElementType()->isUnsignedIntegerType())
3435 return false;
3436
3437 return S->Diag(Loc, diag::err_builtin_invalid_arg_type)
3438 << ArgOrdinal << /* vector of */ 4 << /* uint */ 3 << /* no fp */ 0
3439 << PassedType;
3440}
3441
3442// checks for unsigned ints of all sizes
3444 int ArgOrdinal,
3445 clang::QualType PassedType) {
3446 if (!PassedType->hasUnsignedIntegerRepresentation())
3447 return S->Diag(Loc, diag::err_builtin_invalid_arg_type)
3448 << ArgOrdinal << /* scalar or vector of */ 5 << /* unsigned int */ 3
3449 << /* no fp */ 0 << PassedType;
3450 return false;
3451}
3452
3453static bool CheckExpectedBitWidth(Sema *S, CallExpr *TheCall,
3454 unsigned ArgOrdinal, unsigned Width) {
3455 QualType ArgTy = TheCall->getArg(0)->getType();
3456 if (auto *VTy = ArgTy->getAs<VectorType>())
3457 ArgTy = VTy->getElementType();
3458 // ensure arg type has expected bit width
3459 uint64_t ElementBitCount =
3461 if (ElementBitCount != Width) {
3462 S->Diag(TheCall->getArg(0)->getBeginLoc(),
3463 diag::err_integer_incorrect_bit_count)
3464 << Width << ElementBitCount;
3465 return true;
3466 }
3467 return false;
3468}
3469
3471 QualType ReturnType) {
3472 if (auto *VecTyA = TheCall->getArg(0)->getType()->getAs<VectorType>())
3473 ReturnType =
3474 S->Context.getExtVectorType(ReturnType, VecTyA->getNumElements());
3475 else if (auto *MatTyA =
3476 TheCall->getArg(0)->getType()->getAs<ConstantMatrixType>())
3477 ReturnType = S->Context.getConstantMatrixType(
3478 ReturnType, MatTyA->getNumRows(), MatTyA->getNumColumns());
3479
3480 TheCall->setType(ReturnType);
3481}
3482
3483static bool CheckScalarOrVector(Sema *S, CallExpr *TheCall, QualType Scalar,
3484 unsigned ArgIndex) {
3485 assert(TheCall->getNumArgs() >= ArgIndex);
3486 QualType ArgType = TheCall->getArg(ArgIndex)->getType();
3487 auto *VTy = ArgType->getAs<VectorType>();
3488 // not the scalar or vector<scalar>
3489 if (!(S->Context.hasSameUnqualifiedType(ArgType, Scalar) ||
3490 (VTy &&
3491 S->Context.hasSameUnqualifiedType(VTy->getElementType(), Scalar)))) {
3492 S->Diag(TheCall->getArg(0)->getBeginLoc(),
3493 diag::err_typecheck_expect_scalar_or_vector)
3494 << ArgType << Scalar;
3495 return true;
3496 }
3497 return false;
3498}
3499
3501 QualType Scalar, unsigned ArgIndex) {
3502 assert(TheCall->getNumArgs() > ArgIndex);
3503
3504 Expr *Arg = TheCall->getArg(ArgIndex);
3505 QualType ArgType = Arg->getType();
3506
3507 // Scalar: T
3508 if (S->Context.hasSameUnqualifiedType(ArgType, Scalar))
3509 return false;
3510
3511 // Vector: vector<T>
3512 if (const auto *VTy = ArgType->getAs<VectorType>()) {
3513 if (S->Context.hasSameUnqualifiedType(VTy->getElementType(), Scalar))
3514 return false;
3515 }
3516
3517 // Matrix: ConstantMatrixType with element type T
3518 if (const auto *MTy = ArgType->getAs<ConstantMatrixType>()) {
3519 if (S->Context.hasSameUnqualifiedType(MTy->getElementType(), Scalar))
3520 return false;
3521 }
3522
3523 // Not a scalar/vector/matrix-of-scalar
3524 S->Diag(Arg->getBeginLoc(),
3525 diag::err_typecheck_expect_scalar_or_vector_or_matrix)
3526 << ArgType << Scalar;
3527 return true;
3528}
3529
3530static bool CheckAnyScalarOrVector(Sema *S, CallExpr *TheCall,
3531 unsigned ArgIndex) {
3532 assert(TheCall->getNumArgs() >= ArgIndex);
3533 QualType ArgType = TheCall->getArg(ArgIndex)->getType();
3534 auto *VTy = ArgType->getAs<VectorType>();
3535 // not the scalar or vector<scalar>
3536 if (!(ArgType->isScalarType() ||
3537 (VTy && VTy->getElementType()->isScalarType()))) {
3538 S->Diag(TheCall->getArg(0)->getBeginLoc(),
3539 diag::err_typecheck_expect_any_scalar_or_vector_or_matrix)
3540 << ArgType << 1;
3541 return true;
3542 }
3543 return false;
3544}
3545
3547 unsigned ArgIndex) {
3548 assert(TheCall->getNumArgs() > ArgIndex);
3549 QualType ArgType = TheCall->getArg(ArgIndex)->getType();
3550 if (ArgType->isDependentType())
3551 return false;
3552
3553 QualType ElementType = ArgType;
3554 if (const auto *VectorTy = ArgType->getAs<VectorType>())
3555 ElementType = VectorTy->getElementType();
3556 else if (const auto *MatrixTy = ArgType->getAs<ConstantMatrixType>())
3557 ElementType = MatrixTy->getElementType();
3558
3559 if (ElementType->isBooleanType())
3560 return false;
3561
3562 if (ElementType->isIntegerType() || ElementType->isRealFloatingType()) {
3563 unsigned BitWidth = S->Context.getTypeSize(ElementType);
3564 if (BitWidth == 16 || BitWidth == 32 || BitWidth == 64)
3565 return false;
3566 }
3567
3568 S->Diag(TheCall->getArg(ArgIndex)->getBeginLoc(),
3569 diag::err_typecheck_expect_any_scalar_or_vector_or_matrix)
3570 << ArgType << 2;
3571 return true;
3572}
3573
3574// Check that the argument is not a bool or vector<bool>
3575// Returns true on error
3577 unsigned ArgIndex) {
3578 QualType BoolType = S->getASTContext().BoolTy;
3579 assert(ArgIndex < TheCall->getNumArgs());
3580 QualType ArgType = TheCall->getArg(ArgIndex)->getType();
3581 auto *VTy = ArgType->getAs<VectorType>();
3582 // is the bool or vector<bool>
3583 if (S->Context.hasSameUnqualifiedType(ArgType, BoolType) ||
3584 (VTy &&
3585 S->Context.hasSameUnqualifiedType(VTy->getElementType(), BoolType))) {
3586 S->Diag(TheCall->getArg(0)->getBeginLoc(),
3587 diag::err_typecheck_expect_any_scalar_or_vector_or_matrix)
3588 << ArgType << 0;
3589 return true;
3590 }
3591 return false;
3592}
3593
3594static bool CheckWaveActive(Sema *S, CallExpr *TheCall) {
3595 if (CheckNotBoolScalarOrVector(S, TheCall, 0))
3596 return true;
3597 return false;
3598}
3599
3600static bool CheckWavePrefix(Sema *S, CallExpr *TheCall) {
3601 if (CheckNotBoolScalarOrVector(S, TheCall, 0))
3602 return true;
3603 return false;
3604}
3605
3606static bool CheckBoolSelect(Sema *S, CallExpr *TheCall) {
3607 assert(TheCall->getNumArgs() == 3);
3608 Expr *Arg1 = TheCall->getArg(1);
3609 Expr *Arg2 = TheCall->getArg(2);
3610 if (!S->Context.hasSameUnqualifiedType(Arg1->getType(), Arg2->getType())) {
3611 S->Diag(TheCall->getBeginLoc(),
3612 diag::err_typecheck_call_different_arg_types)
3613 << Arg1->getType() << Arg2->getType() << Arg1->getSourceRange()
3614 << Arg2->getSourceRange();
3615 return true;
3616 }
3617
3618 TheCall->setType(Arg1->getType());
3619 return false;
3620}
3621
3622static bool CheckVectorSelect(Sema *S, CallExpr *TheCall) {
3623 assert(TheCall->getNumArgs() == 3);
3624 Expr *Arg1 = TheCall->getArg(1);
3625 QualType Arg1Ty = Arg1->getType();
3626 Expr *Arg2 = TheCall->getArg(2);
3627 QualType Arg2Ty = Arg2->getType();
3628
3629 QualType Arg1ScalarTy = Arg1Ty;
3630 if (auto VTy = Arg1ScalarTy->getAs<VectorType>())
3631 Arg1ScalarTy = VTy->getElementType();
3632
3633 QualType Arg2ScalarTy = Arg2Ty;
3634 if (auto VTy = Arg2ScalarTy->getAs<VectorType>())
3635 Arg2ScalarTy = VTy->getElementType();
3636
3637 if (!S->Context.hasSameUnqualifiedType(Arg1ScalarTy, Arg2ScalarTy))
3638 S->Diag(Arg1->getBeginLoc(), diag::err_hlsl_builtin_scalar_vector_mismatch)
3639 << /* second and third */ 1 << TheCall->getCallee() << Arg1Ty << Arg2Ty;
3640
3641 QualType Arg0Ty = TheCall->getArg(0)->getType();
3642 unsigned Arg0Length = Arg0Ty->getAs<VectorType>()->getNumElements();
3643 unsigned Arg1Length = Arg1Ty->isVectorType()
3644 ? Arg1Ty->getAs<VectorType>()->getNumElements()
3645 : 0;
3646 unsigned Arg2Length = Arg2Ty->isVectorType()
3647 ? Arg2Ty->getAs<VectorType>()->getNumElements()
3648 : 0;
3649 if (Arg1Length > 0 && Arg0Length != Arg1Length) {
3650 S->Diag(TheCall->getBeginLoc(),
3651 diag::err_typecheck_vector_lengths_not_equal)
3652 << Arg0Ty << Arg1Ty << TheCall->getArg(0)->getSourceRange()
3653 << Arg1->getSourceRange();
3654 return true;
3655 }
3656
3657 if (Arg2Length > 0 && Arg0Length != Arg2Length) {
3658 S->Diag(TheCall->getBeginLoc(),
3659 diag::err_typecheck_vector_lengths_not_equal)
3660 << Arg0Ty << Arg2Ty << TheCall->getArg(0)->getSourceRange()
3661 << Arg2->getSourceRange();
3662 return true;
3663 }
3664
3665 TheCall->setType(
3666 S->getASTContext().getExtVectorType(Arg1ScalarTy, Arg0Length));
3667 return false;
3668}
3669
3671 unsigned Count) {
3672 return Count > 1 ? S.Context.getExtVectorType(BaseType, Count) : BaseType;
3673}
3674
3675static bool CheckScalarFloatOperand(Sema &S, CallExpr *TheCall,
3676 unsigned ArgIndex) {
3677 return CheckArgTypeMatches(&S, TheCall->getArg(ArgIndex), S.Context.FloatTy);
3678}
3679
3680static bool CheckIndexType(Sema *S, CallExpr *TheCall, unsigned IndexArgIndex) {
3681 assert(TheCall->getNumArgs() > IndexArgIndex && "Index argument missing");
3682 QualType ArgType = TheCall->getArg(IndexArgIndex)->getType();
3683 QualType IndexTy = ArgType;
3684 unsigned int ActualDim = 1;
3685 if (const auto *VTy = IndexTy->getAs<VectorType>()) {
3686 ActualDim = VTy->getNumElements();
3687 IndexTy = VTy->getElementType();
3688 }
3689 if (!IndexTy->isIntegerType()) {
3690 S->Diag(TheCall->getArg(IndexArgIndex)->getBeginLoc(),
3691 diag::err_typecheck_expect_int)
3692 << ArgType;
3693 return true;
3694 }
3695
3696 QualType ResourceArgTy = TheCall->getArg(0)->getType();
3697 const HLSLAttributedResourceType *ResTy =
3698 ResourceArgTy.getTypePtr()->getAs<HLSLAttributedResourceType>();
3699 assert(ResTy && "Resource argument must be a resource");
3700 HLSLAttributedResourceType::Attributes ResAttrs = ResTy->getAttrs();
3701
3702 unsigned int ExpectedDim = 1;
3703 if (ResAttrs.ResourceDimension != llvm::dxil::ResourceDimension::Unknown)
3704 ExpectedDim = getResourceDimensions(ResAttrs.ResourceDimension) +
3705 (ResAttrs.IsArray ? 1 : 0);
3706
3707 if (ActualDim != ExpectedDim) {
3708 S->Diag(TheCall->getArg(IndexArgIndex)->getBeginLoc(),
3709 diag::err_hlsl_builtin_resource_coordinate_dimension_mismatch)
3710 << cast<NamedDecl>(TheCall->getCalleeDecl()) << ExpectedDim
3711 << ActualDim;
3712 return true;
3713 }
3714
3715 return false;
3716}
3717
3719 Sema *S, CallExpr *TheCall, unsigned ArgIndex,
3720 llvm::function_ref<bool(const HLSLAttributedResourceType *ResType)> Check =
3721 nullptr) {
3722 assert(TheCall->getNumArgs() >= ArgIndex);
3723 QualType ArgType = TheCall->getArg(ArgIndex)->getType();
3724 const HLSLAttributedResourceType *ResTy =
3725 ArgType.getTypePtr()->getAs<HLSLAttributedResourceType>();
3726 if (!ResTy) {
3727 S->Diag(TheCall->getArg(ArgIndex)->getBeginLoc(),
3728 diag::err_typecheck_expect_hlsl_resource)
3729 << ArgType;
3730 return true;
3731 }
3732 if (Check && Check(ResTy)) {
3733 S->Diag(TheCall->getArg(ArgIndex)->getExprLoc(),
3734 diag::err_invalid_hlsl_resource_type)
3735 << ArgType;
3736 return true;
3737 }
3738 return false;
3739}
3740
3742 QualType MainHandleTy) {
3743 assert(MainHandleTy->isHLSLAttributedResourceType() &&
3744 "expected resource handle type");
3745 auto *MainResType = MainHandleTy->getAs<HLSLAttributedResourceType>();
3746 auto MainAttrs = MainResType->getAttrs();
3747 assert(!MainAttrs.IsCounter && "cannot create a counter from a counter");
3748 MainAttrs.IsCounter = true;
3749 return AST.getHLSLAttributedResourceType(MainResType->getWrappedType(),
3750 MainResType->getContainedType(),
3751 MainAttrs);
3752}
3753
3754enum class SampleKind { Sample, Bias, Grad, Level, Cmp, CmpLevelZero };
3755
3756static StringRef getSampleMethodName(SampleKind Kind) {
3757 switch (Kind) {
3758 case SampleKind::Sample:
3759 return "Sample";
3760 case SampleKind::Bias:
3761 return "SampleBias";
3762 case SampleKind::Grad:
3763 return "SampleGrad";
3764 case SampleKind::Level:
3765 return "SampleLevel";
3766 case SampleKind::Cmp:
3767 return "SampleCmp";
3769 return "SampleCmpLevelZero";
3770 }
3771 llvm_unreachable("Invalid SampleKind");
3772}
3773
3774// Returns the name of the resource method whose body the sampling or gather
3775// builtin is being emitted into, which is the name the user called. This
3776// matters for methods that share a builtin, like 'Gather' and 'GatherRed'.
3777// Falls back to DefaultName if the builtin is used outside of a resource
3778// method.
3779static StringRef getCurrentResourceMethodName(Sema &S, StringRef DefaultName) {
3780 const auto *MD = dyn_cast_if_present<CXXMethodDecl>(S.getCurFunctionDecl());
3781 if (!MD || !MD->getDeclName().isIdentifier())
3782 return DefaultName;
3783
3784 QualType RecordTy = S.Context.getCanonicalTagType(MD->getParent());
3785 if (!RecordTy->isHLSLResourceRecord())
3786 return DefaultName;
3787
3788 return MD->getName();
3789}
3790
3791// Returns the element type of a typed resource's contained type. Typed resource
3792// element types are scalars or vectors of scalars, so anything that is not a
3793// vector is already the element type.
3795 if (const auto *VecTy = ContainedType->getAs<VectorType>())
3796 return VecTy->getElementType();
3797 return ContainedType;
3798}
3799
3800// Sampling from and gathering on resources with a 'double' element type is not
3801// supported. Such resources are still valid declarations whose contents can be
3802// accessed by other means, like Load or the subscript operator.
3803static bool CheckNoDoubleElementType(Sema &S, CallExpr *TheCall,
3804 QualType ContainedType,
3805 StringRef DefaultName) {
3806 QualType EltTy = getTypedResourceElementType(ContainedType);
3807 if (!EltTy->isSpecificBuiltinType(BuiltinType::Double))
3808 return false;
3809
3810 S.Diag(TheCall->getBeginLoc(), diag::err_hlsl_sample_double_element_type)
3811 << getCurrentResourceMethodName(S, DefaultName) << ContainedType;
3812 return true;
3813}
3814
3815// Sampling textures with an integer element type was introduced in SM 6.7 as
3816// part of Advanced Texture Operations. The shader model only applies to DirectX
3817// targets; Vulkan has no such restriction.
3819 QualType ContainedType,
3820 SampleKind Kind) {
3821 // Comparison sampling requires a floating point element type at every shader
3822 // model, which the caller diagnoses.
3823 if (Kind == SampleKind::Cmp || Kind == SampleKind::CmpLevelZero)
3824 return false;
3825
3826 // 'bool' is an integer type in HLSL, but sampling bool resources is never
3827 // allowed, so it must not be reported as requiring shader model 6.7.
3828 QualType EltTy = getTypedResourceElementType(ContainedType);
3829 if (!EltTy->isIntegerType() || EltTy->isBooleanType())
3830 return false;
3831
3832 const TargetInfo &TI = S.Context.getTargetInfo();
3833 if (!TI.getTriple().isDXIL())
3834 return false;
3835
3836 VersionTuple SMVersion = TI.getPlatformMinVersion();
3837 if (SMVersion >= VersionTuple(6, 7))
3838 return false;
3839
3840 S.Diag(TheCall->getBeginLoc(), diag::err_hlsl_sample_integer_element_type)
3842 << ContainedType << SMVersion.getAsString();
3843 return true;
3844}
3845
3847 bool IncludeArraySlice = true) {
3848 // Check the texture handle.
3849 if (CheckResourceHandle(&S, TheCall, 0,
3850 [](const HLSLAttributedResourceType *ResType) {
3851 return ResType->getAttrs().ResourceDimension ==
3852 llvm::dxil::ResourceDimension::Unknown;
3853 }))
3854 return true;
3855
3856 // Check the sampler handle.
3857 if (CheckResourceHandle(&S, TheCall, 1,
3858 [](const HLSLAttributedResourceType *ResType) {
3859 return ResType->getAttrs().ResourceClass !=
3860 llvm::hlsl::ResourceClass::Sampler;
3861 }))
3862 return true;
3863
3864 auto *ResourceTy =
3865 TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
3866
3867 // Check the location.
3868 unsigned ExpectedDim =
3869 getResourceDimensions(ResourceTy->getAttrs().ResourceDimension) +
3870 (IncludeArraySlice && ResourceTy->getAttrs().IsArray ? 1 : 0);
3872 &S, TheCall->getArg(2),
3873 getVectorOrScalarType(S, S.Context.FloatTy, ExpectedDim)))
3874 return true;
3875
3876 return false;
3877}
3878
3879static bool CheckCalculateLodBuiltin(Sema &S, CallExpr *TheCall) {
3880 if (S.checkArgCount(TheCall, 3))
3881 return true;
3882
3883 // CalculateLevelOfDetail location uses resource dimension only (e.g. float2
3884 // for 2D), not an extra array slice component like Sample/Gather.
3885 if (CheckTextureSamplerAndLocation(S, TheCall, /*IncludeArraySlice=*/false))
3886 return true;
3887
3888 TheCall->setType(S.Context.FloatTy);
3889 return false;
3890}
3891
3892static bool CheckGatherBuiltin(Sema &S, CallExpr *TheCall, bool IsCmp) {
3893 if (S.checkArgCountRange(TheCall, IsCmp ? 5 : 4, IsCmp ? 6 : 5))
3894 return true;
3895
3896 if (CheckTextureSamplerAndLocation(S, TheCall))
3897 return true;
3898
3899 unsigned NextIdx = 3;
3900 if (IsCmp) {
3901 // Check the compare value.
3902 if (CheckScalarFloatOperand(S, TheCall, NextIdx))
3903 return true;
3904 NextIdx++;
3905 }
3906
3907 // Check the component operand.
3908 if (CheckArgTypeMatches(&S, TheCall->getArg(NextIdx),
3910 return true;
3911 Expr *ComponentArg = TheCall->getArg(NextIdx);
3912
3913 // GatherCmp operations on Vulkan target must use component 0 (Red).
3914 if (IsCmp && S.getASTContext().getTargetInfo().getTriple().isSPIRV()) {
3915 std::optional<llvm::APSInt> ComponentOpt =
3916 ComponentArg->getIntegerConstantExpr(S.getASTContext());
3917 if (ComponentOpt) {
3918 int64_t ComponentVal = ComponentOpt->getSExtValue();
3919 if (ComponentVal != 0) {
3920 // Issue an error if the component is not 0 (Red).
3921 // 0 -> Red, 1 -> Green, 2 -> Blue, 3 -> Alpha
3922 assert(ComponentVal >= 0 && ComponentVal <= 3 &&
3923 "The component is not in the expected range.");
3924 S.Diag(ComponentArg->getBeginLoc(),
3925 diag::err_hlsl_gathercmp_invalid_component)
3926 << ComponentVal;
3927 return true;
3928 }
3929 }
3930 }
3931
3932 NextIdx++;
3933
3934 // Check the offset operand.
3935 const HLSLAttributedResourceType *ResourceTy =
3936 TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
3937 if (TheCall->getNumArgs() > NextIdx) {
3938 unsigned ExpectedDim =
3939 getResourceDimensions(ResourceTy->getAttrs().ResourceDimension);
3941 &S, TheCall->getArg(NextIdx),
3942 getVectorOrScalarType(S, S.Context.IntTy, ExpectedDim)))
3943 return true;
3944 NextIdx++;
3945 }
3946
3947 assert(ResourceTy->hasContainedType() &&
3948 "Expecting a contained type for resource with a dimension "
3949 "attribute.");
3950 QualType ReturnType = ResourceTy->getContainedType();
3951
3952 if (CheckNoDoubleElementType(S, TheCall, ReturnType,
3953 IsCmp ? "GatherCmp" : "Gather"))
3954 return true;
3955
3956 if (IsCmp) {
3957 if (!ReturnType->hasFloatingRepresentation()) {
3958 S.Diag(TheCall->getBeginLoc(), diag::err_hlsl_samplecmp_requires_float);
3959 return true;
3960 }
3961 }
3962
3963 if (const auto *VecTy = ReturnType->getAs<VectorType>())
3964 ReturnType = VecTy->getElementType();
3965 ReturnType = S.Context.getExtVectorType(ReturnType, 4);
3966
3967 TheCall->setType(ReturnType);
3968
3969 return false;
3970}
3971static bool CheckLoadLevelBuiltin(Sema &S, CallExpr *TheCall) {
3972 if (S.checkArgCountRange(TheCall, 2, 3))
3973 return true;
3974
3975 // Check the texture handle.
3976 if (CheckResourceHandle(&S, TheCall, 0,
3977 [](const HLSLAttributedResourceType *ResType) {
3978 return ResType->getAttrs().ResourceDimension ==
3979 llvm::dxil::ResourceDimension::Unknown;
3980 }))
3981 return true;
3982
3983 auto *ResourceTy =
3984 TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
3985
3986 // A UAV descriptor binds a single mip slice, so a RWTexture location has no
3987 // mip component to select, and TextureLoad on a UAV takes no offset.
3988 bool IsUAV =
3989 ResourceTy->getAttrs().ResourceClass == llvm::dxil::ResourceClass::UAV;
3990 if (IsUAV && S.checkArgCount(TheCall, 2))
3991 return true;
3992
3993 // Check the location: int3 for Texture2D and int4 for Texture2DArray, which
3994 // both carry a trailing mip level; int2 and int3 for the RWTexture forms,
3995 // which do not.
3996 unsigned ResourceDim =
3997 getResourceDimensions(ResourceTy->getAttrs().ResourceDimension);
3998 unsigned LocationDim = ResourceDim + (ResourceTy->getAttrs().IsArray ? 1 : 0);
3999 if (!IsUAV)
4000 ++LocationDim;
4002 &S, TheCall->getArg(1),
4003 getVectorOrScalarType(S, S.Context.IntTy, LocationDim)))
4004 return true;
4005
4006 // Check the offset operand (int2 for 2D textures; no array slice).
4007 if (TheCall->getNumArgs() > 2) {
4009 &S, TheCall->getArg(2),
4010 getVectorOrScalarType(S, S.Context.IntTy, ResourceDim)))
4011 return true;
4012 }
4013
4014 TheCall->setType(ResourceTy->getContainedType());
4015 return false;
4016}
4017
4018static bool CheckLoadMSBuiltin(Sema &S, CallExpr *TheCall) {
4019 if (S.checkArgCountRange(TheCall, 3, 4))
4020 return true;
4021
4022 // Check the multisampled texture handle.
4023 if (CheckResourceHandle(&S, TheCall, 0,
4024 [](const HLSLAttributedResourceType *ResType) {
4025 return !ResType->isMultiSampled();
4026 }))
4027 return true;
4028
4029 auto *ResourceTy =
4030 TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
4031
4032 // Check the location (int2 for Texture2DMS, int3 for Texture2DMSArray).
4033 // Unlike Load on regular textures, there is no mip/LOD component.
4034 unsigned ResourceDim =
4035 getResourceDimensions(ResourceTy->getAttrs().ResourceDimension);
4036 unsigned LocationDim = ResourceDim + (ResourceTy->getAttrs().IsArray ? 1 : 0);
4038 &S, TheCall->getArg(1),
4039 getVectorOrScalarType(S, S.Context.IntTy, LocationDim)))
4040 return true;
4041
4042 // Check the sample index operand (scalar int).
4043 if (CheckArgTypeMatches(&S, TheCall->getArg(2), S.Context.IntTy))
4044 return true;
4045
4046 // Check the offset operand (int2 for 2D textures; no array slice).
4047 if (TheCall->getNumArgs() > 3) {
4049 &S, TheCall->getArg(3),
4050 getVectorOrScalarType(S, S.Context.IntTy, ResourceDim)))
4051 return true;
4052 }
4053
4054 TheCall->setType(ResourceTy->getContainedType());
4055 return false;
4056}
4057
4058static bool CheckSamplingBuiltin(Sema &S, CallExpr *TheCall, SampleKind Kind) {
4059 unsigned MinArgs, MaxArgs;
4060 if (Kind == SampleKind::Sample) {
4061 MinArgs = 3;
4062 MaxArgs = 5;
4063 } else if (Kind == SampleKind::Bias) {
4064 MinArgs = 4;
4065 MaxArgs = 6;
4066 } else if (Kind == SampleKind::Grad) {
4067 MinArgs = 5;
4068 MaxArgs = 7;
4069 } else if (Kind == SampleKind::Level) {
4070 MinArgs = 4;
4071 MaxArgs = 5;
4072 } else if (Kind == SampleKind::Cmp) {
4073 MinArgs = 4;
4074 MaxArgs = 6;
4075 } else {
4076 assert(Kind == SampleKind::CmpLevelZero);
4077 MinArgs = 4;
4078 MaxArgs = 5;
4079 }
4080
4081 if (S.checkArgCountRange(TheCall, MinArgs, MaxArgs))
4082 return true;
4083
4084 if (CheckTextureSamplerAndLocation(S, TheCall))
4085 return true;
4086
4087 const HLSLAttributedResourceType *ResourceTy =
4088 TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
4089 unsigned ExpectedDim =
4090 getResourceDimensions(ResourceTy->getAttrs().ResourceDimension);
4091
4092 unsigned NextIdx = 3;
4093 if (Kind == SampleKind::Bias || Kind == SampleKind::Level ||
4094 Kind == SampleKind::Cmp || Kind == SampleKind::CmpLevelZero) {
4095 // Check the bias, lod level, or compare value, depending on the kind.
4096 // All of them must be a scalar float value.
4097 if (CheckScalarFloatOperand(S, TheCall, NextIdx))
4098 return true;
4099 NextIdx++;
4100 } else if (Kind == SampleKind::Grad) {
4101 QualType GradTy = getVectorOrScalarType(S, S.Context.FloatTy, ExpectedDim);
4102
4103 // Check the DDX operand.
4104 if (CheckArgTypeMatches(&S, TheCall->getArg(NextIdx), GradTy))
4105 return true;
4106
4107 // Check the DDY operand.
4108 if (CheckArgTypeMatches(&S, TheCall->getArg(NextIdx + 1), GradTy))
4109 return true;
4110 NextIdx += 2;
4111 }
4112
4113 // Check the offset operand (if applicable).
4114 if (hasResourceOffset(ResourceTy->getAttrs().ResourceDimension) &&
4115 TheCall->getNumArgs() > NextIdx) {
4117 &S, TheCall->getArg(NextIdx),
4118 getVectorOrScalarType(S, S.Context.IntTy, ExpectedDim)))
4119 return true;
4120 NextIdx++;
4121 }
4122
4123 // Check the clamp operand.
4124 if (Kind != SampleKind::Level && Kind != SampleKind::CmpLevelZero &&
4125 TheCall->getNumArgs() > NextIdx) {
4126 if (CheckScalarFloatOperand(S, TheCall, NextIdx))
4127 return true;
4128 }
4129
4130 assert(ResourceTy->hasContainedType() &&
4131 "Expecting a contained type for resource with a dimension "
4132 "attribute.");
4133 QualType ReturnType = ResourceTy->getContainedType();
4134
4135 if (CheckNoDoubleElementType(S, TheCall, ReturnType,
4136 getSampleMethodName(Kind)))
4137 return true;
4138
4139 if (CheckIntegerElementTypeShaderModel(S, TheCall, ReturnType, Kind))
4140 return true;
4141
4142 if (Kind == SampleKind::Cmp || Kind == SampleKind::CmpLevelZero) {
4143 if (!ReturnType->hasFloatingRepresentation()) {
4144 S.Diag(TheCall->getBeginLoc(), diag::err_hlsl_samplecmp_requires_float);
4145 return true;
4146 }
4147 ReturnType = S.Context.FloatTy;
4148 }
4149 TheCall->setType(ReturnType);
4150
4151 return false;
4152}
4153
4154// Note: returning true in this case results in CheckBuiltinFunctionCall
4155// returning an ExprError
4156bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
4157 switch (BuiltinID) {
4158 case Builtin::BI__builtin_hlsl_adduint64: {
4159 if (SemaRef.checkArgCount(TheCall, 2))
4160 return true;
4161
4162 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
4164 return true;
4165
4166 // ensure arg integers are 32-bits
4167 if (CheckExpectedBitWidth(&SemaRef, TheCall, 0, 32))
4168 return true;
4169
4170 // ensure both args are vectors of total bit size of a multiple of 64
4171 auto *VTy = TheCall->getArg(0)->getType()->getAs<VectorType>();
4172 int NumElementsArg = VTy->getNumElements();
4173 if (NumElementsArg != 2 && NumElementsArg != 4) {
4174 SemaRef.Diag(TheCall->getBeginLoc(), diag::err_vector_incorrect_bit_count)
4175 << 1 /*a multiple of*/ << 64 << NumElementsArg * 32;
4176 return true;
4177 }
4178
4179 // ensure first arg and second arg have the same type
4180 if (CheckAllArgsHaveSameType(&SemaRef, TheCall))
4181 return true;
4182
4183 ExprResult A = TheCall->getArg(0);
4184 QualType ArgTyA = A.get()->getType();
4185 // return type is the same as the input type
4186 TheCall->setType(ArgTyA);
4187 break;
4188 }
4189 case Builtin::BI__builtin_hlsl_resource_getpointer: {
4190 if (SemaRef.checkArgCountRange(TheCall, 1, 2) ||
4191 CheckResourceHandle(&SemaRef, TheCall, 0) ||
4192 (TheCall->getNumArgs() == 2 && CheckIndexType(&SemaRef, TheCall, 1)))
4193 return true;
4194
4195 auto *ResourceTy =
4196 TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
4197 QualType ContainedTy = ResourceTy->getContainedType();
4198 auto ReturnType = SemaRef.Context.getAddrSpaceQualType(
4199 ContainedTy,
4200 getLangASFromResourceClass(ResourceTy->getAttrs().ResourceClass));
4201 ReturnType = SemaRef.Context.getPointerType(ReturnType);
4202 TheCall->setType(ReturnType);
4203
4204 break;
4205 }
4206 case Builtin::BI__builtin_hlsl_resource_getpointer_typed: {
4207 if (SemaRef.checkArgCount(TheCall, 3) ||
4208 CheckResourceHandle(&SemaRef, TheCall, 0) ||
4209 CheckIndexType(&SemaRef, TheCall, 1))
4210 return true;
4211
4212 QualType ElementTy = TheCall->getArg(2)->getType();
4213 assert(ElementTy->isPointerType() &&
4214 "expected pointer type for second argument");
4215 ElementTy = ElementTy->getPointeeType();
4216
4217 // Reject array types
4218 if (ElementTy->isArrayType())
4219 return SemaRef.Diag(
4220 cast<FunctionDecl>(SemaRef.CurContext)->getPointOfInstantiation(),
4221 diag::err_invalid_use_of_array_type);
4222
4223 auto *ResourceTy =
4224 TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
4225 auto ReturnType = SemaRef.Context.getAddrSpaceQualType(
4226 ElementTy,
4227 getLangASFromResourceClass(ResourceTy->getAttrs().ResourceClass));
4228 ReturnType = SemaRef.Context.getPointerType(ReturnType);
4229 TheCall->setType(ReturnType);
4230
4231 break;
4232 }
4233 case Builtin::BI__builtin_hlsl_transpose_if_memory_is_row_major: {
4234 if (SemaRef.checkArgCount(TheCall, 2) ||
4235 CheckArgTypeMatches(&SemaRef, TheCall->getArg(1),
4236 SemaRef.getASTContext().IntTy))
4237 return true;
4238
4239 TheCall->setType(TheCall->getArg(0)->getType());
4240
4241 break;
4242 }
4243 case Builtin::BI__builtin_hlsl_resource_load_with_status: {
4244 if (SemaRef.checkArgCount(TheCall, 3) ||
4245 CheckResourceHandle(&SemaRef, TheCall, 0) ||
4246 CheckArgTypeMatches(&SemaRef, TheCall->getArg(1),
4247 SemaRef.getASTContext().UnsignedIntTy) ||
4248 CheckArgTypeMatches(&SemaRef, TheCall->getArg(2),
4249 SemaRef.getASTContext().UnsignedIntTy) ||
4250 CheckModifiableLValue(&SemaRef, TheCall, 2))
4251 return true;
4252
4253 auto *ResourceTy =
4254 TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
4255 QualType ReturnType = ResourceTy->getContainedType();
4256 TheCall->setType(ReturnType);
4257
4258 break;
4259 }
4260 case Builtin::BI__builtin_hlsl_resource_load_with_status_typed: {
4261 if (SemaRef.checkArgCount(TheCall, 4) ||
4262 CheckResourceHandle(&SemaRef, TheCall, 0) ||
4263 CheckArgTypeMatches(&SemaRef, TheCall->getArg(1),
4264 SemaRef.getASTContext().UnsignedIntTy) ||
4265 CheckArgTypeMatches(&SemaRef, TheCall->getArg(2),
4266 SemaRef.getASTContext().UnsignedIntTy) ||
4267 CheckModifiableLValue(&SemaRef, TheCall, 2))
4268 return true;
4269
4270 QualType ReturnType = TheCall->getArg(3)->getType();
4271 assert(ReturnType->isPointerType() &&
4272 "expected pointer type for second argument");
4273 ReturnType = ReturnType->getPointeeType();
4274
4275 // Reject array types
4276 if (ReturnType->isArrayType())
4277 return SemaRef.Diag(
4278 cast<FunctionDecl>(SemaRef.CurContext)->getPointOfInstantiation(),
4279 diag::err_invalid_use_of_array_type);
4280
4281 TheCall->setType(ReturnType);
4282
4283 break;
4284 }
4285 case Builtin::BI__builtin_hlsl_resource_load_level:
4286 return CheckLoadLevelBuiltin(SemaRef, TheCall);
4287 case Builtin::BI__builtin_hlsl_resource_load_ms:
4288 return CheckLoadMSBuiltin(SemaRef, TheCall);
4289 case Builtin::BI__builtin_hlsl_resource_sample:
4291 case Builtin::BI__builtin_hlsl_resource_sample_bias:
4293 case Builtin::BI__builtin_hlsl_resource_sample_grad:
4295 case Builtin::BI__builtin_hlsl_resource_sample_level:
4297 case Builtin::BI__builtin_hlsl_resource_sample_cmp:
4299 case Builtin::BI__builtin_hlsl_resource_sample_cmp_level_zero:
4301 case Builtin::BI__builtin_hlsl_resource_calculate_lod:
4302 case Builtin::BI__builtin_hlsl_resource_calculate_lod_unclamped:
4303 return CheckCalculateLodBuiltin(SemaRef, TheCall);
4304 case Builtin::BI__builtin_hlsl_resource_gather:
4305 return CheckGatherBuiltin(SemaRef, TheCall, /*IsCmp=*/false);
4306 case Builtin::BI__builtin_hlsl_resource_gather_cmp:
4307 return CheckGatherBuiltin(SemaRef, TheCall, /*IsCmp=*/true);
4308 case Builtin::BI__builtin_hlsl_resource_uninitializedhandle: {
4309 assert(TheCall->getNumArgs() == 1 && "expected 1 arg");
4310 // Update return type to be the attributed resource type from arg0.
4311 QualType ResourceTy = TheCall->getArg(0)->getType();
4312 TheCall->setType(ResourceTy);
4313 break;
4314 }
4315 case Builtin::BI__builtin_hlsl_resource_handlefrombinding: {
4316 assert(TheCall->getNumArgs() == 6 && "expected 6 args");
4317 // Update return type to be the attributed resource type from arg0.
4318 QualType ResourceTy = TheCall->getArg(0)->getType();
4319 TheCall->setType(ResourceTy);
4320 break;
4321 }
4322 case Builtin::BI__builtin_hlsl_resource_handlefromimplicitbinding: {
4323 assert(TheCall->getNumArgs() == 6 && "expected 6 args");
4324 // Update return type to be the attributed resource type from arg0.
4325 QualType ResourceTy = TheCall->getArg(0)->getType();
4326 TheCall->setType(ResourceTy);
4327 break;
4328 }
4329 case Builtin::BI__builtin_hlsl_resource_counterhandlefromimplicitbinding: {
4330 assert(TheCall->getNumArgs() == 3 && "expected 3 args");
4331 // Update return type to be the attributed resource type from arg0
4332 // with added IsCounter flag.
4333 QualType MainHandleTy = TheCall->getArg(0)->getType();
4334 QualType CounterHandleTy =
4335 createCounterHandleType(SemaRef.getASTContext(), MainHandleTy);
4336 TheCall->setType(CounterHandleTy);
4337 break;
4338 }
4339 case Builtin::BI__builtin_hlsl_resource_handlefromheap: {
4340 if (SemaRef.checkArgCount(TheCall, 2) ||
4341 CheckResourceHandle(&SemaRef, TheCall, 0) ||
4342 CheckArgTypeMatches(&SemaRef, TheCall->getArg(1),
4343 SemaRef.getASTContext().UnsignedIntTy))
4344 return true;
4345
4346 // Update return type to be the attributed resource type from arg0.
4347 QualType ResourceTy = TheCall->getArg(0)->getType();
4348 TheCall->setType(ResourceTy);
4349 break;
4350 }
4351 case Builtin::BI__builtin_hlsl_resource_counterhandlefromheap: {
4352 if (SemaRef.checkArgCount(TheCall, 1) ||
4353 CheckResourceHandle(&SemaRef, TheCall, 0))
4354 return true;
4355 // Update return type to be the attributed resource type from arg0
4356 // with added IsCounter flag.
4357 QualType MainHandleTy = TheCall->getArg(0)->getType();
4358 QualType CounterHandleTy =
4359 createCounterHandleType(SemaRef.getASTContext(), MainHandleTy);
4360 TheCall->setType(CounterHandleTy);
4361 break;
4362 }
4363 case Builtin::BI__builtin_hlsl_and:
4364 case Builtin::BI__builtin_hlsl_or: {
4365 if (SemaRef.checkArgCount(TheCall, 2))
4366 return true;
4367 if (CheckScalarOrVectorOrMatrix(&SemaRef, TheCall, getASTContext().BoolTy,
4368 0))
4369 return true;
4370 if (CheckAllArgsHaveSameType(&SemaRef, TheCall))
4371 return true;
4372
4373 ExprResult A = TheCall->getArg(0);
4374 QualType ArgTyA = A.get()->getType();
4375 // return type is the same as the input type
4376 TheCall->setType(ArgTyA);
4377 break;
4378 }
4379 case Builtin::BI__builtin_hlsl_all:
4380 case Builtin::BI__builtin_hlsl_any: {
4381 if (SemaRef.checkArgCount(TheCall, 1))
4382 return true;
4383 if (CheckAnyScalarOrVector(&SemaRef, TheCall, 0))
4384 return true;
4385 break;
4386 }
4387 case Builtin::BI__builtin_hlsl_asdouble: {
4388 if (SemaRef.checkArgCount(TheCall, 2))
4389 return true;
4391 &SemaRef, TheCall,
4392 /*only check for uint*/ SemaRef.Context.UnsignedIntTy,
4393 /* arg index */ 0))
4394 return true;
4396 &SemaRef, TheCall,
4397 /*only check for uint*/ SemaRef.Context.UnsignedIntTy,
4398 /* arg index */ 1))
4399 return true;
4400 if (CheckAllArgsHaveSameType(&SemaRef, TheCall))
4401 return true;
4402
4403 SetElementTypeAsReturnType(&SemaRef, TheCall, getASTContext().DoubleTy);
4404 break;
4405 }
4406 case Builtin::BI__builtin_hlsl_elementwise_clamp: {
4407 if (SemaRef.BuiltinElementwiseTernaryMath(
4408 TheCall, /*ArgTyRestr=*/
4410 return true;
4411 break;
4412 }
4413 case Builtin::BI__builtin_hlsl_dot: {
4414 // arg count is checked by BuiltinVectorToScalarMath
4415 if (SemaRef.BuiltinVectorToScalarMath(TheCall))
4416 return true;
4418 return true;
4419 break;
4420 }
4421 case Builtin::BI__builtin_hlsl_elementwise_firstbithigh:
4422 case Builtin::BI__builtin_hlsl_elementwise_firstbitlow: {
4423 if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall))
4424 return true;
4425
4426 const Expr *Arg = TheCall->getArg(0);
4427 QualType ArgTy = Arg->getType();
4428 QualType EltTy = ArgTy;
4429
4430 QualType ResTy = SemaRef.Context.UnsignedIntTy;
4431
4432 if (auto *VecTy = EltTy->getAs<VectorType>()) {
4433 EltTy = VecTy->getElementType();
4434 ResTy = SemaRef.Context.getExtVectorType(ResTy, VecTy->getNumElements());
4435 }
4436
4437 if (!EltTy->isIntegerType()) {
4438 Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
4439 << 1 << /* scalar or vector of */ 5 << /* integer ty */ 1
4440 << /* no fp */ 0 << ArgTy;
4441 return true;
4442 }
4443
4444 TheCall->setType(ResTy);
4445 break;
4446 }
4447 case Builtin::BI__builtin_hlsl_select: {
4448 if (SemaRef.checkArgCount(TheCall, 3))
4449 return true;
4450 if (CheckScalarOrVector(&SemaRef, TheCall, getASTContext().BoolTy, 0))
4451 return true;
4452 QualType ArgTy = TheCall->getArg(0)->getType();
4453 if (ArgTy->isBooleanType() && CheckBoolSelect(&SemaRef, TheCall))
4454 return true;
4455 auto *VTy = ArgTy->getAs<VectorType>();
4456 if (VTy && VTy->getElementType()->isBooleanType() &&
4457 CheckVectorSelect(&SemaRef, TheCall))
4458 return true;
4459 break;
4460 }
4461 case Builtin::BI__builtin_hlsl_elementwise_saturate:
4462 case Builtin::BI__builtin_hlsl_elementwise_rcp: {
4463 if (SemaRef.checkArgCount(TheCall, 1))
4464 return true;
4465 if (!TheCall->getArg(0)
4466 ->getType()
4467 ->hasFloatingRepresentation()) // half or float or double
4468 return SemaRef.Diag(TheCall->getArg(0)->getBeginLoc(),
4469 diag::err_builtin_invalid_arg_type)
4470 << /* ordinal */ 1 << /* scalar or vector */ 5 << /* no int */ 0
4471 << /* fp */ 1 << TheCall->getArg(0)->getType();
4472 if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall))
4473 return true;
4474 break;
4475 }
4476 case Builtin::BI__builtin_hlsl_elementwise_rsqrt:
4477 case Builtin::BI__builtin_hlsl_elementwise_frac:
4478 case Builtin::BI__builtin_hlsl_elementwise_ddx_coarse:
4479 case Builtin::BI__builtin_hlsl_elementwise_ddy_coarse:
4480 case Builtin::BI__builtin_hlsl_elementwise_ddx_fine:
4481 case Builtin::BI__builtin_hlsl_elementwise_ddy_fine: {
4482 if (SemaRef.checkArgCount(TheCall, 1))
4483 return true;
4484 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
4486 return true;
4487 if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall))
4488 return true;
4489 break;
4490 }
4491 case Builtin::BI__builtin_hlsl_elementwise_isinf:
4492 case Builtin::BI__builtin_hlsl_elementwise_isnan: {
4493 if (SemaRef.checkArgCount(TheCall, 1))
4494 return true;
4495 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
4497 return true;
4498 if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall))
4499 return true;
4501 break;
4502 }
4503 case Builtin::BI__builtin_hlsl_mad: {
4504 if (SemaRef.BuiltinElementwiseTernaryMath(
4505 TheCall, /*ArgTyRestr=*/
4507 return true;
4508 break;
4509 }
4510 case Builtin::BI__builtin_hlsl_mul: {
4511 if (SemaRef.checkArgCount(TheCall, 2))
4512 return true;
4513
4514 Expr *Arg0 = TheCall->getArg(0);
4515 Expr *Arg1 = TheCall->getArg(1);
4516 QualType Ty0 = Arg0->getType();
4517 QualType Ty1 = Arg1->getType();
4518
4519 auto getElemType = [](QualType T) -> QualType {
4520 if (const auto *VTy = T->getAs<VectorType>())
4521 return VTy->getElementType();
4522 if (const auto *MTy = T->getAs<ConstantMatrixType>())
4523 return MTy->getElementType();
4524 return T;
4525 };
4526
4527 QualType EltTy0 = getElemType(Ty0);
4528
4529 bool IsVec0 = Ty0->isVectorType();
4530 bool IsMat0 = Ty0->isConstantMatrixType();
4531 bool IsVec1 = Ty1->isVectorType();
4532 bool IsMat1 = Ty1->isConstantMatrixType();
4533
4534 QualType RetTy;
4535
4536 if (IsVec0 && IsMat1) {
4537 auto *MatTy = Ty1->castAs<ConstantMatrixType>();
4538 RetTy = getASTContext().getExtVectorType(EltTy0, MatTy->getNumColumns());
4539 } else if (IsMat0 && IsVec1) {
4540 auto *MatTy = Ty0->castAs<ConstantMatrixType>();
4541 RetTy = getASTContext().getExtVectorType(EltTy0, MatTy->getNumRows());
4542 } else {
4543 assert(IsMat0 && IsMat1);
4544 auto *MatTy0 = Ty0->castAs<ConstantMatrixType>();
4545 auto *MatTy1 = Ty1->castAs<ConstantMatrixType>();
4547 EltTy0, MatTy0->getNumRows(), MatTy1->getNumColumns());
4548 }
4549
4550 TheCall->setType(RetTy);
4551 break;
4552 }
4553 case Builtin::BI__builtin_elementwise_fma: {
4554 if (SemaRef.checkArgCount(TheCall, 3) ||
4555 CheckAllArgsHaveSameType(&SemaRef, TheCall)) {
4556 return true;
4557 }
4558
4559 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
4561 return true;
4562
4563 ExprResult A = TheCall->getArg(0);
4564 QualType ArgTyA = A.get()->getType();
4565 // return type is the same as input type
4566 TheCall->setType(ArgTyA);
4567 break;
4568 }
4569 case Builtin::BI__builtin_hlsl_transpose: {
4570 if (SemaRef.checkArgCount(TheCall, 1))
4571 return true;
4572
4573 Expr *Arg = TheCall->getArg(0);
4574 QualType ArgTy = Arg->getType();
4575
4576 const auto *MatTy = ArgTy->getAs<ConstantMatrixType>();
4577 if (!MatTy) {
4578 SemaRef.Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
4579 << 1 << /* matrix */ 3 << /* no int */ 0 << /* no fp */ 0 << ArgTy;
4580 return true;
4581 }
4582
4584 MatTy->getElementType(), MatTy->getNumColumns(), MatTy->getNumRows());
4585 TheCall->setType(RetTy);
4586 break;
4587 }
4588 case Builtin::BI__builtin_hlsl_elementwise_sign: {
4589 if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall))
4590 return true;
4591 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
4593 return true;
4595 break;
4596 }
4597 case Builtin::BI__builtin_hlsl_wave_active_all_equal: {
4598 if (SemaRef.checkArgCount(TheCall, 1))
4599 return true;
4600
4601 // Ensure input expr type is a scalar/vector
4602 if (CheckAnyScalarOrVector(&SemaRef, TheCall, 0))
4603 return true;
4604
4605 QualType InputTy = TheCall->getArg(0)->getType();
4606 ASTContext &Ctx = getASTContext();
4607
4608 QualType RetTy;
4609
4610 // If vector, construct bool vector of same size
4611 if (const auto *VecTy = InputTy->getAs<ExtVectorType>()) {
4612 unsigned NumElts = VecTy->getNumElements();
4613 RetTy = Ctx.getExtVectorType(Ctx.BoolTy, NumElts);
4614 } else {
4615 // Scalar case
4616 RetTy = Ctx.BoolTy;
4617 }
4618
4619 TheCall->setType(RetTy);
4620 break;
4621 }
4622 case Builtin::BI__builtin_hlsl_wave_active_max:
4623 case Builtin::BI__builtin_hlsl_wave_active_min:
4624 case Builtin::BI__builtin_hlsl_wave_active_sum:
4625 case Builtin::BI__builtin_hlsl_wave_active_product: {
4626 if (SemaRef.checkArgCount(TheCall, 1))
4627 return true;
4628
4629 // Ensure input expr type is a scalar/vector and the same as the return type
4630 if (CheckAnyScalarOrVector(&SemaRef, TheCall, 0))
4631 return true;
4632 if (CheckWaveActive(&SemaRef, TheCall))
4633 return true;
4634 ExprResult Expr = TheCall->getArg(0);
4635 QualType ArgTyExpr = Expr.get()->getType();
4636 TheCall->setType(ArgTyExpr);
4637 break;
4638 }
4639 case Builtin::BI__builtin_hlsl_wave_active_bit_or:
4640 case Builtin::BI__builtin_hlsl_wave_active_bit_xor:
4641 case Builtin::BI__builtin_hlsl_wave_active_bit_and: {
4642 if (SemaRef.checkArgCount(TheCall, 1))
4643 return true;
4644
4645 // Ensure input expr type is a scalar/vector
4646 if (CheckAnyScalarOrVector(&SemaRef, TheCall, 0))
4647 return true;
4648
4649 if (CheckWaveActive(&SemaRef, TheCall))
4650 return true;
4651
4652 // Ensure the expr type is interpretable as a uint or vector<uint>
4653 ExprResult Expr = TheCall->getArg(0);
4654 QualType ArgTyExpr = Expr.get()->getType();
4655 auto *VTy = ArgTyExpr->getAs<VectorType>();
4656 if (!(ArgTyExpr->isIntegerType() ||
4657 (VTy && VTy->getElementType()->isIntegerType()))) {
4658 SemaRef.Diag(TheCall->getArg(0)->getBeginLoc(),
4659 diag::err_builtin_invalid_arg_type)
4660 << ArgTyExpr << SemaRef.Context.UnsignedIntTy << 1 << 0 << 0;
4661 return true;
4662 }
4663
4664 // Ensure input expr type is the same as the return type
4665 TheCall->setType(ArgTyExpr);
4666 break;
4667 }
4668 case Builtin::BI__builtin_hlsl_interlocked_add:
4669 case Builtin::BI__builtin_hlsl_interlocked_and:
4670 case Builtin::BI__builtin_hlsl_interlocked_exchange:
4671 case Builtin::BI__builtin_hlsl_interlocked_max:
4672 case Builtin::BI__builtin_hlsl_interlocked_min:
4673 case Builtin::BI__builtin_hlsl_interlocked_or:
4674 case Builtin::BI__builtin_hlsl_interlocked_xor: {
4675 // The builtin's prototype in Builtins.td is `void (...)`, so direct calls
4676 // to `__builtin_hlsl_interlocked_op` bypass argument checking entirely.
4677 // When reached via the synthesized `InterlockedOp` overload set in
4678 // HLSLExternalSemaSource, overload resolution has already enforced the
4679 // argument count, integer-type matching, and the address-space requirement
4680 // on `dest`. The checks below are a safety net for callers that invoke the
4681 // builtin by its mangled name and would otherwise reach CodeGen unchecked.
4682 // InterlockedExchange always reports the previous value, so it requires
4683 // `original_value` instead of accepting it as an optional argument.
4684 if (BuiltinID == Builtin::BI__builtin_hlsl_interlocked_exchange) {
4685 if (SemaRef.checkArgCount(TheCall, 3))
4686 return true;
4687 } else {
4688 if (TheCall->getNumArgs() < 2) {
4689 SemaRef.Diag(TheCall->getEndLoc(),
4690 diag::err_typecheck_call_too_few_args_at_least)
4691 << /*callee_type=*/0 << /*min_arg_count=*/2 << TheCall->getNumArgs()
4692 << /*is_non_object=*/0 << TheCall->getSourceRange();
4693 return true;
4694 }
4695 if (SemaRef.checkArgCountAtMost(TheCall, 3))
4696 return true;
4697 }
4698
4699 QualType DestTy = TheCall->getArg(0)->getType().getUnqualifiedType();
4700 // InterlockedExchange also operates on float. DXIL lowers that as a
4701 // bitwise exchange of the value's bit pattern, and DXC accepts 32-bit
4702 // float only, so half and double are rejected.
4703 const bool AllowsFloat =
4704 BuiltinID == Builtin::BI__builtin_hlsl_interlocked_exchange;
4705 if (!DestTy->isIntegerType() &&
4706 !(AllowsFloat && DestTy->isSpecificBuiltinType(BuiltinType::Float))) {
4707 SemaRef.Diag(TheCall->getArg(0)->getBeginLoc(),
4708 diag::err_builtin_invalid_arg_type)
4709 << /*ordinal=*/1 << /*scalar*/ 1 << /*integer*/ 1
4710 << /*32 bit floating-point*/ (AllowsFloat ? 3 : 0) << DestTy;
4711 return true;
4712 }
4713
4714 // 64-bit interlocked ops require SM 6.6 on DXIL. The synthesized wrapper
4715 // methods (e.g. RWByteAddressBuffer::InterlockedAdd64) are only declared
4716 // on SM 6.6+, so this defensive check only fires for direct builtin
4717 // calls; skip synthetic invocations (invalid source location).
4718 const TargetInfo &TI = SemaRef.Context.getTargetInfo();
4719 if (TheCall->getBeginLoc().isValid() &&
4720 TI.getTriple().getArch() == llvm::Triple::dxil &&
4721 SemaRef.Context.getTypeSize(DestTy) == 64 &&
4722 TI.getPlatformMinVersion() < VersionTuple(6, 6)) {
4723 SemaRef.Diag(TheCall->getBeginLoc(), diag::err_hlsl_builtin_requires_sm)
4724 << TheCall->getDirectCallee() << VersionTuple(6, 6).getAsString();
4725 return true;
4726 }
4727
4728 if (CheckModifiableLValue(&SemaRef, TheCall, 0))
4729 return true;
4730
4731 if (CheckArgAddrSpaceOneOf(&SemaRef, TheCall, 0,
4733 return true;
4734
4735 if (CheckArgTypeMatches(&SemaRef, TheCall->getArg(1), DestTy))
4736 return true;
4737
4738 if (TheCall->getNumArgs() == 3) {
4739 if (CheckArgTypeMatches(&SemaRef, TheCall->getArg(2), DestTy))
4740 return true;
4741 if (CheckModifiableLValue(&SemaRef, TheCall, 2))
4742 return true;
4743 }
4744
4745 TheCall->setType(SemaRef.Context.VoidTy);
4746 break;
4747 }
4748 // Note these are llvm builtins that we want to catch invalid intrinsic
4749 // generation. Normal handling of these builtins will occur elsewhere.
4750 case Builtin::BI__builtin_elementwise_bitreverse: {
4751 // does not include a check for number of arguments
4752 // because that is done previously
4753 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
4755 return true;
4756 break;
4757 }
4758 case Builtin::BI__builtin_hlsl_wave_prefix_count_bits: {
4759 if (SemaRef.checkArgCount(TheCall, 1))
4760 return true;
4761
4762 QualType ArgType = TheCall->getArg(0)->getType();
4763
4764 if (!(ArgType->isScalarType())) {
4765 SemaRef.Diag(TheCall->getArg(0)->getBeginLoc(),
4766 diag::err_typecheck_expect_any_scalar_or_vector_or_matrix)
4767 << ArgType << 0;
4768 return true;
4769 }
4770
4771 if (!(ArgType->isBooleanType())) {
4772 SemaRef.Diag(TheCall->getArg(0)->getBeginLoc(),
4773 diag::err_typecheck_expect_any_scalar_or_vector_or_matrix)
4774 << ArgType << 0;
4775 return true;
4776 }
4777
4778 break;
4779 }
4780 case Builtin::BI__builtin_hlsl_wave_read_lane_at: {
4781 if (SemaRef.checkArgCount(TheCall, 2))
4782 return true;
4783
4784 // Ensure index parameter type can be interpreted as a uint
4785 ExprResult Index = TheCall->getArg(1);
4786 QualType ArgTyIndex = Index.get()->getType();
4787 if (!ArgTyIndex->isIntegerType()) {
4788 SemaRef.Diag(TheCall->getArg(1)->getBeginLoc(),
4789 diag::err_typecheck_convert_incompatible)
4790 << ArgTyIndex << SemaRef.Context.UnsignedIntTy << 1 << 0 << 0;
4791 return true;
4792 }
4793
4794 // Ensure input expr type is a scalar/vector and the same as the return type
4795 if (CheckAnyScalarOrVector(&SemaRef, TheCall, 0))
4796 return true;
4797
4798 ExprResult Expr = TheCall->getArg(0);
4799 QualType ArgTyExpr = Expr.get()->getType();
4800 TheCall->setType(ArgTyExpr);
4801 break;
4802 }
4803 case Builtin::BI__builtin_hlsl_wave_read_lane_first: {
4804 if (SemaRef.checkArgCount(TheCall, 1))
4805 return true;
4806
4807 if (CheckAnyScalarOrVectorOrMatrix(&SemaRef, TheCall, 0))
4808 return true;
4809
4810 TheCall->setType(TheCall->getArg(0)->getType());
4811 break;
4812 }
4813 case Builtin::BI__builtin_hlsl_wave_get_lane_index: {
4814 if (SemaRef.checkArgCount(TheCall, 0))
4815 return true;
4816 break;
4817 }
4818 case Builtin::BI__builtin_hlsl_wave_prefix_sum:
4819 case Builtin::BI__builtin_hlsl_wave_prefix_product: {
4820 if (SemaRef.checkArgCount(TheCall, 1))
4821 return true;
4822
4823 // Ensure input expr type is a scalar/vector and the same as the return type
4824 if (CheckAnyScalarOrVector(&SemaRef, TheCall, 0))
4825 return true;
4826 if (CheckWavePrefix(&SemaRef, TheCall))
4827 return true;
4828 ExprResult Expr = TheCall->getArg(0);
4829 QualType ArgTyExpr = Expr.get()->getType();
4830 TheCall->setType(ArgTyExpr);
4831 break;
4832 }
4833 case Builtin::BI__builtin_hlsl_quad_read_across_x:
4834 case Builtin::BI__builtin_hlsl_quad_read_across_y:
4835 case Builtin::BI__builtin_hlsl_quad_read_across_diagonal: {
4836 if (SemaRef.checkArgCount(TheCall, 1))
4837 return true;
4838
4839 if (CheckAnyScalarOrVector(&SemaRef, TheCall, 0))
4840 return true;
4841 if (CheckNotBoolScalarOrVector(&SemaRef, TheCall, 0))
4842 return true;
4843 ExprResult Expr = TheCall->getArg(0);
4844 QualType ArgTyExpr = Expr.get()->getType();
4845 TheCall->setType(ArgTyExpr);
4846 break;
4847 }
4848 case Builtin::BI__builtin_hlsl_elementwise_splitdouble: {
4849 if (SemaRef.checkArgCount(TheCall, 3))
4850 return true;
4851
4852 if (CheckScalarOrVectorOrMatrix(&SemaRef, TheCall, SemaRef.Context.DoubleTy,
4853 0) ||
4855 SemaRef.Context.UnsignedIntTy, 1) ||
4857 SemaRef.Context.UnsignedIntTy, 2))
4858 return true;
4859
4860 if (CheckModifiableLValue(&SemaRef, TheCall, 1) ||
4861 CheckModifiableLValue(&SemaRef, TheCall, 2))
4862 return true;
4863 break;
4864 }
4865 case Builtin::BI__builtin_hlsl_elementwise_clip: {
4866 if (SemaRef.checkArgCount(TheCall, 1))
4867 return true;
4868
4869 if (CheckScalarOrVector(&SemaRef, TheCall, SemaRef.Context.FloatTy, 0))
4870 return true;
4871 break;
4872 }
4873 case Builtin::BI__builtin_elementwise_acos:
4874 case Builtin::BI__builtin_elementwise_asin:
4875 case Builtin::BI__builtin_elementwise_atan:
4876 case Builtin::BI__builtin_elementwise_atan2:
4877 case Builtin::BI__builtin_elementwise_ceil:
4878 case Builtin::BI__builtin_elementwise_cos:
4879 case Builtin::BI__builtin_elementwise_cosh:
4880 case Builtin::BI__builtin_elementwise_exp:
4881 case Builtin::BI__builtin_elementwise_exp2:
4882 case Builtin::BI__builtin_elementwise_exp10:
4883 case Builtin::BI__builtin_elementwise_floor:
4884 case Builtin::BI__builtin_elementwise_fmod:
4885 case Builtin::BI__builtin_elementwise_log:
4886 case Builtin::BI__builtin_elementwise_log2:
4887 case Builtin::BI__builtin_elementwise_log10:
4888 case Builtin::BI__builtin_elementwise_pow:
4889 case Builtin::BI__builtin_elementwise_roundeven:
4890 case Builtin::BI__builtin_elementwise_sin:
4891 case Builtin::BI__builtin_elementwise_sinh:
4892 case Builtin::BI__builtin_elementwise_sqrt:
4893 case Builtin::BI__builtin_elementwise_tan:
4894 case Builtin::BI__builtin_elementwise_tanh:
4895 case Builtin::BI__builtin_elementwise_trunc: {
4896 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
4898 return true;
4899 break;
4900 }
4901 case Builtin::BI__builtin_hlsl_buffer_update_counter: {
4902 assert(TheCall->getNumArgs() == 2 && "expected 2 args");
4903 auto checkResTy = [](const HLSLAttributedResourceType *ResTy) -> bool {
4904 return !(ResTy->getAttrs().ResourceClass == ResourceClass::UAV &&
4905 ResTy->getAttrs().RawBuffer && ResTy->hasContainedType());
4906 };
4907 if (CheckResourceHandle(&SemaRef, TheCall, 0, checkResTy))
4908 return true;
4909 Expr *OffsetExpr = TheCall->getArg(1);
4910 std::optional<llvm::APSInt> Offset =
4911 OffsetExpr->getIntegerConstantExpr(SemaRef.getASTContext());
4912 if (!Offset.has_value() || std::abs(Offset->getExtValue()) != 1) {
4913 SemaRef.Diag(TheCall->getArg(1)->getBeginLoc(),
4914 diag::err_hlsl_expect_arg_const_int_one_or_neg_one)
4915 << 1;
4916 return true;
4917 }
4918 break;
4919 }
4920 case Builtin::BI__builtin_hlsl_elementwise_f16tof32: {
4921 if (SemaRef.checkArgCount(TheCall, 1))
4922 return true;
4923 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
4925 return true;
4926 // ensure arg integers are 32 bits
4927 if (CheckExpectedBitWidth(&SemaRef, TheCall, 0, 32))
4928 return true;
4929 // check it wasn't a bool type
4930 QualType ArgTy = TheCall->getArg(0)->getType();
4931 if (auto *VTy = ArgTy->getAs<VectorType>())
4932 ArgTy = VTy->getElementType();
4933 if (ArgTy->isBooleanType()) {
4934 SemaRef.Diag(TheCall->getArg(0)->getBeginLoc(),
4935 diag::err_builtin_invalid_arg_type)
4936 << 1 << /* scalar or vector of */ 5 << /* unsigned int */ 3
4937 << /* no fp */ 0 << TheCall->getArg(0)->getType();
4938 return true;
4939 }
4940
4941 SetElementTypeAsReturnType(&SemaRef, TheCall, getASTContext().FloatTy);
4942 break;
4943 }
4944 case Builtin::BI__builtin_hlsl_elementwise_f32tof16: {
4945 if (SemaRef.checkArgCount(TheCall, 1))
4946 return true;
4948 return true;
4950 getASTContext().UnsignedIntTy);
4951 break;
4952 }
4953 }
4954 return false;
4955}
4956
4960 WorkList.push_back(BaseTy);
4961 while (!WorkList.empty()) {
4962 QualType T = WorkList.pop_back_val();
4963 T = T.getCanonicalType().getUnqualifiedType();
4964 if (const auto *AT = dyn_cast<ConstantArrayType>(T)) {
4965 llvm::SmallVector<QualType, 16> ElementFields;
4966 // Generally I've avoided recursion in this algorithm, but arrays of
4967 // structs could be time-consuming to flatten and churn through on the
4968 // work list. Hopefully nesting arrays of structs containing arrays
4969 // of structs too many levels deep is unlikely.
4970 BuildFlattenedTypeList(AT->getElementType(), ElementFields);
4971 // Repeat the element's field list n times.
4972 for (uint64_t Ct = 0; Ct < AT->getZExtSize(); ++Ct)
4973 llvm::append_range(List, ElementFields);
4974 continue;
4975 }
4976 // Vectors can only have element types that are builtin types, so this can
4977 // add directly to the list instead of to the WorkList.
4978 if (const auto *VT = dyn_cast<VectorType>(T)) {
4979 List.insert(List.end(), VT->getNumElements(), VT->getElementType());
4980 continue;
4981 }
4982 if (const auto *MT = dyn_cast<ConstantMatrixType>(T)) {
4983 List.insert(List.end(), MT->getNumElementsFlattened(),
4984 MT->getElementType());
4985 continue;
4986 }
4987 if (const auto *RD = T->getAsCXXRecordDecl()) {
4988 if (RD->isStandardLayout())
4989 RD = RD->getStandardLayoutBaseWithFields();
4990
4991 // For types that we shouldn't decompose (unions and non-aggregates), just
4992 // add the type itself to the list.
4993 if (RD->isUnion() || !RD->isAggregate()) {
4994 List.push_back(T);
4995 continue;
4996 }
4997
4999 for (const auto *FD : RD->fields())
5000 if (!FD->isUnnamedBitField())
5001 FieldTypes.push_back(FD->getType());
5002 // Reverse the newly added sub-range.
5003 std::reverse(FieldTypes.begin(), FieldTypes.end());
5004 llvm::append_range(WorkList, FieldTypes);
5005
5006 // If this wasn't a standard layout type we may also have some base
5007 // classes to deal with.
5008 if (!RD->isStandardLayout()) {
5009 FieldTypes.clear();
5010 for (const auto &Base : RD->bases())
5011 FieldTypes.push_back(Base.getType());
5012 std::reverse(FieldTypes.begin(), FieldTypes.end());
5013 llvm::append_range(WorkList, FieldTypes);
5014 }
5015 continue;
5016 }
5017 List.push_back(T);
5018 }
5019}
5020
5022 if (QT.isNull())
5023 return false;
5024
5025 // Must be a class/struct.
5026 const auto *RD = QT->getAsCXXRecordDecl();
5027 if (!RD || RD->isUnion())
5028 return false;
5029
5030 // Cannot be a resource type or contain one.
5031 return !QT->isHLSLIntangibleType();
5032}
5033
5035 // null and array types are not allowed.
5036 if (QT.isNull() || QT->isArrayType())
5037 return false;
5038
5039 // UDT types are not allowed
5040 if (QT->isRecordType())
5041 return false;
5042
5043 if (QT->isBooleanType() || QT->isEnumeralType())
5044 return false;
5045
5046 // the only other valid builtin types are scalars or vectors
5047 if (QT->isArithmeticType()) {
5048 if (SemaRef.Context.getTypeSize(QT) / 8 > 16)
5049 return false;
5050 return true;
5051 }
5052
5053 if (const VectorType *VT = QT->getAs<VectorType>()) {
5054 int ArraySize = VT->getNumElements();
5055
5056 if (ArraySize > 4)
5057 return false;
5058
5059 QualType ElTy = VT->getElementType();
5060 if (ElTy->isBooleanType())
5061 return false;
5062
5063 if (SemaRef.Context.getTypeSize(QT) / 8 > 16)
5064 return false;
5065 return true;
5066 }
5067
5068 return false;
5069}
5070
5072 if (T1.isNull() || T2.isNull())
5073 return false;
5074
5077
5078 // If both types are the same canonical type, they're obviously compatible.
5079 if (SemaRef.getASTContext().hasSameType(T1, T2))
5080 return true;
5081
5083 BuildFlattenedTypeList(T1, T1Types);
5085 BuildFlattenedTypeList(T2, T2Types);
5086
5087 // Check the flattened type list
5088 return llvm::equal(T1Types, T2Types,
5089 [this](QualType LHS, QualType RHS) -> bool {
5090 return SemaRef.IsLayoutCompatible(LHS, RHS);
5091 });
5092}
5093
5095 FunctionDecl *Old) {
5096 if (New->getNumParams() != Old->getNumParams())
5097 return true;
5098
5099 bool HadError = false;
5100
5101 for (unsigned i = 0, e = New->getNumParams(); i != e; ++i) {
5102 ParmVarDecl *NewParam = New->getParamDecl(i);
5103 ParmVarDecl *OldParam = Old->getParamDecl(i);
5104
5105 // HLSL parameter declarations for inout and out must match between
5106 // declarations. In HLSL inout and out are ambiguous at the call site,
5107 // but have different calling behavior, so you cannot overload a
5108 // method based on a difference between inout and out annotations.
5109 const auto *NDAttr = NewParam->getAttr<HLSLParamModifierAttr>();
5110 unsigned NSpellingIdx = (NDAttr ? NDAttr->getSpellingListIndex() : 0);
5111 const auto *ODAttr = OldParam->getAttr<HLSLParamModifierAttr>();
5112 unsigned OSpellingIdx = (ODAttr ? ODAttr->getSpellingListIndex() : 0);
5113
5114 if (NSpellingIdx != OSpellingIdx) {
5115 SemaRef.Diag(NewParam->getLocation(),
5116 diag::err_hlsl_param_qualifier_mismatch)
5117 << NDAttr << NewParam;
5118 SemaRef.Diag(OldParam->getLocation(), diag::note_previous_declaration_as)
5119 << ODAttr;
5120 HadError = true;
5121 }
5122 }
5123 return HadError;
5124}
5125
5126// Generally follows PerformScalarCast, with cases reordered for
5127// clarity of what types are supported
5129
5130 if (!SrcTy->isScalarType() || !DestTy->isScalarType())
5131 return false;
5132
5133 if (SemaRef.getASTContext().hasSameUnqualifiedType(SrcTy, DestTy))
5134 return true;
5135
5136 switch (SrcTy->getScalarTypeKind()) {
5137 case Type::STK_Bool: // casting from bool is like casting from an integer
5138 case Type::STK_Integral:
5139 switch (DestTy->getScalarTypeKind()) {
5140 case Type::STK_Bool:
5141 case Type::STK_Integral:
5142 case Type::STK_Floating:
5143 return true;
5144 case Type::STK_CPointer:
5148 llvm_unreachable("HLSL doesn't support pointers.");
5151 llvm_unreachable("HLSL doesn't support complex types.");
5153 llvm_unreachable("HLSL doesn't support fixed point types.");
5154 }
5155 llvm_unreachable("Should have returned before this");
5156
5157 case Type::STK_Floating:
5158 switch (DestTy->getScalarTypeKind()) {
5159 case Type::STK_Floating:
5160 case Type::STK_Bool:
5161 case Type::STK_Integral:
5162 return true;
5165 llvm_unreachable("HLSL doesn't support complex types.");
5167 llvm_unreachable("HLSL doesn't support fixed point types.");
5168 case Type::STK_CPointer:
5172 llvm_unreachable("HLSL doesn't support pointers.");
5173 }
5174 llvm_unreachable("Should have returned before this");
5175
5177 case Type::STK_CPointer:
5180 llvm_unreachable("HLSL doesn't support pointers.");
5181
5183 llvm_unreachable("HLSL doesn't support fixed point types.");
5184
5187 llvm_unreachable("HLSL doesn't support complex types.");
5188 }
5189
5190 llvm_unreachable("Unhandled scalar cast");
5191}
5192
5193// Can perform an HLSL Aggregate splat cast if the Dest is an aggregate and the
5194// Src is a scalar, a vector of length 1, or a 1x1 matrix
5195// Or if Dest is a vector and Src is a vector of length 1 or a 1x1 matrix
5197
5198 QualType SrcTy = Src->getType();
5199 // Not a valid HLSL Aggregate Splat cast if Dest is a scalar or if this is
5200 // going to be a vector splat from a scalar.
5201 if ((SrcTy->isScalarType() && DestTy->isVectorType()) ||
5202 DestTy->isScalarType())
5203 return false;
5204
5205 const VectorType *SrcVecTy = SrcTy->getAs<VectorType>();
5206 const ConstantMatrixType *SrcMatTy = SrcTy->getAs<ConstantMatrixType>();
5207
5208 // Src isn't a scalar, a vector of length 1, or a 1x1 matrix
5209 if (!SrcTy->isScalarType() &&
5210 !(SrcVecTy && SrcVecTy->getNumElements() == 1) &&
5211 !(SrcMatTy && SrcMatTy->getNumElementsFlattened() == 1))
5212 return false;
5213
5214 if (SrcVecTy)
5215 SrcTy = SrcVecTy->getElementType();
5216 else if (SrcMatTy)
5217 SrcTy = SrcMatTy->getElementType();
5218
5220 BuildFlattenedTypeList(DestTy, DestTypes);
5221
5222 for (unsigned I = 0, Size = DestTypes.size(); I < Size; ++I) {
5223 if (DestTypes[I]->isUnionType())
5224 return false;
5225 if (!CanPerformScalarCast(SrcTy, DestTypes[I]))
5226 return false;
5227 }
5228 return true;
5229}
5230
5231// Can we perform an HLSL Elementwise cast?
5233
5234 // Don't handle casts where LHS and RHS are any combination of scalar/vector
5235 // There must be an aggregate somewhere
5236 QualType SrcTy = Src->getType();
5237 if (SrcTy->isScalarType()) // always a splat and this cast doesn't handle that
5238 return false;
5239
5240 if (SrcTy->isVectorType() &&
5241 (DestTy->isScalarType() || DestTy->isVectorType()))
5242 return false;
5243
5244 if (SrcTy->isConstantMatrixType() &&
5245 (DestTy->isScalarType() || DestTy->isConstantMatrixType()))
5246 return false;
5247
5249 BuildFlattenedTypeList(DestTy, DestTypes);
5251 BuildFlattenedTypeList(SrcTy, SrcTypes);
5252
5253 // Usually the size of SrcTypes must be greater than or equal to the size of
5254 // DestTypes.
5255 if (SrcTypes.size() < DestTypes.size())
5256 return false;
5257
5258 unsigned SrcSize = SrcTypes.size();
5259 unsigned DstSize = DestTypes.size();
5260 unsigned I;
5261 for (I = 0; I < DstSize && I < SrcSize; I++) {
5262 if (SrcTypes[I]->isUnionType() || DestTypes[I]->isUnionType())
5263 return false;
5264 if (!CanPerformScalarCast(SrcTypes[I], DestTypes[I])) {
5265 return false;
5266 }
5267 }
5268
5269 // check the rest of the source type for unions.
5270 for (; I < SrcSize; I++) {
5271 if (SrcTypes[I]->isUnionType())
5272 return false;
5273 }
5274 return true;
5275}
5276
5278 assert(Param->hasAttr<HLSLParamModifierAttr>() &&
5279 "We should not get here without a parameter modifier expression");
5280 const auto *Attr = Param->getAttr<HLSLParamModifierAttr>();
5281 if (Attr->getABI() == ParameterABI::Ordinary)
5282 return ExprResult(Arg);
5283
5284 bool IsInOut = Attr->getABI() == ParameterABI::HLSLInOut;
5285 if (!Arg->isLValue()) {
5286 SemaRef.Diag(Arg->getBeginLoc(), diag::error_hlsl_inout_lvalue)
5287 << Arg << (IsInOut ? 1 : 0);
5288 return ExprError();
5289 }
5290
5291 ASTContext &Ctx = SemaRef.getASTContext();
5292
5293 QualType Ty = Param->getType().getNonLValueExprType(Ctx);
5294
5295 // HLSL allows implicit conversions from scalars to vectors, but not the
5296 // inverse, so we need to disallow `inout` with scalar->vector or
5297 // scalar->matrix conversions.
5298 if (Arg->getType()->isScalarType() != Ty->isScalarType()) {
5299 SemaRef.Diag(Arg->getBeginLoc(), diag::error_hlsl_inout_scalar_extension)
5300 << Arg << (IsInOut ? 1 : 0);
5301 return ExprError();
5302 }
5303
5304 auto *ArgOpV = new (Ctx) OpaqueValueExpr(Param->getBeginLoc(), Arg->getType(),
5305 VK_LValue, OK_Ordinary, Arg);
5306
5307 // Parameters are initialized via copy initialization. This allows for
5308 // overload resolution of argument constructors.
5309 InitializedEntity Entity =
5311 ExprResult Res =
5312 SemaRef.PerformCopyInitialization(Entity, Param->getBeginLoc(), ArgOpV);
5313 if (Res.isInvalid())
5314 return ExprError();
5315 Expr *Base = Res.get();
5316 // After the cast, drop the reference type when creating the exprs.
5317 Ty = Ty.getNonLValueExprType(Ctx);
5318 auto *OpV = new (Ctx)
5319 OpaqueValueExpr(Param->getBeginLoc(), Ty, VK_LValue, OK_Ordinary, Base);
5320
5321 // Writebacks are performed with `=` binary operator, which allows for
5322 // overload resolution on writeback result expressions.
5323 Res = SemaRef.ActOnBinOp(SemaRef.getCurScope(), Arg->getBeginLoc(),
5324 tok::equal, ArgOpV, OpV);
5325
5326 if (Res.isInvalid())
5327 return ExprError();
5328 Expr *Writeback = Res.get();
5329 auto *OutExpr =
5330 HLSLOutArgExpr::Create(Ctx, Ty, ArgOpV, OpV, Writeback, IsInOut);
5331
5332 return ExprResult(OutExpr);
5333}
5334
5336 // If HLSL gains support for references, all the cites that use this will need
5337 // to be updated with semantic checking to produce errors for
5338 // pointers/references.
5339 assert(!Ty->isReferenceType() &&
5340 "Pointer and reference types cannot be inout or out parameters");
5341 Ty = SemaRef.getASTContext().getLValueReferenceType(Ty);
5342 Ty.addRestrict();
5343 return Ty;
5344}
5345
5346// Returns true if the type has a non-empty constant buffer layout (if it is
5347// scalar, vector or matrix, or if it contains any of these.
5349 const Type *Ty = QT->getUnqualifiedDesugaredType();
5350 if (Ty->isScalarType() || Ty->isVectorType() || Ty->isMatrixType())
5351 return true;
5352
5354 return false;
5355
5356 if (const auto *RD = Ty->getAsCXXRecordDecl()) {
5357 for (const auto *FD : RD->fields()) {
5359 return true;
5360 }
5361 assert(RD->getNumBases() <= 1 &&
5362 "HLSL doesn't support multiple inheritance");
5363 return RD->getNumBases()
5364 ? hasConstantBufferLayout(RD->bases_begin()->getType())
5365 : false;
5366 }
5367
5368 if (const auto *AT = dyn_cast<ArrayType>(Ty)) {
5369 if (const auto *CAT = dyn_cast<ConstantArrayType>(AT))
5370 if (isZeroSizedArray(CAT))
5371 return false;
5373 }
5374
5375 return false;
5376}
5377
5378static bool IsDefaultBufferConstantDecl(const ASTContext &Ctx, VarDecl *VD) {
5379 bool IsVulkan =
5380 Ctx.getTargetInfo().getTriple().getOS() == llvm::Triple::Vulkan;
5381 bool IsVKPushConstant = IsVulkan && VD->hasAttr<HLSLVkPushConstantAttr>();
5382 QualType QT = VD->getType();
5383 return VD->getDeclContext()->isTranslationUnit() &&
5384 QT.getAddressSpace() == LangAS::Default &&
5385 VD->getStorageClass() != SC_Static &&
5386 !VD->hasAttr<HLSLVkConstantIdAttr>() && !IsVKPushConstant &&
5388}
5389
5391 // The variable already has an address space (groupshared for ex).
5392 if (Decl->getType().hasAddressSpace())
5393 return;
5394
5395 if (Decl->getType()->isDependentType())
5396 return;
5397
5398 QualType Type = Decl->getType();
5399
5400 if (Decl->hasAttr<HLSLVkExtBuiltinInputAttr>()) {
5401 LangAS ImplAS = LangAS::hlsl_input;
5402 Type = SemaRef.getASTContext().getAddrSpaceQualType(Type, ImplAS);
5403 Decl->setType(Type);
5404 return;
5405 }
5406
5407 if (Decl->hasAttr<HLSLVkExtBuiltinOutputAttr>()) {
5408 LangAS ImplAS = LangAS::hlsl_output;
5409 Type = SemaRef.getASTContext().getAddrSpaceQualType(Type, ImplAS);
5410 Decl->setType(Type);
5411
5412 // HLSL uses `static` differently than C++. For BuiltIn output, the static
5413 // does not imply private to the module scope.
5414 // Marking it as external to reflect the semantic this attribute brings.
5415 // See https://github.com/microsoft/hlsl-specs/issues/350
5416 Decl->setStorageClass(SC_Extern);
5417 return;
5418 }
5419
5420 bool IsVulkan = getASTContext().getTargetInfo().getTriple().getOS() ==
5421 llvm::Triple::Vulkan;
5422 if (IsVulkan && Decl->hasAttr<HLSLVkPushConstantAttr>()) {
5423 if (HasDeclaredAPushConstant)
5424 SemaRef.Diag(Decl->getLocation(), diag::err_hlsl_push_constant_unique);
5425
5427 Type = SemaRef.getASTContext().getAddrSpaceQualType(Type, ImplAS);
5428 Decl->setType(Type);
5429 HasDeclaredAPushConstant = true;
5430 return;
5431 }
5432
5433 if (Type->isSamplerT() || Type->isVoidType())
5434 return;
5435
5436 // Resource handles.
5438 return;
5439
5440 // Only static globals belong to the Private address space.
5441 // Non-static globals belongs to the cbuffer.
5442 if (Decl->getStorageClass() != SC_Static && !Decl->isStaticDataMember())
5443 return;
5444
5446 Type = SemaRef.getASTContext().getAddrSpaceQualType(Type, ImplAS);
5447 Decl->setType(Type);
5448}
5449
5450namespace {
5451
5452// Helper class for assigning bindings to resources declared within a struct.
5453// It keeps track of all binding attributes declared on a struct instance, and
5454// the offsets for each register type that have been assigned so far.
5455// Handles both explicit and implicit bindings.
5456class StructBindingContext {
5457 // Bindings and offsets per register type. We only need to support four
5458 // register types - SRV (u), UAV (t), CBuffer (c), and Sampler (s).
5459 HLSLResourceBindingAttr *RegBindingsAttrs[4];
5460 unsigned RegBindingOffset[4];
5461
5462 // Make sure the RegisterType values are what we expect
5463 static_assert(static_cast<unsigned>(RegisterType::SRV) == 0 &&
5464 static_cast<unsigned>(RegisterType::UAV) == 1 &&
5465 static_cast<unsigned>(RegisterType::CBuffer) == 2 &&
5466 static_cast<unsigned>(RegisterType::Sampler) == 3,
5467 "unexpected register type values");
5468
5469 // Vulkan binding attribute does not vary by register type.
5470 HLSLVkBindingAttr *VkBindingAttr;
5471 unsigned VkBindingOffset;
5472
5473public:
5474 // Constructor: gather all binding attributes on a struct instance and
5475 // initialize offsets.
5476 StructBindingContext(VarDecl *VD) {
5477 for (unsigned i = 0; i < 4; ++i) {
5478 RegBindingsAttrs[i] = nullptr;
5479 RegBindingOffset[i] = 0;
5480 }
5481 VkBindingAttr = nullptr;
5482 VkBindingOffset = 0;
5483
5484 ASTContext &AST = VD->getASTContext();
5485 bool IsSpirv = AST.getTargetInfo().getTriple().isSPIRV();
5486
5487 for (Attr *A : VD->attrs()) {
5488 if (auto *RBA = dyn_cast<HLSLResourceBindingAttr>(A)) {
5489 RegisterType RegType = RBA->getRegisterType();
5490 unsigned RegTypeIdx = static_cast<unsigned>(RegType);
5491 // Ignore unsupported register annotations, such as 'c' or 'i'.
5492 if (RegTypeIdx < 4)
5493 RegBindingsAttrs[RegTypeIdx] = RBA;
5494 continue;
5495 }
5496 // Gather the Vulkan binding attributes only if the target is SPIR-V.
5497 if (IsSpirv) {
5498 if (auto *VBA = dyn_cast<HLSLVkBindingAttr>(A))
5499 VkBindingAttr = VBA;
5500 }
5501 }
5502 }
5503
5504 // Creates a binding attribute for a resource based on the gathered attributes
5505 // and the required register type and range.
5506 Attr *createBindingAttr(SemaHLSL &S, ASTContext &AST, RegisterType RegType,
5507 unsigned Range, bool HasCounter) {
5508 assert(static_cast<unsigned>(RegType) < 4 && "unexpected register type");
5509
5510 if (VkBindingAttr) {
5511 unsigned Offset = VkBindingOffset;
5512 VkBindingOffset += Range;
5513 return HLSLVkBindingAttr::CreateImplicit(
5514 AST, VkBindingAttr->getBinding() + Offset, VkBindingAttr->getSet(),
5515 VkBindingAttr->getRange());
5516 }
5517
5518 HLSLResourceBindingAttr *RBA =
5519 RegBindingsAttrs[static_cast<unsigned>(RegType)];
5520 HLSLResourceBindingAttr *NewAttr = nullptr;
5521
5522 if (RBA && RBA->hasRegisterSlot()) {
5523 // Explicit binding - create a new attribute with offseted slot number
5524 // based on the required register type.
5525 unsigned Offset = RegBindingOffset[static_cast<unsigned>(RegType)];
5526 RegBindingOffset[static_cast<unsigned>(RegType)] += Range;
5527
5528 unsigned NewSlotNumber = RBA->getSlotNumber() + Offset;
5529 StringRef NewSlotNumberStr =
5530 createRegisterString(AST, RBA->getRegisterType(), NewSlotNumber);
5531 NewAttr = HLSLResourceBindingAttr::CreateImplicit(
5532 AST, NewSlotNumberStr, RBA->getSpace(), RBA->getRange());
5533 NewAttr->setBinding(RegType, NewSlotNumber, RBA->getSpaceNumber());
5534 } else {
5535 // No binding attribute or space-only binding - create a binding
5536 // attribute for implicit binding.
5537 NewAttr = HLSLResourceBindingAttr::CreateImplicit(AST, "", "0", {});
5538 NewAttr->setBinding(RegType, std::nullopt,
5539 RBA ? RBA->getSpaceNumber() : 0);
5540 NewAttr->setImplicitBindingOrderID(S.getNextImplicitBindingOrderID());
5541 }
5542 if (HasCounter)
5543 NewAttr->setImplicitCounterBindingOrderID(
5545 return NewAttr;
5546 }
5547};
5548
5549// Creates a global variable declaration for a resource field embedded in a
5550// struct, assigns it a binding, initializes it, and associates it with the
5551// struct declaration via an HLSLAssociatedResourceDeclAttr.
5552static void createGlobalResourceDeclForStruct(
5553 Sema &S, VarDecl *ParentVD, SourceLocation Loc, IdentifierInfo *Id,
5554 QualType ResTy, StructBindingContext &BindingCtx) {
5555 assert(isResourceRecordTypeOrArrayOf(ResTy) &&
5556 "expected resource type or array of resources");
5557
5558 DeclContext *DC = ParentVD->getNonTransparentDeclContext();
5559 assert(DC->isTranslationUnit() && "expected translation unit decl context");
5560
5561 ASTContext &AST = S.getASTContext();
5562 VarDecl *ResDecl =
5563 VarDecl::Create(AST, DC, Loc, Loc, Id, ResTy, nullptr, SC_None);
5564
5565 unsigned Range = 1;
5566 const Type *SingleResTy = ResTy.getTypePtr()->getUnqualifiedDesugaredType();
5567 while (const auto *AT = dyn_cast<ArrayType>(SingleResTy)) {
5568 const auto *CAT = dyn_cast<ConstantArrayType>(AT);
5569 Range = CAT ? (Range * CAT->getSize().getZExtValue()) : 0;
5570 SingleResTy =
5572 }
5573 const HLSLAttributedResourceType *ResHandleTy =
5574 HLSLAttributedResourceType::findHandleTypeOnResource(SingleResTy);
5575
5576 // Add a binding attribute to the global resource declaration.
5577 bool HasCounter = hasCounterHandle(SingleResTy->getAsCXXRecordDecl());
5578 Attr *BindingAttr = BindingCtx.createBindingAttr(
5579 S.HLSL(), AST, getRegisterType(ResHandleTy), Range, HasCounter);
5580 ResDecl->addAttr(BindingAttr);
5581 ResDecl->addAttr(InternalLinkageAttr::CreateImplicit(AST));
5582 ResDecl->setImplicit();
5583
5584 if (Range == 1)
5585 S.HLSL().initGlobalResourceDecl(ResDecl);
5586 else
5587 S.HLSL().initGlobalResourceArrayDecl(ResDecl);
5588
5589 ParentVD->addAttr(
5590 HLSLAssociatedResourceDeclAttr::CreateImplicit(AST, ResDecl));
5591 DC->addDecl(ResDecl);
5592
5593 DeclGroupRef DG(ResDecl);
5595}
5596
5597static void handleArrayOfStructWithResources(
5598 Sema &S, VarDecl *ParentVD, const ConstantArrayType *CAT,
5599 EmbeddedResourceNameBuilder &NameBuilder, StructBindingContext &BindingCtx);
5600
5601// Scans base and all fields of a struct/class type to find all embedded
5602// resources or resource arrays. Creates a global variable for each resource
5603// found.
5604static void handleStructWithResources(Sema &S, VarDecl *ParentVD,
5605 const CXXRecordDecl *RD,
5606 EmbeddedResourceNameBuilder &NameBuilder,
5607 StructBindingContext &BindingCtx) {
5608
5609 // Scan the base classes.
5610 assert(RD->getNumBases() <= 1 && "HLSL doesn't support multiple inheritance");
5611 const auto *BasesIt = RD->bases_begin();
5612 if (BasesIt != RD->bases_end()) {
5613 QualType QT = BasesIt->getType();
5614 if (QT->isHLSLIntangibleType()) {
5615 CXXRecordDecl *BaseRD = QT->getAsCXXRecordDecl();
5616 NameBuilder.pushBaseName(BaseRD->getName());
5617 handleStructWithResources(S, ParentVD, BaseRD, NameBuilder, BindingCtx);
5618 NameBuilder.pop();
5619 }
5620 }
5621 // Process this class fields.
5622 for (const FieldDecl *FD : RD->fields()) {
5623 QualType FDTy = FD->getType().getCanonicalType();
5624 if (!FDTy->isHLSLIntangibleType())
5625 continue;
5626
5627 NameBuilder.pushName(FD->getName());
5628
5630 IdentifierInfo *II = NameBuilder.getNameAsIdentifier(S.getASTContext());
5631 createGlobalResourceDeclForStruct(S, ParentVD, FD->getLocation(), II,
5632 FDTy, BindingCtx);
5633 } else if (const auto *RD = FDTy->getAsCXXRecordDecl()) {
5634 handleStructWithResources(S, ParentVD, RD, NameBuilder, BindingCtx);
5635
5636 } else if (const auto *ArrayTy = dyn_cast<ConstantArrayType>(FDTy)) {
5637 assert(!FDTy->isHLSLResourceRecordArray() &&
5638 "resource arrays should have been already handled");
5639 handleArrayOfStructWithResources(S, ParentVD, ArrayTy, NameBuilder,
5640 BindingCtx);
5641 }
5642 NameBuilder.pop();
5643 }
5644}
5645
5646// Processes array of structs with resources.
5647static void
5648handleArrayOfStructWithResources(Sema &S, VarDecl *ParentVD,
5649 const ConstantArrayType *CAT,
5650 EmbeddedResourceNameBuilder &NameBuilder,
5651 StructBindingContext &BindingCtx) {
5652
5653 QualType ElementTy = CAT->getElementType().getCanonicalType();
5654 assert(ElementTy->isHLSLIntangibleType() && "Expected HLSL intangible type");
5655
5656 const ConstantArrayType *SubCAT = dyn_cast<ConstantArrayType>(ElementTy);
5657 const CXXRecordDecl *ElementRD = ElementTy->getAsCXXRecordDecl();
5658
5659 if (!SubCAT && !ElementRD)
5660 return;
5661
5662 for (unsigned I = 0, E = CAT->getSize().getZExtValue(); I < E; ++I) {
5663 NameBuilder.pushArrayIndex(I);
5664 if (ElementRD)
5665 handleStructWithResources(S, ParentVD, ElementRD, NameBuilder,
5666 BindingCtx);
5667 else
5668 handleArrayOfStructWithResources(S, ParentVD, SubCAT, NameBuilder,
5669 BindingCtx);
5670 NameBuilder.pop();
5671 }
5672}
5673
5674} // namespace
5675
5676// Scans all fields of a user-defined struct (or array of structs)
5677// to find all embedded resources or resource arrays. For each resource
5678// a global variable of the resource type is created and associated
5679// with the parent declaration (VD) through a HLSLAssociatedResourceDeclAttr
5680// attribute.
5681void SemaHLSL::handleGlobalStructOrArrayOfWithResources(VarDecl *VD) {
5682 EmbeddedResourceNameBuilder NameBuilder(VD->getName());
5683 StructBindingContext BindingCtx(VD);
5684
5685 const Type *VDTy = VD->getType().getTypePtr();
5686 assert(VDTy->isHLSLIntangibleType() && !isResourceRecordTypeOrArrayOf(VD) &&
5687 "Expected non-resource struct or array type");
5688
5689 if (const CXXRecordDecl *RD = VDTy->getAsCXXRecordDecl()) {
5690 handleStructWithResources(SemaRef, VD, RD, NameBuilder, BindingCtx);
5691 return;
5692 }
5693
5694 if (const auto *CAT = dyn_cast<ConstantArrayType>(VDTy)) {
5695 handleArrayOfStructWithResources(SemaRef, VD, CAT, NameBuilder, BindingCtx);
5696 return;
5697 }
5698}
5699
5701 if (VD->hasGlobalStorage()) {
5702 // make sure the declaration has a complete type
5703 if (SemaRef.RequireCompleteType(
5704 VD->getLocation(),
5705 SemaRef.getASTContext().getBaseElementType(VD->getType()),
5706 diag::err_typecheck_decl_incomplete_type)) {
5707 VD->setInvalidDecl();
5709 return;
5710 }
5711
5712 // Global variables outside a cbuffer block that are not a resource, static,
5713 // groupshared, or an empty array or struct belong to the default constant
5714 // buffer $Globals (to be created at the end of the translation unit).
5716 // update address space to hlsl_constant
5719 VD->setType(NewTy);
5720 DefaultCBufferDecls.push_back(VD);
5721 }
5722
5723 // find all resources bindings on decl
5724 if (VD->getType()->isHLSLIntangibleType())
5725 collectResourceBindingsOnVarDecl(VD);
5726
5727 if (VD->hasAttr<HLSLVkConstantIdAttr>())
5729
5731 VD->getStorageClass() != SC_Static) {
5732 // Add internal linkage attribute to non-static resource variables. The
5733 // global externally visible storage is accessed through the handle, which
5734 // is a member. The variable itself is not externally visible.
5735 VD->addAttr(InternalLinkageAttr::CreateImplicit(getASTContext()));
5736 }
5737
5738 // process explicit bindings
5739 processExplicitBindingsOnDecl(VD);
5740
5741 // Add implicit binding attribute to non-static resource arrays.
5742 if (VD->getType()->isHLSLResourceRecordArray() &&
5743 VD->getStorageClass() != SC_Static) {
5744 // If the resource array does not have an explicit binding attribute,
5745 // create an implicit one. It will be used to transfer implicit binding
5746 // order_ID to codegen.
5747 ResourceBindingAttrs Binding(VD);
5748 if (!Binding.isExplicit()) {
5749 uint32_t OrderID = getNextImplicitBindingOrderID();
5750 if (Binding.hasBinding())
5751 Binding.setImplicitOrderID(OrderID);
5752 else {
5755 OrderID);
5756 // Re-create the binding object to pick up the new attribute.
5757 Binding = ResourceBindingAttrs(VD);
5758 }
5759 }
5760
5761 // Get to the base type of a potentially multi-dimensional array.
5763
5764 const CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
5765 if (hasCounterHandle(RD)) {
5766 if (!Binding.hasCounterImplicitOrderID()) {
5767 uint32_t OrderID = getNextImplicitBindingOrderID();
5768 Binding.setCounterImplicitOrderID(OrderID);
5769 }
5770 }
5771 }
5772
5773 // Process resources in user-defined structs, or arrays of such structs.
5774 const Type *VDTy = VD->getType().getTypePtr();
5775 if (VD->getStorageClass() != SC_Static && VDTy->isHLSLIntangibleType() &&
5777 handleGlobalStructOrArrayOfWithResources(VD);
5778
5779 // Mark groupshared variables as extern so they will have
5780 // external storage and won't be default initialized
5781 if (VD->hasAttr<HLSLGroupSharedAddressSpaceAttr>())
5783 }
5784
5786}
5787
5789 assert(VD->getType()->isHLSLResourceRecord() &&
5790 "expected resource record type");
5791
5792 ASTContext &AST = SemaRef.getASTContext();
5793 uint64_t UIntTySize = AST.getTypeSize(AST.UnsignedIntTy);
5794 uint64_t IntTySize = AST.getTypeSize(AST.IntTy);
5795
5796 // Gather resource binding attributes.
5797 ResourceBindingAttrs Binding(VD);
5798
5799 // Find correct initialization method and create its arguments.
5800 QualType ResourceTy = VD->getType();
5801 CXXRecordDecl *ResourceDecl = ResourceTy->getAsCXXRecordDecl();
5802 CXXMethodDecl *CreateMethod = nullptr;
5804
5805 bool HasCounter = hasCounterHandle(ResourceDecl);
5806 const char *CreateMethodName;
5807 if (Binding.isExplicit())
5808 CreateMethodName = HasCounter ? "__createFromBindingWithImplicitCounter"
5809 : "__createFromBinding";
5810 else
5811 CreateMethodName = HasCounter
5812 ? "__createFromImplicitBindingWithImplicitCounter"
5813 : "__createFromImplicitBinding";
5814
5815 CreateMethod =
5816 lookupMethod(SemaRef, ResourceDecl, CreateMethodName, VD->getLocation());
5817
5818 if (!CreateMethod) {
5819 // This can happen if someone creates a struct that looks like an HLSL
5820 // resource record but does not have the required static create method.
5821 // No binding will be generated for it.
5822 assert(!ResourceDecl->isImplicit() &&
5823 "create method lookup should always succeed for built-in resource "
5824 "records");
5825 return false;
5826 }
5827
5828 if (Binding.isExplicit()) {
5829 IntegerLiteral *RegSlot =
5830 IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, Binding.getSlot()),
5832 Args.push_back(RegSlot);
5833 } else {
5834 uint32_t OrderID = (Binding.hasImplicitOrderID())
5835 ? Binding.getImplicitOrderID()
5837 IntegerLiteral *OrderId =
5838 IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, OrderID),
5840 Args.push_back(OrderId);
5841 }
5842
5843 IntegerLiteral *Space =
5844 IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, Binding.getSpace()),
5846 Args.push_back(Space);
5847
5849 AST, llvm::APInt(IntTySize, 1), AST.IntTy, SourceLocation());
5850 Args.push_back(RangeSize);
5851
5853 AST, llvm::APInt(UIntTySize, 0), AST.UnsignedIntTy, SourceLocation());
5854 Args.push_back(Index);
5855
5856 StringRef VarName = VD->getName();
5858 AST, VarName, StringLiteralKind::Ordinary, false,
5859 AST.getStringLiteralArrayType(AST.CharTy.withConst(), VarName.size()),
5860 SourceLocation());
5862 AST, AST.getPointerType(AST.CharTy.withConst()), CK_ArrayToPointerDecay,
5863 Name, nullptr, VK_PRValue, FPOptionsOverride());
5864 Args.push_back(NameCast);
5865
5866 if (HasCounter) {
5867 // Will this be in the correct order?
5868 uint32_t CounterOrderID = getNextImplicitBindingOrderID();
5869 IntegerLiteral *CounterId =
5870 IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, CounterOrderID),
5872 Args.push_back(CounterId);
5873 }
5874
5875 // Make sure the create method template is instantiated and emitted.
5876 if (!CreateMethod->isDefined() && CreateMethod->isTemplateInstantiation())
5877 SemaRef.InstantiateFunctionDefinition(VD->getLocation(), CreateMethod,
5878 true);
5879
5880 // Create CallExpr with a call to the static method and set it as the decl
5881 // initialization.
5883 AST, NestedNameSpecifierLoc(), SourceLocation(), CreateMethod, false,
5884 CreateMethod->getNameInfo(), CreateMethod->getType(), VK_PRValue);
5885
5886 auto *ImpCast = ImplicitCastExpr::Create(
5887 AST, AST.getPointerType(CreateMethod->getType()),
5888 CK_FunctionToPointerDecay, DRE, nullptr, VK_PRValue, FPOptionsOverride());
5889
5890 CallExpr *InitExpr =
5891 CallExpr::Create(AST, ImpCast, Args, ResourceTy, VK_PRValue,
5893 VD->setInit(InitExpr);
5895 SemaRef.CheckCompleteVariableDeclaration(VD);
5896 return true;
5897}
5898
5900 assert(VD->getType()->isHLSLResourceRecordArray() &&
5901 "expected array of resource records");
5902
5903 // Individual resources in a resource array are not initialized here. They
5904 // are initialized later on during codegen when the individual resources are
5905 // accessed. Codegen will emit a call to the resource initialization method
5906 // with the specified array index. We need to make sure though that the method
5907 // for the specific resource type is instantiated, so codegen can emit a call
5908 // to it when the array element is accessed.
5909
5910 // Find correct initialization method based on the resource binding
5911 // information.
5912 ASTContext &AST = SemaRef.getASTContext();
5913 QualType ResElementTy = AST.getBaseElementType(VD->getType());
5914 CXXRecordDecl *ResourceDecl = ResElementTy->getAsCXXRecordDecl();
5915 CXXMethodDecl *CreateMethod = nullptr;
5916
5917 bool HasCounter = hasCounterHandle(ResourceDecl);
5918 ResourceBindingAttrs ResourceAttrs(VD);
5919 if (ResourceAttrs.isExplicit())
5920 // Resource has explicit binding.
5921 CreateMethod =
5922 lookupMethod(SemaRef, ResourceDecl,
5923 HasCounter ? "__createFromBindingWithImplicitCounter"
5924 : "__createFromBinding",
5925 VD->getLocation());
5926 else
5927 // Resource has implicit binding.
5928 CreateMethod = lookupMethod(
5929 SemaRef, ResourceDecl,
5930 HasCounter ? "__createFromImplicitBindingWithImplicitCounter"
5931 : "__createFromImplicitBinding",
5932 VD->getLocation());
5933
5934 if (!CreateMethod)
5935 return false;
5936
5937 // Make sure the create method template is instantiated and emitted.
5938 if (!CreateMethod->isDefined() && CreateMethod->isTemplateInstantiation())
5939 SemaRef.InstantiateFunctionDefinition(VD->getLocation(), CreateMethod,
5940 true);
5941 return true;
5942}
5943
5944// Returns true if the initialization has been handled.
5945// Returns false to use default initialization.
5947 // Objects in the hlsl_constant address space are initialized
5948 // externally, so don't synthesize an implicit initializer.
5950 return true;
5951
5952 if (VD->hasGlobalStorage() && VD->getStorageClass() != SC_Static) {
5953 const Type *Ty = VD->getType().getTypePtr();
5955 return true;
5957 return true;
5958 }
5959
5960 // User-defined structs/classes do not have constructors.
5961 // When declared at a global scope, they are part of the constant buffer
5962 // and should not be initialized by the compiler.
5963 // When declared at a local scope, they are not initialized.
5964 // Also applies to arrays of user-defined structs/classes.
5965 const Type *Ty = VD->getType()->getUnqualifiedDesugaredType();
5966 while (Ty->isArrayType())
5968 if (CXXRecordDecl *RD = Ty->getAsCXXRecordDecl())
5969 return !RD->isHLSLBuiltinRecord();
5970
5971 return false;
5972}
5973
5974std::optional<const DeclBindingInfo *> SemaHLSL::inferGlobalBinding(Expr *E) {
5975 if (auto *Ternary = dyn_cast<ConditionalOperator>(E)) {
5976 auto TrueInfo = inferGlobalBinding(Ternary->getTrueExpr());
5977 auto FalseInfo = inferGlobalBinding(Ternary->getFalseExpr());
5978 if (!TrueInfo || !FalseInfo)
5979 return std::nullopt;
5980 if (*TrueInfo != *FalseInfo)
5981 return std::nullopt;
5982 return TrueInfo;
5983 }
5984
5985 if (auto *ASE = dyn_cast<ArraySubscriptExpr>(E))
5986 E = ASE->getBase()->IgnoreParenImpCasts();
5987
5988 if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParens()))
5989 if (VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
5990 const Type *Ty = VD->getType()->getUnqualifiedDesugaredType();
5991 if (Ty->isArrayType())
5993
5994 if (const auto *AttrResType =
5995 HLSLAttributedResourceType::findHandleTypeOnResource(Ty)) {
5996 ResourceClass RC = AttrResType->getAttrs().ResourceClass;
5997 return Bindings.getDeclBindingInfo(VD, RC);
5998 }
5999 }
6000
6001 return nullptr;
6002}
6003
6004void SemaHLSL::trackLocalResource(VarDecl *VD, Expr *E) {
6005 std::optional<const DeclBindingInfo *> ExprBinding = inferGlobalBinding(E);
6006 if (!ExprBinding) {
6007 SemaRef.Diag(E->getBeginLoc(),
6008 diag::warn_hlsl_assigning_local_resource_is_not_unique)
6009 << E << VD;
6010 return; // Expr use multiple resources
6011 }
6012
6013 if (*ExprBinding == nullptr)
6014 return; // No binding could be inferred to track, return without error
6015
6016 auto PrevBinding = Assigns.find(VD);
6017 if (PrevBinding == Assigns.end()) {
6018 // No previous binding recorded, simply record the new assignment
6019 Assigns.insert({VD, *ExprBinding});
6020 return;
6021 }
6022
6023 // Otherwise, warn if the assignment implies different resource bindings
6024 if (*ExprBinding != PrevBinding->second) {
6025 SemaRef.Diag(E->getBeginLoc(),
6026 diag::warn_hlsl_assigning_local_resource_is_not_unique)
6027 << E << VD;
6028 SemaRef.Diag(VD->getLocation(), diag::note_var_declared_here) << VD;
6029 return;
6030 }
6031
6032 return;
6033}
6034
6036 Expr *RHSExpr, SourceLocation Loc) {
6037 assert((LHSExpr->getType()->isHLSLResourceRecord() ||
6038 LHSExpr->getType()->isHLSLResourceRecordArray()) &&
6039 "expected LHS to be a resource record or array of resource records");
6040 if (Opc != BO_Assign)
6041 return true;
6042
6043 // If LHS is an array subscript, get the underlying declaration.
6044 Expr *E = LHSExpr;
6045 while (auto *ASE = dyn_cast<ArraySubscriptExpr>(E))
6046 E = ASE->getBase()->IgnoreParenImpCasts();
6047
6048 // Report error if LHS is a non-static resource declared at a global scope.
6049 if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParens())) {
6050 if (VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
6051 if (VD->hasGlobalStorage() && VD->getStorageClass() != SC_Static) {
6052 // assignment to global resource is not allowed
6053 SemaRef.Diag(Loc, diag::err_hlsl_assign_to_global_resource) << VD;
6054 SemaRef.Diag(VD->getLocation(), diag::note_var_declared_here) << VD;
6055 return false;
6056 }
6057
6058 trackLocalResource(VD, RHSExpr);
6059 }
6060 }
6061 return true;
6062}
6063
6064// Returns true if the given type can have an overload of the given
6065// binary operator.
6067 CXXRecordDecl *RD = LHSTy->getAsCXXRecordDecl();
6068 if (!RD)
6069 return true;
6070 return RD->isHLSLBuiltinRecord() || Opc != BO_Assign;
6071}
6072
6073// Walks though the global variable declaration, collects all resource binding
6074// requirements and adds them to Bindings
6075void SemaHLSL::collectResourceBindingsOnVarDecl(VarDecl *VD) {
6076 assert(VD->hasGlobalStorage() && VD->getType()->isHLSLIntangibleType() &&
6077 "expected global variable that contains HLSL resource");
6078
6079 // Cbuffers and Tbuffers are HLSLBufferDecl types
6080 if (const HLSLBufferDecl *CBufferOrTBuffer = dyn_cast<HLSLBufferDecl>(VD)) {
6081 Bindings.addDeclBindingInfo(VD, CBufferOrTBuffer->isCBuffer()
6082 ? ResourceClass::CBuffer
6083 : ResourceClass::SRV);
6084 return;
6085 }
6086
6087 // Unwrap arrays
6088 // FIXME: Calculate array size while unwrapping
6089 const Type *Ty = VD->getType()->getUnqualifiedDesugaredType();
6090 while (Ty->isArrayType()) {
6091 const ArrayType *AT = cast<ArrayType>(Ty);
6093 }
6094
6095 // Resource (or array of resources)
6096 if (const HLSLAttributedResourceType *AttrResType =
6097 HLSLAttributedResourceType::findHandleTypeOnResource(Ty)) {
6098 Bindings.addDeclBindingInfo(VD, AttrResType->getAttrs().ResourceClass);
6099 return;
6100 }
6101
6102 // User defined record type
6103 if (const RecordType *RT = dyn_cast<RecordType>(Ty))
6104 collectResourceBindingsOnUserRecordDecl(VD, RT);
6105}
6106
6107// Walks though the explicit resource binding attributes on the declaration,
6108// and makes sure there is a resource that matched the binding and updates
6109// DeclBindingInfoLists
6110void SemaHLSL::processExplicitBindingsOnDecl(VarDecl *VD) {
6111 assert(VD->hasGlobalStorage() && "expected global variable");
6112
6113 bool HasBinding = false;
6114 for (Attr *A : VD->attrs()) {
6115 if (isa<HLSLVkBindingAttr>(A)) {
6116 HasBinding = true;
6117 if (auto PA = VD->getAttr<HLSLVkPushConstantAttr>())
6118 Diag(PA->getLoc(), diag::err_hlsl_attr_incompatible) << A << PA;
6119 }
6120
6121 HLSLResourceBindingAttr *RBA = dyn_cast<HLSLResourceBindingAttr>(A);
6122 if (!RBA || !RBA->hasRegisterSlot())
6123 continue;
6124 HasBinding = true;
6125
6126 RegisterType RT = RBA->getRegisterType();
6127 assert(RT != RegisterType::I && "invalid or obsolete register type should "
6128 "never have an attribute created");
6129
6130 if (RT == RegisterType::C) {
6131 if (Bindings.hasBindingInfoForDecl(VD))
6132 SemaRef.Diag(VD->getLocation(),
6133 diag::warn_hlsl_user_defined_type_missing_member)
6134 << static_cast<int>(RT);
6135 continue;
6136 }
6137
6138 // Find DeclBindingInfo for this binding and update it, or report error
6139 // if it does not exist (user type does to contain resources with the
6140 // expected resource class).
6142 if (DeclBindingInfo *BI = Bindings.getDeclBindingInfo(VD, RC)) {
6143 // update binding info
6144 BI->setBindingAttribute(RBA, BindingType::Explicit);
6145 } else {
6146 SemaRef.Diag(VD->getLocation(),
6147 diag::warn_hlsl_user_defined_type_missing_member)
6148 << static_cast<int>(RT);
6149 }
6150 }
6151
6152 if (!HasBinding && isResourceRecordTypeOrArrayOf(VD))
6153 SemaRef.Diag(VD->getLocation(), diag::warn_hlsl_implicit_binding);
6154}
6155namespace {
6156class InitListTransformer {
6157 Sema &S;
6158 ASTContext &Ctx;
6159 QualType InitTy;
6160 QualType *DstIt = nullptr;
6161 Expr **ArgIt = nullptr;
6162 // Is wrapping the destination type iterator required? This is only used for
6163 // incomplete array types where we loop over the destination type since we
6164 // don't know the full number of elements from the declaration.
6165 bool Wrap;
6166
6167 bool castInitializer(Expr *E) {
6168 assert(DstIt && "This should always be something!");
6169 if (DstIt == DestTypes.end()) {
6170 if (!Wrap) {
6171 ArgExprs.push_back(E);
6172 // This is odd, but it isn't technically a failure due to conversion, we
6173 // handle mismatched counts of arguments differently.
6174 return true;
6175 }
6176 DstIt = DestTypes.begin();
6177 }
6178 InitializedEntity Entity = InitializedEntity::InitializeParameter(
6179 Ctx, *DstIt, /* Consumed (ObjC) */ false);
6180 ExprResult Res = S.PerformCopyInitialization(Entity, E->getBeginLoc(), E);
6181 if (Res.isInvalid())
6182 return false;
6183 Expr *Init = Res.get();
6184 ArgExprs.push_back(Init);
6185 DstIt++;
6186 return true;
6187 }
6188
6189 bool buildInitializerListImpl(Expr *E) {
6190 // If this is an initialization list, traverse the sub initializers.
6191 if (auto *Init = dyn_cast<InitListExpr>(E)) {
6192 for (auto *SubInit : Init->inits())
6193 if (!buildInitializerListImpl(SubInit))
6194 return false;
6195 return true;
6196 }
6197
6198 // If this is a scalar type, just enqueue the expression.
6199 QualType Ty = E->getType().getDesugaredType(Ctx);
6200
6201 if (Ty->isScalarType() || (Ty->isRecordType() && !Ty->isAggregateType()) ||
6203 return castInitializer(E);
6204
6205 // If this is an aggregate type and a prvalue, create an xvalue temporary
6206 // so the member accesses will be xvalues. Wrap it in OpaqueExpr to make
6207 // sure codegen will not generate duplicate copies.
6208 if (E->isPRValue() && Ty->isAggregateType()) {
6210 if (TmpExpr.isInvalid())
6211 return false;
6212 E = TmpExpr.get();
6213 E = new (Ctx) OpaqueValueExpr(E->getBeginLoc(), E->getType(),
6214 E->getValueKind(), E->getObjectKind(), E);
6215 }
6216
6217 if (auto *VecTy = Ty->getAs<VectorType>()) {
6218 uint64_t Size = VecTy->getNumElements();
6219
6220 QualType SizeTy = Ctx.getSizeType();
6221 uint64_t SizeTySize = Ctx.getTypeSize(SizeTy);
6222 for (uint64_t I = 0; I < Size; ++I) {
6223 auto *Idx = IntegerLiteral::Create(Ctx, llvm::APInt(SizeTySize, I),
6224 SizeTy, SourceLocation());
6225
6227 E, E->getBeginLoc(), Idx, E->getEndLoc());
6228 if (ElExpr.isInvalid())
6229 return false;
6230 if (!castInitializer(ElExpr.get()))
6231 return false;
6232 }
6233 return true;
6234 }
6235 if (auto *MTy = Ty->getAs<ConstantMatrixType>()) {
6236 unsigned Rows = MTy->getNumRows();
6237 unsigned Cols = MTy->getNumColumns();
6238 QualType ElemTy = MTy->getElementType();
6239
6240 for (unsigned R = 0; R < Rows; ++R) {
6241 for (unsigned C = 0; C < Cols; ++C) {
6242 // row index literal
6243 Expr *RowIdx = IntegerLiteral::Create(
6244 Ctx, llvm::APInt(Ctx.getIntWidth(Ctx.IntTy), R), Ctx.IntTy,
6245 E->getBeginLoc());
6246 // column index literal
6247 Expr *ColIdx = IntegerLiteral::Create(
6248 Ctx, llvm::APInt(Ctx.getIntWidth(Ctx.IntTy), C), Ctx.IntTy,
6249 E->getBeginLoc());
6251 E, RowIdx, ColIdx, E->getEndLoc());
6252 if (ElExpr.isInvalid())
6253 return false;
6254 if (!castInitializer(ElExpr.get()))
6255 return false;
6256 ElExpr.get()->setType(ElemTy);
6257 }
6258 }
6259 return true;
6260 }
6261
6262 if (auto *ArrTy = dyn_cast<ConstantArrayType>(Ty.getTypePtr())) {
6263 uint64_t Size = ArrTy->getZExtSize();
6264 QualType SizeTy = Ctx.getSizeType();
6265 uint64_t SizeTySize = Ctx.getTypeSize(SizeTy);
6266 for (uint64_t I = 0; I < Size; ++I) {
6267 auto *Idx = IntegerLiteral::Create(Ctx, llvm::APInt(SizeTySize, I),
6268 SizeTy, SourceLocation());
6270 E, E->getBeginLoc(), Idx, E->getEndLoc());
6271 if (ElExpr.isInvalid())
6272 return false;
6273 if (!buildInitializerListImpl(ElExpr.get()))
6274 return false;
6275 }
6276 return true;
6277 }
6278
6279 if (auto *RD = Ty->getAsCXXRecordDecl()) {
6280 llvm::SmallVector<CXXRecordDecl *> RecordDecls;
6281 RecordDecls.push_back(RD);
6282 while (RecordDecls.back()->getNumBases()) {
6283 CXXRecordDecl *D = RecordDecls.back();
6284 assert(D->getNumBases() == 1 &&
6285 "HLSL doesn't support multiple inheritance");
6286 RecordDecls.push_back(
6288 }
6289 while (!RecordDecls.empty()) {
6290 CXXRecordDecl *RD = RecordDecls.pop_back_val();
6291 for (auto *FD : RD->fields()) {
6292 if (FD->isUnnamedBitField())
6293 continue;
6294 DeclAccessPair Found = DeclAccessPair::make(FD, FD->getAccess());
6295 DeclarationNameInfo NameInfo(FD->getDeclName(), E->getBeginLoc());
6297 E, false, E->getBeginLoc(), CXXScopeSpec(), FD, Found, NameInfo);
6298 if (Res.isInvalid())
6299 return false;
6300 if (!buildInitializerListImpl(Res.get()))
6301 return false;
6302 }
6303 }
6304 }
6305 return true;
6306 }
6307
6308 Expr *generateInitListsImpl(QualType Ty) {
6309 Ty = Ty.getDesugaredType(Ctx);
6310 assert(ArgIt != ArgExprs.end() && "Something is off in iteration!");
6311 if (Ty->isScalarType() || (Ty->isRecordType() && !Ty->isAggregateType()) ||
6313 return *(ArgIt++);
6314
6315 llvm::SmallVector<Expr *> Inits;
6316 if (Ty->isVectorType() || Ty->isConstantArrayType() ||
6317 Ty->isConstantMatrixType()) {
6318 QualType ElTy;
6319 uint64_t Size = 0;
6320 if (auto *ATy = Ty->getAs<VectorType>()) {
6321 ElTy = ATy->getElementType();
6322 Size = ATy->getNumElements();
6323 } else if (auto *CMTy = Ty->getAs<ConstantMatrixType>()) {
6324 ElTy = CMTy->getElementType();
6325 Size = CMTy->getNumElementsFlattened();
6326 } else {
6327 auto *VTy = cast<ConstantArrayType>(Ty.getTypePtr());
6328 ElTy = VTy->getElementType();
6329 Size = VTy->getZExtSize();
6330 }
6331 for (uint64_t I = 0; I < Size; ++I)
6332 Inits.push_back(generateInitListsImpl(ElTy));
6333 }
6334 if (auto *RD = Ty->getAsCXXRecordDecl()) {
6335 llvm::SmallVector<CXXRecordDecl *> RecordDecls;
6336 RecordDecls.push_back(RD);
6337 while (RecordDecls.back()->getNumBases()) {
6338 CXXRecordDecl *D = RecordDecls.back();
6339 assert(D->getNumBases() == 1 &&
6340 "HLSL doesn't support multiple inheritance");
6341 RecordDecls.push_back(
6343 }
6344 while (!RecordDecls.empty()) {
6345 CXXRecordDecl *RD = RecordDecls.pop_back_val();
6346 for (auto *FD : RD->fields())
6347 if (!FD->isUnnamedBitField())
6348 Inits.push_back(generateInitListsImpl(FD->getType()));
6349 }
6350 }
6351 auto *NewInit =
6352 new (Ctx) InitListExpr(Ctx, Inits.front()->getBeginLoc(), Inits,
6353 Inits.back()->getEndLoc(), /*isExplicit=*/false);
6354 NewInit->setType(Ty);
6355 return NewInit;
6356 }
6357
6358public:
6359 llvm::SmallVector<QualType, 16> DestTypes;
6360 llvm::SmallVector<Expr *, 16> ArgExprs;
6361 InitListTransformer(Sema &SemaRef, const InitializedEntity &Entity)
6362 : S(SemaRef), Ctx(SemaRef.getASTContext()),
6363 Wrap(Entity.getType()->isIncompleteArrayType()) {
6364 InitTy = Entity.getType().getNonReferenceType();
6365 // When we're generating initializer lists for incomplete array types we
6366 // need to wrap around both when building the initializers and when
6367 // generating the final initializer lists.
6368 if (Wrap) {
6369 assert(InitTy->isIncompleteArrayType());
6370 const IncompleteArrayType *IAT = Ctx.getAsIncompleteArrayType(InitTy);
6371 InitTy = IAT->getElementType();
6372 }
6373 BuildFlattenedTypeList(InitTy, DestTypes);
6374 DstIt = DestTypes.begin();
6375 }
6376
6377 bool buildInitializerList(Expr *E) { return buildInitializerListImpl(E); }
6378
6379 Expr *generateInitLists() {
6380 assert(!ArgExprs.empty() &&
6381 "Call buildInitializerList to generate argument expressions.");
6382 ArgIt = ArgExprs.begin();
6383 if (!Wrap)
6384 return generateInitListsImpl(InitTy);
6385 llvm::SmallVector<Expr *> Inits;
6386 while (ArgIt != ArgExprs.end())
6387 Inits.push_back(generateInitListsImpl(InitTy));
6388
6389 auto *NewInit =
6390 new (Ctx) InitListExpr(Ctx, Inits.front()->getBeginLoc(), Inits,
6391 Inits.back()->getEndLoc(), /*isExplicit=*/false);
6392 llvm::APInt ArySize(64, Inits.size());
6393 NewInit->setType(Ctx.getConstantArrayType(InitTy, ArySize, nullptr,
6394 ArraySizeModifier::Normal, 0));
6395 return NewInit;
6396 }
6397};
6398} // namespace
6399
6400// Recursively detect any incomplete array anywhere in the type graph,
6401// including arrays, struct fields, and base classes.
6403 Ty = Ty.getCanonicalType();
6404
6405 // Array types
6406 if (const ArrayType *AT = dyn_cast<ArrayType>(Ty)) {
6408 return true;
6410 }
6411
6412 // Record (struct/class) types
6413 if (const auto *RT = Ty->getAs<RecordType>()) {
6414 const RecordDecl *RD = RT->getDecl();
6415
6416 // Walk base classes (for C++ / HLSL structs with inheritance)
6417 if (const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
6418 for (const CXXBaseSpecifier &Base : CXXRD->bases()) {
6419 if (containsIncompleteArrayType(Base.getType()))
6420 return true;
6421 }
6422 }
6423
6424 // Walk fields
6425 for (const FieldDecl *F : RD->fields()) {
6426 if (containsIncompleteArrayType(F->getType()))
6427 return true;
6428 }
6429 }
6430
6431 return false;
6432}
6433
6435 InitListExpr *Init) {
6436 // If the initializer is a scalar, just return it.
6437 if (Init->getType()->isScalarType())
6438 return true;
6439 ASTContext &Ctx = SemaRef.getASTContext();
6440 InitListTransformer ILT(SemaRef, Entity);
6441
6442 for (unsigned I = 0; I < Init->getNumInits(); ++I) {
6443 Expr *E = Init->getInit(I);
6444 if (E->HasSideEffects(Ctx)) {
6445 QualType Ty = E->getType();
6446 if (Ty->isRecordType())
6447 E = new (Ctx) MaterializeTemporaryExpr(Ty, E, E->isLValue());
6448 E = new (Ctx) OpaqueValueExpr(E->getBeginLoc(), Ty, E->getValueKind(),
6449 E->getObjectKind(), E);
6450 Init->setInit(I, E);
6451 }
6452 if (!ILT.buildInitializerList(E))
6453 return false;
6454 }
6455 size_t ExpectedSize = ILT.DestTypes.size();
6456 size_t ActualSize = ILT.ArgExprs.size();
6457 if (ExpectedSize == 0 && ActualSize == 0)
6458 return true;
6459
6460 // Reject empty initializer if *any* incomplete array exists structurally
6461 if (ActualSize == 0 && containsIncompleteArrayType(Entity.getType())) {
6462 QualType InitTy = Entity.getType().getNonReferenceType();
6463 if (InitTy.hasAddressSpace())
6464 InitTy = SemaRef.getASTContext().removeAddrSpaceQualType(InitTy);
6465
6466 SemaRef.Diag(Init->getBeginLoc(), diag::err_hlsl_incorrect_num_initializers)
6467 << /*TooManyOrFew=*/(int)(ExpectedSize < ActualSize) << InitTy
6468 << /*ExpectedSize=*/ExpectedSize << /*ActualSize=*/ActualSize;
6469 return false;
6470 }
6471
6472 // We infer size after validating legality.
6473 // For incomplete arrays it is completely arbitrary to choose whether we think
6474 // the user intended fewer or more elements. This implementation assumes that
6475 // the user intended more, and errors that there are too few initializers to
6476 // complete the final element.
6477 if (Entity.getType()->isIncompleteArrayType()) {
6478 assert(ExpectedSize > 0 &&
6479 "The expected size of an incomplete array type must be at least 1.");
6480 ExpectedSize =
6481 ((ActualSize + ExpectedSize - 1) / ExpectedSize) * ExpectedSize;
6482 }
6483
6484 // An initializer list might be attempting to initialize a reference or
6485 // rvalue-reference. When checking the initializer we should look through
6486 // the reference.
6487 QualType InitTy = Entity.getType().getNonReferenceType();
6488 if (InitTy.hasAddressSpace())
6489 InitTy = SemaRef.getASTContext().removeAddrSpaceQualType(InitTy);
6490 if (ExpectedSize != ActualSize) {
6491 int TooManyOrFew = ActualSize > ExpectedSize ? 1 : 0;
6492 SemaRef.Diag(Init->getBeginLoc(), diag::err_hlsl_incorrect_num_initializers)
6493 << TooManyOrFew << InitTy << ExpectedSize << ActualSize;
6494 return false;
6495 }
6496
6497 // generateInitListsImpl will always return an InitListExpr here, because the
6498 // scalar case is handled above.
6499 auto *NewInit = cast<InitListExpr>(ILT.generateInitLists());
6500 Init->resizeInits(Ctx, NewInit->getNumInits());
6501 for (unsigned I = 0; I < NewInit->getNumInits(); ++I)
6502 Init->updateInit(Ctx, I, NewInit->getInit(I));
6503 return true;
6504}
6505
6506static QualType ReportMatrixInvalidMember(Sema &S, StringRef Name,
6507 StringRef Expected,
6508 SourceLocation OpLoc,
6509 SourceLocation CompLoc) {
6510 S.Diag(OpLoc, diag::err_builtin_matrix_invalid_member)
6511 << Name << Expected << SourceRange(CompLoc);
6512 return QualType();
6513}
6514
6517 const IdentifierInfo *CompName,
6518 SourceLocation CompLoc) {
6519 const auto *MT = baseType->castAs<ConstantMatrixType>();
6520 StringRef AccessorName = CompName->getName();
6521 assert(!AccessorName.empty() && "Matrix Accessor must have a name");
6522
6523 unsigned Rows = MT->getNumRows();
6524 unsigned Cols = MT->getNumColumns();
6525 bool IsZeroBasedAccessor = false;
6526 unsigned ChunkLen = 0;
6527 if (AccessorName.size() < 2)
6528 return ReportMatrixInvalidMember(S, AccessorName,
6529 "length 4 for zero based: \'_mRC\' or "
6530 "length 3 for one-based: \'_RC\' accessor",
6531 OpLoc, CompLoc);
6532
6533 if (AccessorName[0] == '_') {
6534 if (AccessorName[1] == 'm') {
6535 IsZeroBasedAccessor = true;
6536 ChunkLen = 4; // zero-based: "_mRC"
6537 } else {
6538 ChunkLen = 3; // one-based: "_RC"
6539 }
6540 } else
6542 S, AccessorName, "zero based: \'_mRC\' or one-based: \'_RC\' accessor",
6543 OpLoc, CompLoc);
6544
6545 if (AccessorName.size() % ChunkLen != 0) {
6546 const llvm::StringRef Expected = IsZeroBasedAccessor
6547 ? "zero based: '_mRC' accessor"
6548 : "one-based: '_RC' accessor";
6549
6550 return ReportMatrixInvalidMember(S, AccessorName, Expected, OpLoc, CompLoc);
6551 }
6552
6553 auto isDigit = [](char c) { return c >= '0' && c <= '9'; };
6554 auto isZeroBasedIndex = [](unsigned i) { return i <= 3; };
6555 auto isOneBasedIndex = [](unsigned i) { return i >= 1 && i <= 4; };
6556
6557 bool HasRepeated = false;
6558 SmallVector<bool, 16> Seen(Rows * Cols, false);
6559 unsigned NumComponents = 0;
6560 const char *Begin = AccessorName.data();
6561
6562 for (unsigned I = 0, E = AccessorName.size(); I < E; I += ChunkLen) {
6563 const char *Chunk = Begin + I;
6564 char RowChar = 0, ColChar = 0;
6565 if (IsZeroBasedAccessor) {
6566 // Zero-based: "_mRC"
6567 if (Chunk[0] != '_' || Chunk[1] != 'm') {
6568 char Bad = (Chunk[0] != '_') ? Chunk[0] : Chunk[1];
6570 S, StringRef(&Bad, 1), "\'_m\' prefix",
6571 OpLoc.getLocWithOffset(I + (Bad == Chunk[0] ? 1 : 2)), CompLoc);
6572 }
6573 RowChar = Chunk[2];
6574 ColChar = Chunk[3];
6575 } else {
6576 // One-based: "_RC"
6577 if (Chunk[0] != '_')
6579 S, StringRef(&Chunk[0], 1), "\'_\' prefix",
6580 OpLoc.getLocWithOffset(I + 1), CompLoc);
6581 RowChar = Chunk[1];
6582 ColChar = Chunk[2];
6583 }
6584
6585 // Must be digits.
6586 bool IsDigitsError = false;
6587 if (!isDigit(RowChar)) {
6588 unsigned BadPos = IsZeroBasedAccessor ? 2 : 1;
6589 ReportMatrixInvalidMember(S, StringRef(&RowChar, 1), "row as integer",
6590 OpLoc.getLocWithOffset(I + BadPos + 1),
6591 CompLoc);
6592 IsDigitsError = true;
6593 }
6594
6595 if (!isDigit(ColChar)) {
6596 unsigned BadPos = IsZeroBasedAccessor ? 3 : 2;
6597 ReportMatrixInvalidMember(S, StringRef(&ColChar, 1), "column as integer",
6598 OpLoc.getLocWithOffset(I + BadPos + 1),
6599 CompLoc);
6600 IsDigitsError = true;
6601 }
6602 if (IsDigitsError)
6603 return QualType();
6604
6605 unsigned Row = RowChar - '0';
6606 unsigned Col = ColChar - '0';
6607
6608 bool HasIndexingError = false;
6609 if (IsZeroBasedAccessor) {
6610 // 0-based [0..3]
6611 if (!isZeroBasedIndex(Row)) {
6612 S.Diag(OpLoc, diag::err_hlsl_matrix_element_not_in_bounds)
6613 << /*row*/ 0 << /*zero-based*/ 0 << SourceRange(CompLoc);
6614 HasIndexingError = true;
6615 }
6616 if (!isZeroBasedIndex(Col)) {
6617 S.Diag(OpLoc, diag::err_hlsl_matrix_element_not_in_bounds)
6618 << /*col*/ 1 << /*zero-based*/ 0 << SourceRange(CompLoc);
6619 HasIndexingError = true;
6620 }
6621 } else {
6622 // 1-based [1..4]
6623 if (!isOneBasedIndex(Row)) {
6624 S.Diag(OpLoc, diag::err_hlsl_matrix_element_not_in_bounds)
6625 << /*row*/ 0 << /*one-based*/ 1 << SourceRange(CompLoc);
6626 HasIndexingError = true;
6627 }
6628 if (!isOneBasedIndex(Col)) {
6629 S.Diag(OpLoc, diag::err_hlsl_matrix_element_not_in_bounds)
6630 << /*col*/ 1 << /*one-based*/ 1 << SourceRange(CompLoc);
6631 HasIndexingError = true;
6632 }
6633 // Convert to 0-based after range checking.
6634 --Row;
6635 --Col;
6636 }
6637
6638 if (HasIndexingError)
6639 return QualType();
6640
6641 // Note: matrix swizzle index is hard coded. That means Row and Col can
6642 // potentially be larger than Rows and Cols if matrix size is less than
6643 // the max index size.
6644 bool HasBoundsError = false;
6645 if (Row >= Rows) {
6646 Diag(OpLoc, diag::err_hlsl_matrix_index_out_of_bounds)
6647 << /*Row*/ 0 << Row << Rows << SourceRange(CompLoc);
6648 HasBoundsError = true;
6649 }
6650 if (Col >= Cols) {
6651 Diag(OpLoc, diag::err_hlsl_matrix_index_out_of_bounds)
6652 << /*Col*/ 1 << Col << Cols << SourceRange(CompLoc);
6653 HasBoundsError = true;
6654 }
6655 if (HasBoundsError)
6656 return QualType();
6657
6658 unsigned FlatIndex = Row * Cols + Col;
6659 if (Seen[FlatIndex])
6660 HasRepeated = true;
6661 Seen[FlatIndex] = true;
6662 ++NumComponents;
6663 }
6664 if (NumComponents == 0 || NumComponents > 4) {
6665 S.Diag(OpLoc, diag::err_hlsl_matrix_swizzle_invalid_length)
6666 << NumComponents << SourceRange(CompLoc);
6667 return QualType();
6668 }
6669
6670 QualType ElemTy = MT->getElementType();
6671 if (NumComponents == 1)
6672 return ElemTy;
6673 QualType VT = S.Context.getExtVectorType(ElemTy, NumComponents);
6674 if (HasRepeated)
6675 VK = VK_PRValue;
6676
6677 for (Sema::ExtVectorDeclsType::iterator
6679 E = S.ExtVectorDecls.end();
6680 I != E; ++I) {
6681 if ((*I)->getUnderlyingType() == VT)
6683 /*Qualifier=*/std::nullopt, *I);
6684 }
6685
6686 return VT;
6687}
6688
6690 // If initializing a local resource, track the resource binding it is using
6691 if (VDecl->getType()->isHLSLResourceRecord() && !VDecl->hasGlobalStorage())
6692 trackLocalResource(VDecl, Init);
6693
6694 const HLSLVkConstantIdAttr *ConstIdAttr =
6695 VDecl->getAttr<HLSLVkConstantIdAttr>();
6696 if (!ConstIdAttr)
6697 return true;
6698
6699 ASTContext &Context = SemaRef.getASTContext();
6700
6701 APValue InitValue;
6702 if (!Init->isCXX11ConstantExpr(Context, &InitValue)) {
6703 Diag(VDecl->getLocation(), diag::err_specialization_const);
6704 VDecl->setInvalidDecl();
6705 return false;
6706 }
6707
6708 Builtin::ID BID =
6710
6711 // Argument 1: The ID from the attribute
6712 int ConstantID = ConstIdAttr->getId();
6713 llvm::APInt IDVal(Context.getIntWidth(Context.IntTy), ConstantID);
6714 Expr *IdExpr = IntegerLiteral::Create(Context, IDVal, Context.IntTy,
6715 ConstIdAttr->getLocation());
6716
6717 SmallVector<Expr *, 2> Args = {IdExpr, Init};
6718 Expr *C = SemaRef.BuildBuiltinCallExpr(Init->getExprLoc(), BID, Args);
6719 if (C->getType()->getCanonicalTypeUnqualified() !=
6721 C = SemaRef
6722 .BuildCStyleCastExpr(SourceLocation(),
6723 Context.getTrivialTypeSourceInfo(
6724 Init->getType(), Init->getExprLoc()),
6725 SourceLocation(), C)
6726 .get();
6727 }
6728 Init = C;
6729 return true;
6730}
6731
6733 SourceLocation NameLoc) {
6734 if (!Template)
6735 return QualType();
6736
6737 DeclContext *DC = Template->getDeclContext();
6738 if (!DC->isNamespace() || !cast<NamespaceDecl>(DC)->getIdentifier() ||
6739 cast<NamespaceDecl>(DC)->getName() != "hlsl")
6740 return QualType();
6741
6742 TemplateParameterList *Params = Template->getTemplateParameters();
6743 if (!Params || Params->size() != 1)
6744 return QualType();
6745
6746 if (!Template->isImplicit())
6747 return QualType();
6748
6749 // We manually extract default arguments here instead of letting
6750 // CheckTemplateIdType handle it. This ensures that for resource types that
6751 // lack a default argument (like Buffer), we return a null QualType, which
6752 // triggers the "requires template arguments" error rather than a less
6753 // descriptive "too few template arguments" error.
6754 TemplateArgumentListInfo TemplateArgs(NameLoc, NameLoc);
6755 for (NamedDecl *P : *Params) {
6756 if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(P)) {
6757 if (TTP->hasDefaultArgument()) {
6758 TemplateArgs.addArgument(TTP->getDefaultArgument());
6759 continue;
6760 }
6761 } else if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P)) {
6762 if (NTTP->hasDefaultArgument()) {
6763 TemplateArgs.addArgument(NTTP->getDefaultArgument());
6764 continue;
6765 }
6766 } else if (auto *TTPD = dyn_cast<TemplateTemplateParmDecl>(P)) {
6767 if (TTPD->hasDefaultArgument()) {
6768 TemplateArgs.addArgument(TTPD->getDefaultArgument());
6769 continue;
6770 }
6771 }
6772 return QualType();
6773 }
6774
6775 return SemaRef.CheckTemplateIdType(
6777 TemplateArgs, nullptr, /*ForNestedNameSpecifier=*/false);
6778}
Defines the clang::ASTContext interface.
Defines enum values for all the target-independent builtin functions.
llvm::dxil::ResourceClass ResourceClass
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
TokenType getType() const
Returns the token's type, e.g.
FormatToken * Previous
The previous token in the unwrapped line.
Defines the clang::IdentifierInfo, clang::IdentifierTable, and clang::Selector interfaces.
#define X(type, name)
Definition Value.h:97
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
llvm::SmallVector< std::pair< const MemRegion *, SVal >, 4 > Bindings
static bool CheckArgTypeMatches(Sema *S, Expr *Arg, QualType ExpectedType)
static void BuildFlattenedTypeList(QualType BaseTy, llvm::SmallVectorImpl< QualType > &List)
static bool CheckUnsignedIntRepresentation(Sema *S, SourceLocation Loc, int ArgOrdinal, clang::QualType PassedType)
static bool containsIncompleteArrayType(QualType Ty)
static QualType handleIntegerVectorBinOpConversion(Sema &SemaRef, ExprResult &LHS, ExprResult &RHS, QualType LHSType, QualType RHSType, QualType LElTy, QualType RElTy, bool IsCompAssign)
static bool convertToRegisterType(StringRef Slot, RegisterType *RT)
Definition SemaHLSL.cpp:98
static StringRef createRegisterString(ASTContext &AST, RegisterType RegType, unsigned N)
Definition SemaHLSL.cpp:200
static bool CheckWaveActive(Sema *S, CallExpr *TheCall)
static void createHostLayoutStructForBuffer(Sema &S, HLSLBufferDecl *BufDecl)
Definition SemaHLSL.cpp:636
static void castVector(Sema &S, ExprResult &E, QualType &Ty, unsigned Sz)
static QualType ReportMatrixInvalidMember(Sema &S, StringRef Name, StringRef Expected, SourceLocation OpLoc, SourceLocation CompLoc)
static bool CheckBoolSelect(Sema *S, CallExpr *TheCall)
static unsigned calculateLegacyCbufferFieldAlign(const ASTContext &Context, QualType T)
Definition SemaHLSL.cpp:262
static bool CheckScalarFloatOperand(Sema &S, CallExpr *TheCall, unsigned ArgIndex)
static bool isZeroSizedArray(const ConstantArrayType *CAT)
Definition SemaHLSL.cpp:381
static bool DiagnoseHLSLRegisterAttribute(Sema &S, SourceLocation &ArgLoc, Decl *D, RegisterType RegType, bool SpecifiedSpace)
static bool CheckAnyScalarOrVectorOrMatrix(Sema *S, CallExpr *TheCall, unsigned ArgIndex)
static bool hasConstantBufferLayout(QualType QT)
llvm::dxbc::PSV::SemanticKind SemanticKind
Definition SemaHLSL.cpp:59
static FieldDecl * createFieldForHostLayoutStruct(Sema &S, const Type *Ty, IdentifierInfo *II, CXXRecordDecl *LayoutStruct)
Definition SemaHLSL.cpp:544
static bool CheckIntegerElementTypeShaderModel(Sema &S, CallExpr *TheCall, QualType ContainedType, SampleKind Kind)
static bool CheckUnsignedIntVecRepresentation(Sema *S, SourceLocation Loc, int ArgOrdinal, clang::QualType PassedType)
SampleKind
static bool isInvalidConstantBufferLeafElementType(const Type *Ty)
Definition SemaHLSL.cpp:415
static bool CheckCalculateLodBuiltin(Sema &S, CallExpr *TheCall)
static Builtin::ID getSpecConstBuiltinId(const Type *Type)
Definition SemaHLSL.cpp:166
static bool CheckNoDoubleElementType(Sema &S, CallExpr *TheCall, QualType ContainedType, StringRef DefaultName)
static bool CheckFloatingOrIntRepresentation(Sema *S, SourceLocation Loc, int ArgOrdinal, clang::QualType PassedType)
static const Type * createHostLayoutType(Sema &S, const Type *Ty)
Definition SemaHLSL.cpp:506
static bool CheckAnyScalarOrVector(Sema *S, CallExpr *TheCall, unsigned ArgIndex)
static const HLSLAttributedResourceType * getResourceArrayHandleType(QualType QT)
Definition SemaHLSL.cpp:397
static IdentifierInfo * getHostLayoutStructName(Sema &S, NamedDecl *BaseDecl, bool MustBeUnique)
Definition SemaHLSL.cpp:471
static QualType createCounterHandleType(ASTContext &AST, QualType MainHandleTy)
static bool CheckArgAddrSpaceOneOf(Sema *S, CallExpr *TheCall, unsigned ArgIndex, ArrayRef< LangAS > AllowedSpaces)
static void addImplicitBindingAttrToDecl(Sema &S, Decl *D, RegisterType RT, uint32_t ImplicitBindingOrderID)
Definition SemaHLSL.cpp:680
static StringRef getSampleMethodName(SampleKind Kind)
static void SetElementTypeAsReturnType(Sema *S, CallExpr *TheCall, QualType ReturnType)
static unsigned calculateLegacyCbufferSize(const ASTContext &Context, QualType T)
Definition SemaHLSL.cpp:281
static bool CheckLoadLevelBuiltin(Sema &S, CallExpr *TheCall)
static RegisterType getRegisterType(ResourceClass RC)
Definition SemaHLSL.cpp:65
static bool ValidateRegisterNumber(uint64_t SlotNum, Decl *TheDecl, ASTContext &Ctx, RegisterType RegTy)
static bool isVkPipelineBuiltin(const ASTContext &AstContext, FunctionDecl *FD, HLSLAppliedSemanticAttr *Semantic, bool IsInput)
Definition SemaHLSL.cpp:868
static bool CheckModifiableLValue(Sema *S, CallExpr *TheCall, unsigned ArgIndex)
static QualType castElement(Sema &S, ExprResult &E, QualType Ty)
static char getRegisterTypeChar(RegisterType RT)
Definition SemaHLSL.cpp:130
static bool CheckNotBoolScalarOrVector(Sema *S, CallExpr *TheCall, unsigned ArgIndex)
static bool isMatrixOrArrayOfMatrix(const ASTContext &Ctx, QualType QT)
static QualType getTypedResourceElementType(QualType ContainedType)
static bool findExistingMatrixLayoutMarker(QualType T, attr::Kind &ExistingKind)
Walks the existing AttributedType sugar of T looking for a previously applied HLSLRowMajor/HLSLColumn...
static CXXRecordDecl * findRecordDeclInContext(IdentifierInfo *II, DeclContext *DC)
Definition SemaHLSL.cpp:454
static bool CheckWavePrefix(Sema *S, CallExpr *TheCall)
static bool CheckExpectedBitWidth(Sema *S, CallExpr *TheCall, unsigned ArgOrdinal, unsigned Width)
static LangAS getLangASFromResourceClass(ResourceClass RC)
Definition SemaHLSL.cpp:83
static bool CheckTextureSamplerAndLocation(Sema &S, CallExpr *TheCall, bool IncludeArraySlice=true)
static bool CheckVectorSelect(Sema *S, CallExpr *TheCall)
static QualType handleFloatVectorBinOpConversion(Sema &SemaRef, ExprResult &LHS, ExprResult &RHS, QualType LHSType, QualType RHSType, QualType LElTy, QualType RElTy, bool IsCompAssign)
static const Type * getHostLayoutFieldType(QualType QT)
Definition SemaHLSL.cpp:535
static ResourceClass getResourceClass(RegisterType RT)
Definition SemaHLSL.cpp:148
static CXXRecordDecl * createHostLayoutStruct(Sema &S, CXXRecordDecl *StructDecl)
Definition SemaHLSL.cpp:571
static bool CheckScalarOrVector(Sema *S, CallExpr *TheCall, QualType Scalar, unsigned ArgIndex)
static QualType getVectorOrScalarType(Sema &S, QualType BaseType, unsigned Count)
static bool isLayoutAdaptingMatrixBuiltin(unsigned BuiltinID)
static bool CheckSamplingBuiltin(Sema &S, CallExpr *TheCall, SampleKind Kind)
static bool CheckScalarOrVectorOrMatrix(Sema *S, CallExpr *TheCall, QualType Scalar, unsigned ArgIndex)
static bool CheckFloatRepresentation(Sema *S, SourceLocation Loc, int ArgOrdinal, clang::QualType PassedType)
static bool CheckAnyDoubleRepresentation(Sema *S, SourceLocation Loc, int ArgOrdinal, clang::QualType PassedType)
static bool requiresImplicitBufferLayoutStructure(const CXXRecordDecl *RD)
Definition SemaHLSL.cpp:434
static bool CheckResourceHandle(Sema *S, CallExpr *TheCall, unsigned ArgIndex, llvm::function_ref< bool(const HLSLAttributedResourceType *ResType)> Check=nullptr)
static void validatePackoffset(Sema &S, HLSLBufferDecl *BufDecl)
Definition SemaHLSL.cpp:328
static StringRef getCurrentResourceMethodName(Sema &S, StringRef DefaultName)
static bool IsDefaultBufferConstantDecl(const ASTContext &Ctx, VarDecl *VD)
HLSLResourceBindingAttr::RegisterType RegisterType
Definition SemaHLSL.cpp:60
static CastKind getScalarCastKind(ASTContext &Ctx, QualType DestTy, QualType SrcTy)
static bool CheckGatherBuiltin(Sema &S, CallExpr *TheCall, bool IsCmp)
static bool isValidWaveSizeValue(unsigned Value)
static bool isResourceRecordTypeOrArrayOf(QualType Ty)
Definition SemaHLSL.cpp:388
static bool CheckLoadMSBuiltin(Sema &S, CallExpr *TheCall)
static bool AccumulateHLSLResourceSlots(QualType Ty, uint64_t &StartSlot, const uint64_t &Limit, const ResourceClass ResClass, ASTContext &Ctx, uint64_t ArrayCount=1)
static bool CheckNoDoubleVectors(Sema *S, SourceLocation Loc, int ArgOrdinal, clang::QualType PassedType)
static bool ValidateMultipleRegisterAnnotations(Sema &S, Decl *TheDecl, RegisterType regType)
static bool DiagnoseLocalRegisterBinding(Sema &S, SourceLocation &ArgLoc, Decl *D, RegisterType RegType, bool SpecifiedSpace)
static bool CheckIndexType(Sema *S, CallExpr *TheCall, unsigned IndexArgIndex)
This file declares semantic analysis for HLSL constructs.
Defines the clang::SourceLocation class and associated facilities.
Defines various enumerations that describe declaration and type specifiers.
C Language Family Type Representation.
Defines the clang::TypeLoc interface and its subclasses.
C Language Family Type Representation.
static const TypeInfo & getInfo(unsigned id)
Definition Types.cpp:44
return(__x > > __y)|(__x<<(32 - __y))
APValue - This class implements a discriminated union of [uninitialized] [APSInt] [APFloat],...
Definition APValue.h:122
virtual bool HandleTopLevelDecl(DeclGroupRef D)
HandleTopLevelDecl - Handle the specified top-level declaration.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:239
unsigned getIntWidth(QualType T) const
int getIntegerTypeOrder(QualType LHS, QualType RHS) const
Return the highest ranked integer type, see C99 6.3.1.8p1.
CanQualType FloatTy
QualType getPointerType(QualType T) const
Return the uniqued reference to the type for a pointer to the specified type.
const IncompleteArrayType * getAsIncompleteArrayType(QualType T) const
IdentifierTable & Idents
Definition ASTContext.h:846
QualType getConstantArrayType(QualType EltTy, const llvm::APInt &ArySize, const Expr *SizeExpr, ArraySizeModifier ASM, unsigned IndexTypeQuals) const
Return the unique reference to the type for a constant array of the specified element type.
QualType getBaseElementType(const ArrayType *VAT) const
Return the innermost element type of an array type.
int getFloatingTypeOrder(QualType LHS, QualType RHS) const
Compare the rank of the two specified floating point types, ignoring the domain of the type (i....
CanQualType BoolTy
TypeSourceInfo * getTrivialTypeSourceInfo(QualType T, SourceLocation Loc=SourceLocation()) const
Allocate a TypeSourceInfo where all locations have been initialized to a given location,...
QualType getStringLiteralArrayType(QualType EltTy, unsigned Length) const
Return a type for a constant array for a string literal of the specified element type and length.
CanQualType CharTy
CanQualType IntTy
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.
CanQualType UnsignedIntTy
QualType getTypedefType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier Qualifier, const TypedefNameDecl *Decl, QualType UnderlyingType=QualType(), std::optional< bool > TypeMatchesDeclOrNone=std::nullopt) const
Return the unique reference to the type for the specified typedef-name decl.
llvm::StringRef backupStr(llvm::StringRef S) const
Definition ASTContext.h:928
QualType getSizeType() const
Return the unique type for "size_t" (C99 7.17), defined in <stddef.h>.
QualType getExtVectorType(QualType VectorType, unsigned NumElts) const
Return the unique reference to an extended vector type of the specified element type and size.
const TargetInfo & getTargetInfo() const
Definition ASTContext.h:965
QualType getHLSLAttributedResourceType(QualType Wrapped, QualType Contained, const HLSLAttributedResourceType::Attributes &Attrs)
QualType getAddrSpaceQualType(QualType T, LangAS AddressSpace) const
Return the uniqued reference to the type for an address space qualified type with the specified type ...
CanQualType getCanonicalTagType(const TagDecl *TD) const
static bool hasSameUnqualifiedType(QualType T1, QualType T2)
Determine whether the given types are equivalent after cvr-qualifiers have been removed.
QualType getConstantMatrixType(QualType ElementType, unsigned NumRows, unsigned NumColumns) const
Return the unique reference to the matrix type of the specified element type and size.
unsigned getTypeAlign(QualType T) const
Return the ABI-specified alignment of a (complete) type T, in bits.
PtrTy get() const
Definition Ownership.h:171
bool isInvalid() const
Definition Ownership.h:167
Represents an array type, per C99 6.7.5.2 - Array Declarators.
Definition TypeBase.h:3813
QualType getElementType() const
Definition TypeBase.h:3825
Attr - This represents one attribute.
Definition Attr.h:46
attr::Kind getKind() const
Definition Attr.h:92
SourceLocation getLocation() const
Definition Attr.h:99
SourceLocation getScopeLoc() const
const IdentifierInfo * getScopeName() const
SourceLocation getLoc() const
const IdentifierInfo * getAttrName() const
Represents a base class of a C++ class.
Definition DeclCXX.h:146
QualType getType() const
Retrieves the type of the base class.
Definition DeclCXX.h:249
Represents a static or instance method of a struct/union/class.
Definition DeclCXX.h:2150
Represents a C++ struct/union/class.
Definition DeclCXX.h:258
bool isHLSLIntangible() const
Returns true if the class contains HLSL intangible type, either as a field or in base class.
Definition DeclCXX.h:1566
static CXXRecordDecl * Create(const ASTContext &C, TagKind TK, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, CXXRecordDecl *PrevDecl=nullptr)
Definition DeclCXX.cpp:133
void setBases(CXXBaseSpecifier const *const *Bases, unsigned NumBases)
Sets the base classes of this struct or class.
Definition DeclCXX.cpp:185
base_class_iterator bases_end()
Definition DeclCXX.h:618
void completeDefinition() override
Indicates that the definition of this class is now complete.
Definition DeclCXX.cpp:2247
base_class_range bases()
Definition DeclCXX.h:609
unsigned getNumBases() const
Retrieves the number of base classes of this class.
Definition DeclCXX.h:603
bool isHLSLBuiltinRecord() const
Returns true if the class is a built-in HLSL record.
Definition DeclCXX.h:1569
base_class_iterator bases_begin()
Definition DeclCXX.h:616
bool isEmpty() const
Determine whether this is an empty class in the sense of (C++11 [meta.unary.prop]).
Definition DeclCXX.h:1196
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition Expr.h:2987
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition Expr.h:3191
SourceLocation getBeginLoc() const
Definition Expr.h:3321
static CallExpr * Create(const ASTContext &Ctx, Expr *Fn, ArrayRef< Expr * > Args, QualType Ty, ExprValueKind VK, SourceLocation RParenLoc, FPOptionsOverride FPFeatures, unsigned MinNumArgs=0, ADLCallKind UsesADL=NotADL)
Create a call expression.
Definition Expr.cpp:1545
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
Definition Expr.h:3170
Expr * getCallee()
Definition Expr.h:3134
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition Expr.h:3178
SourceLocation getEndLoc() const
Definition Expr.h:3340
Decl * getCalleeDecl()
Definition Expr.h:3164
static CanQual< Type > CreateUnsafe(QualType Other)
QualType withConst() const
Retrieves a version of this type with const applied.
const T * getTypePtr() const
Retrieve the underlying type pointer, which refers to a canonical type.
QuantityType getQuantity() const
getQuantity - Get the raw integer representation of this quantity.
Definition CharUnits.h:185
Represents the canonical version of C arrays with a specified constant size.
Definition TypeBase.h:3851
bool isZeroSize() const
Return true if the size is zero.
Definition TypeBase.h:3921
llvm::APInt getSize() const
Return the constant array size as an APInt.
Definition TypeBase.h:3907
uint64_t getZExtSize() const
Return the size zero-extended as a uint64_t.
Definition TypeBase.h:3927
Represents a concrete matrix type with constant number of rows and columns.
Definition TypeBase.h:4478
unsigned getNumColumns() const
Returns the number of columns in the matrix.
Definition TypeBase.h:4497
static DeclAccessPair make(NamedDecl *D, AccessSpecifier AS)
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Definition DeclBase.h:1466
bool isNamespace() const
Definition DeclBase.h:2239
lookup_result lookup(DeclarationName Name) const
lookup - Find the declarations (if any) with the given Name in this context.
bool isTranslationUnit() const
Definition DeclBase.h:2222
void addDecl(Decl *D)
Add the declaration D into this context.
decl_range decls() const
decls_begin/decls_end - Iterate over the declarations stored in this context.
Definition DeclBase.h:2423
DeclContext * getNonTransparentContext()
A reference to a declared variable, function, enum, etc.
Definition Expr.h:1290
static DeclRefExpr * Create(const ASTContext &Context, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, ValueDecl *D, bool RefersToEnclosingVariableOrCapture, SourceLocation NameLoc, QualType T, ExprValueKind VK, NamedDecl *FoundD=nullptr, const TemplateArgumentListInfo *TemplateArgs=nullptr, NonOdrUseReason NOUR=NOUR_None)
Definition Expr.cpp:494
ValueDecl * getDecl()
Definition Expr.h:1358
Decl - This represents one declaration (or definition), e.g.
Definition DeclBase.h:86
T * getAttr() const
Definition DeclBase.h:581
ASTContext & getASTContext() const LLVM_READONLY
Definition DeclBase.cpp:550
void addAttr(Attr *A)
attr_iterator attr_end() const
Definition DeclBase.h:550
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
Definition DeclBase.h:601
void setInvalidDecl(bool Invalid=true)
setInvalidDecl - Indicates the Decl had a semantic error.
Definition DeclBase.cpp:178
bool isInExportDeclContext() const
Whether this declaration was exported in a lexical context.
attr_iterator attr_begin() const
Definition DeclBase.h:547
DeclContext * getNonTransparentDeclContext()
Return the non transparent context.
SourceLocation getLocation() const
Definition DeclBase.h:447
void setImplicit(bool I=true)
Definition DeclBase.h:602
DeclContext * getDeclContext()
Definition DeclBase.h:456
attr_range attrs() const
Definition DeclBase.h:543
AccessSpecifier getAccess() const
Definition DeclBase.h:515
SourceLocation getBeginLoc() const LLVM_READONLY
Definition DeclBase.h:439
void dropAttr()
Definition DeclBase.h:564
bool hasAttr() const
Definition DeclBase.h:585
The name of a declaration.
Represents a ValueDecl that came out of a declarator.
Definition Decl.h:781
SourceLocation getBeginLoc() const LLVM_READONLY
Definition Decl.h:832
This represents one expression.
Definition Expr.h:113
bool isIntegerConstantExpr(const ASTContext &Ctx) const
void setType(QualType t)
Definition Expr.h:146
ExprValueKind getValueKind() const
getValueKind - The value kind that this expression produces.
Definition Expr.h:448
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
Definition Expr.cpp:3123
Expr * IgnoreParens() LLVM_READONLY
Skip past any parentheses which might surround this expression until reaching a fixed point.
Definition Expr.cpp:3119
bool isPRValue() const
Definition Expr.h:286
bool isLValue() const
isLValue - True if this expression is an "l-value" according to the rules of the current language.
Definition Expr.h:285
ExprObjectKind getObjectKind() const
getObjectKind - The object kind that this expression produces.
Definition Expr.h:455
Expr * IgnoreCasts() LLVM_READONLY
Skip past any casts which might surround this expression until reaching a fixed point.
Definition Expr.cpp:3107
bool HasSideEffects(const ASTContext &Ctx, bool IncludePossibleEffects=true) const
HasSideEffects - This routine returns true for all those expressions which have any effect other than...
Definition Expr.cpp:3722
std::optional< llvm::APSInt > getIntegerConstantExpr(const ASTContext &Ctx, bool AllowRelaxedEval=false) const
isIntegerConstantExpr - Return the value if this expression is a valid integer constant expression.
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Definition Expr.cpp:283
@ MLV_Valid
Definition Expr.h:307
QualType getType() const
Definition Expr.h:145
ExtVectorType - Extended vector type.
Definition TypeBase.h:4358
Represents difference between two FPOptions values.
Represents a member of a struct/union/class.
Definition Decl.h:3295
static FieldDecl * Create(const ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, const IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, Expr *BW, bool Mutable, InClassInitStyle InitStyle)
Definition Decl.cpp:4765
static FixItHint CreateReplacement(CharSourceRange RemoveRange, StringRef Code)
Create a code modification hint that replaces the given source range with the given code string.
Definition Diagnostic.h:140
Represents a function declaration or definition.
Definition Decl.h:2059
const ParmVarDecl * getParamDecl(unsigned i) const
Definition Decl.h:2928
Stmt * getBody(const FunctionDecl *&Definition) const
Retrieve the body (definition) of the function.
Definition Decl.cpp:3266
bool isThisDeclarationADefinition() const
Returns whether this specific declaration of the function is also a definition that does not contain ...
Definition Decl.h:2428
QualType getReturnType() const
Definition Decl.h:2976
ArrayRef< ParmVarDecl * > parameters() const
Definition Decl.h:2905
bool isTemplateInstantiation() const
Determines if the given function was instantiated from a function template.
Definition Decl.cpp:4296
redecl_range redecls() const
Returns an iterator range for all the redeclarations of the same decl.
unsigned getNumParams() const
Return the number of parameters this function must have based on its FunctionType.
Definition Decl.cpp:3868
DeclarationNameInfo getNameInfo() const
Definition Decl.h:2325
bool hasBody(const FunctionDecl *&Definition) const
Returns true if the function has a body.
Definition Decl.cpp:3186
bool isDefined(const FunctionDecl *&Definition, bool CheckForPendingFriendDefinition=false) const
Returns true if the function has a definition that does not need to be instantiated.
Definition Decl.cpp:3233
HLSLBufferDecl - Represent a cbuffer or tbuffer declaration.
Definition Decl.h:5332
static HLSLBufferDecl * Create(ASTContext &C, DeclContext *LexicalParent, bool CBuffer, SourceLocation KwLoc, IdentifierInfo *ID, SourceLocation IDLoc, SourceLocation LBrace)
Definition Decl.cpp:5977
void addLayoutStruct(CXXRecordDecl *LS)
Definition Decl.cpp:6017
void setHasValidPackoffset(bool PO)
Definition Decl.h:5377
static HLSLBufferDecl * CreateDefaultCBuffer(ASTContext &C, DeclContext *LexicalParent, ArrayRef< Decl * > DefaultCBufferDecls)
Definition Decl.cpp:6000
buffer_decl_range buffer_decls() const
Definition Decl.h:5407
static HLSLOutArgExpr * Create(const ASTContext &C, QualType Ty, OpaqueValueExpr *Base, OpaqueValueExpr *OpV, Expr *WB, bool IsInOut)
Definition Expr.cpp:5697
static HLSLRootSignatureDecl * Create(ASTContext &C, DeclContext *DC, SourceLocation Loc, IdentifierInfo *ID, llvm::dxbc::RootSignatureVersion Version, ArrayRef< llvm::hlsl::rootsig::RootElement > RootElements)
Definition Decl.cpp:6063
One of these records is kept for each identifier that is lexed.
StringRef getName() const
Return the actual identifier string.
A simple pair of identifier info and location.
SourceLocation getLoc() const
IdentifierInfo * getIdentifierInfo() const
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
ImplicitCastExpr - Allows us to explicitly represent implicit type conversions, which have no direct ...
Definition Expr.h:3897
static ImplicitCastExpr * Create(const ASTContext &Context, QualType T, CastKind Kind, Expr *Operand, const CXXCastPath *BasePath, ExprValueKind Cat, FPOptionsOverride FPO)
Definition Expr.cpp:2103
Describes an C or C++ initializer list.
Definition Expr.h:5352
Describes an entity that is being initialized.
QualType getType() const
Retrieve type being initialized.
static InitializedEntity InitializeParameter(ASTContext &Context, ParmVarDecl *Parm)
Create the initialization entity for a parameter.
static IntegerLiteral * Create(const ASTContext &C, const llvm::APInt &V, QualType type, SourceLocation l)
Returns a new integer literal with value 'V' and type 'type'.
Definition Expr.cpp:981
iterator begin(ExternalSemaSource *source, bool LocalOnly=false)
Represents the results of name lookup.
Definition Lookup.h:147
Represents a prvalue temporary that is written into memory so that a reference can bind to it.
Definition ExprCXX.h:4973
Represents a matrix type, as defined in the Matrix Types clang extensions.
Definition TypeBase.h:4428
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
Definition Expr.h:3408
ValueDecl * getMemberDecl() const
Retrieve the member declaration to which this expression refers.
Definition Expr.h:3491
Expr * getBase() const
Definition Expr.h:3485
This represents a decl that may have a name.
Definition Decl.h:275
NamedDecl * getUnderlyingDecl()
Looks through UsingDecls and ObjCCompatibleAliasDecls for the underlying named decl.
Definition Decl.h:488
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
Definition Decl.h:296
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Definition Decl.h:302
DeclarationName getDeclName() const
Get the actual, stored name of the declaration, which may be a special name.
Definition Decl.h:341
A C++ nested-name-specifier augmented with source location information.
OpaqueValueExpr - An expression referring to an opaque object of a fixed type and value class.
Definition Expr.h:1198
Represents a parameter to a function.
Definition Decl.h:1820
ParsedAttr - Represents a syntactic attribute.
Definition ParsedAttr.h:119
unsigned getSemanticSpelling() const
If the parsed attribute has a semantic equivalent, and it would have a semantic Spelling enumeration ...
unsigned getMinArgs() const
bool checkExactlyNumArgs(class Sema &S, unsigned Num) const
Check if the attribute has exactly as many args as Num.
IdentifierLoc * getArgAsIdent(unsigned Arg) const
Definition ParsedAttr.h:389
bool hasParsedType() const
Definition ParsedAttr.h:337
void setInvalid(bool b=true) const
Definition ParsedAttr.h:345
const ParsedType & getTypeArg() const
Definition ParsedAttr.h:459
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this attribute.
Definition ParsedAttr.h:371
bool isArgIdent(unsigned Arg) const
Definition ParsedAttr.h:385
Expr * getArgAsExpr(unsigned Arg) const
Definition ParsedAttr.h:383
AttributeCommonInfo::Kind getKind() const
Definition ParsedAttr.h:623
A (possibly-)qualified type.
Definition TypeBase.h:938
void addRestrict()
Add the restrict qualifier to this QualType.
Definition TypeBase.h:1188
QualType getNonLValueExprType(const ASTContext &Context) const
Determine the type of a (typically non-lvalue) expression with the specified result type.
Definition Type.cpp:3810
QualType getDesugaredType(const ASTContext &Context) const
Return the specified type with any "sugar" removed from the type.
Definition TypeBase.h:1312
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition TypeBase.h:1005
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Definition TypeBase.h:8428
LangAS getAddressSpace() const
Return the address space of this type.
Definition TypeBase.h:8554
QualType getNonReferenceType() const
If Type is a reference type (e.g., const int&), returns the type that the reference refers to ("const...
Definition TypeBase.h:8613
QualType getCanonicalType() const
Definition TypeBase.h:8480
QualType getUnqualifiedType() const
Retrieve the unqualified variant of the given type, removing as little sugar as possible.
Definition TypeBase.h:8522
bool hasAddressSpace() const
Check if this type has any address space qualifier.
Definition TypeBase.h:8549
Represents a struct/union/class.
Definition Decl.h:4460
field_range fields() const
Definition Decl.h:4663
RecordDecl * getDefinitionOrSelf() const
Definition Decl.h:4648
bool field_empty() const
Definition Decl.h:4671
bool hasBindingInfoForDecl(const VarDecl *VD) const
Definition SemaHLSL.cpp:236
DeclBindingInfo * getDeclBindingInfo(const VarDecl *VD, ResourceClass ResClass)
Definition SemaHLSL.cpp:222
DeclBindingInfo * addDeclBindingInfo(const VarDecl *VD, ResourceClass ResClass)
Definition SemaHLSL.cpp:209
Scope - A scope is a transient data structure that is used while parsing the program.
Definition Scope.h:41
SemaBase(Sema &S)
Definition SemaBase.cpp:7
ASTContext & getASTContext() const
Definition SemaBase.cpp:9
Sema & SemaRef
Definition SemaBase.h:40
SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID)
Emit a diagnostic.
Definition SemaBase.cpp:61
ExprResult ActOnOutParamExpr(ParmVarDecl *Param, Expr *Arg)
HLSLRootSignatureDecl * lookupRootSignatureOverrideDecl(DeclContext *DC) const
bool CanPerformElementwiseCast(Expr *Src, QualType DestType)
void handleWaveSizeAttr(Decl *D, const ParsedAttr &AL)
void handleVkLocationAttr(Decl *D, const ParsedAttr &AL)
HLSLAttributedResourceLocInfo TakeLocForHLSLAttribute(const HLSLAttributedResourceType *RT)
void handleSemanticAttr(Decl *D, const ParsedAttr &AL)
bool CanPerformScalarCast(QualType SrcTy, QualType DestTy)
QualType ProcessResourceTypeAttributes(QualType Wrapped)
void handleShaderAttr(Decl *D, const ParsedAttr &AL)
uint32_t getNextImplicitBindingOrderID()
Definition SemaHLSL.h:254
void CheckEntryPoint(FunctionDecl *FD)
Definition SemaHLSL.cpp:990
void handleVkExtBuiltinOutputAttr(Decl *D, const ParsedAttr &AL)
void emitLogicalOperatorFixIt(Expr *LHS, Expr *RHS, BinaryOperatorKind Opc)
void propagateContextualMatrixLayout(Expr *E, QualType DestType)
T * createSemanticAttr(const AttributeCommonInfo &ACI, std::optional< unsigned > Location)
Definition SemaHLSL.h:203
bool initGlobalResourceDecl(VarDecl *VD)
void ActOnEndOfTranslationUnit(TranslationUnitDecl *TU)
bool initGlobalResourceArrayDecl(VarDecl *VD)
HLSLVkConstantIdAttr * mergeVkConstantIdAttr(Decl *D, const AttributeCommonInfo &AL, int Id)
Definition SemaHLSL.cpp:751
HLSLNumThreadsAttr * mergeNumThreadsAttr(Decl *D, const AttributeCommonInfo &AL, int X, int Y, int Z)
Definition SemaHLSL.cpp:717
void deduceAddressSpace(VarDecl *Decl)
std::pair< IdentifierInfo *, bool > ActOnStartRootSignatureDecl(StringRef Signature)
Computes the unique Root Signature identifier from the given signature, then lookup if there is a pre...
void handlePackOffsetAttr(Decl *D, const ParsedAttr &AL)
Attr * buildMatrixLayoutTypeAttr(QualType T, const ParsedAttr &AL)
bool handleInitialization(VarDecl *VDecl, Expr *&Init)
void handleParamModifierAttr(Decl *D, const ParsedAttr &AL)
bool CheckResourceBinOp(BinaryOperatorKind Opc, Expr *LHSExpr, Expr *RHSExpr, SourceLocation Loc)
bool diagnoseIndexType(QualType T, const ParsedAttr &AL)
bool CanPerformAggregateSplatCast(Expr *Src, QualType DestType)
bool ActOnResourceMemberAccessExpr(MemberExpr *ME)
bool IsScalarizedLayoutCompatible(QualType T1, QualType T2) const
QualType ActOnTemplateShorthand(TemplateDecl *Template, SourceLocation NameLoc)
void handleRootSignatureAttr(Decl *D, const ParsedAttr &AL)
bool CheckCompatibleParameterABI(FunctionDecl *New, FunctionDecl *Old)
QualType handleVectorBinOpConversion(ExprResult &LHS, ExprResult &RHS, QualType LHSType, QualType RHSType, bool IsCompAssign)
QualType checkMatrixComponent(Sema &S, QualType baseType, ExprValueKind &VK, SourceLocation OpLoc, const IdentifierInfo *CompName, SourceLocation CompLoc)
bool IsConstantBufferElementCompatible(QualType T1)
void handleResourceBindingAttr(Decl *D, const ParsedAttr &AL)
bool IsTypedResourceElementCompatible(QualType T1)
bool transformInitList(const InitializedEntity &Entity, InitListExpr *Init)
void handleNumThreadsAttr(Decl *D, const ParsedAttr &AL)
bool ActOnUninitializedVarDecl(VarDecl *D)
void handleVkExtBuiltinInputAttr(Decl *D, const ParsedAttr &AL)
bool canHaveOverloadedBinOp(QualType Ty, BinaryOperatorKind Opc)
void ActOnTopLevelFunction(FunctionDecl *FD)
Definition SemaHLSL.cpp:820
bool handleResourceTypeAttr(QualType T, const ParsedAttr &AL)
void handleVkPushConstantAttr(Decl *D, const ParsedAttr &AL)
HLSLShaderAttr * mergeShaderAttr(Decl *D, const AttributeCommonInfo &AL, llvm::Triple::EnvironmentType ShaderType)
Definition SemaHLSL.cpp:787
NamedDecl * getConstantBufferConversionFunction(QualType Type, CXXRecordDecl *RD)
void ActOnFinishBuffer(Decl *Dcl, SourceLocation RBrace)
Definition SemaHLSL.cpp:690
void handleVkBindingAttr(Decl *D, const ParsedAttr &AL)
HLSLParamModifierAttr * mergeParamModifierAttr(Decl *D, const AttributeCommonInfo &AL, HLSLParamModifierAttr::Spelling Spelling)
Definition SemaHLSL.cpp:800
void diagnoseSystemSemanticAttr(Decl *D, const ParsedAttr &AL, llvm::dxbc::PSV::SemanticKind SemanticKind, std::optional< unsigned > Index)
QualType getInoutParameterType(QualType Ty)
bool diagnoseFloatType(QualType T, const ParsedAttr &AL)
SemaHLSL(Sema &S)
Definition SemaHLSL.cpp:240
void handleVkConstantIdAttr(Decl *D, const ParsedAttr &AL)
std::optional< ExprResult > tryPerformConstantBufferConversion(Expr *BaseExpr)
Decl * ActOnStartBuffer(Scope *BufferScope, bool CBuffer, SourceLocation KwLoc, IdentifierInfo *Ident, SourceLocation IdentLoc, SourceLocation LBrace)
Definition SemaHLSL.cpp:242
bool diagnoseMatrixLayoutInstantiation(attr::Kind K, QualType T, SourceLocation Loc)
HLSLWaveSizeAttr * mergeWaveSizeAttr(Decl *D, const AttributeCommonInfo &AL, int Min, int Max, int Preferred, int SpelledArgsCount)
Definition SemaHLSL.cpp:731
bool handleRootSignatureElements(ArrayRef< hlsl::RootSignatureElement > Elements)
void ActOnFinishRootSignatureDecl(SourceLocation Loc, IdentifierInfo *DeclIdent, ArrayRef< hlsl::RootSignatureElement > Elements)
Creates the Root Signature decl of the parsed Root Signature elements onto the AST and push it onto c...
void ActOnVariableDeclarator(VarDecl *VD)
bool CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall)
Sema - This implements semantic analysis and AST building for C.
Definition Sema.h:863
@ LookupOrdinaryName
Ordinary name lookup, which finds ordinary names (functions, variables, typedefs, etc....
Definition Sema.h:9394
@ LookupMemberName
Member name lookup, which finds the names of class/struct/union members.
Definition Sema.h:9402
ExtVectorDeclsType ExtVectorDecls
ExtVectorDecls - This is a list all the extended vector types.
Definition Sema.h:4979
FunctionDecl * getCurFunctionDecl(bool AllowLambda=false) const
Returns a pointer to the innermost enclosing function, or nullptr if the current context is not insid...
Definition Sema.cpp:1768
ASTContext & Context
Definition Sema.h:1304
ASTContext & getASTContext() const
Definition Sema.h:935
ExprResult ImpCastExprToType(Expr *E, QualType Type, CastKind CK, ExprValueKind VK=VK_PRValue, const CXXCastPath *BasePath=nullptr, CheckedConversionKind CCK=CheckedConversionKind::Implicit)
ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast.
Definition Sema.cpp:777
const LangOptions & getLangOpts() const
Definition Sema.h:928
ExprResult TemporaryMaterializationConversion(Expr *E)
If E is a prvalue denoting an unmaterialized temporary, materialize it as an xvalue.
SemaHLSL & HLSL()
Definition Sema.h:1481
ExprResult BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow, SourceLocation OpLoc, const CXXScopeSpec &SS, FieldDecl *Field, DeclAccessPair FoundDecl, const DeclarationNameInfo &MemberNameInfo)
bool checkArgCountRange(CallExpr *Call, unsigned MinArgCount, unsigned MaxArgCount)
Checks that a call expression's argument count is in the desired range.
ExternalSemaSource * getExternalSource() const
Definition Sema.h:938
ASTConsumer & Consumer
Definition Sema.h:1305
bool checkArgCount(CallExpr *Call, unsigned DesiredArgCount)
Checks that a call expression's argument count is the desired number.
ExprResult CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, Expr *Idx, SourceLocation RLoc)
bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, bool InUnqualifiedLookup=false)
Perform qualified name lookup into a given context.
ExprResult PerformCopyInitialization(const InitializedEntity &Entity, SourceLocation EqualLoc, ExprResult Init, bool TopLevelOfInitList=false, bool AllowExplicit=false)
ExprResult CreateBuiltinMatrixSubscriptExpr(Expr *Base, Expr *RowIdx, Expr *ColumnIdx, SourceLocation RBLoc)
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
SourceLocation getLocWithOffset(IntTy Offset) const
Return a source location with the specified offset from this SourceLocation.
A trivial tuple used to represent a source range.
SourceLocation getEnd() const
SourceLocation getEndLoc() const LLVM_READONLY
Definition Stmt.cpp:367
void printPretty(raw_ostream &OS, PrinterHelper *Helper, const PrintingPolicy &Policy, unsigned Indentation=0, StringRef NewlineSymbol="\n", const ASTContext *Context=nullptr) const
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition Stmt.cpp:343
SourceLocation getBeginLoc() const LLVM_READONLY
Definition Stmt.cpp:355
StringLiteral - This represents a string literal expression, e.g.
Definition Expr.h:1819
static StringLiteral * Create(const ASTContext &Ctx, StringRef Str, StringLiteralKind Kind, bool Pascal, QualType Ty, ArrayRef< SourceLocation > Locs)
This is the "fully general" constructor that allows representation of strings formed from one or more...
Definition Expr.cpp:1194
void startDefinition()
Starts the definition of this tag declaration.
Definition Decl.cpp:4971
bool isUnion() const
Definition Decl.h:4063
bool isClass() const
Definition Decl.h:4062
Exposes information about the current target.
Definition TargetInfo.h:226
TargetOptions & getTargetOpts() const
Retrieve the target options.
Definition TargetInfo.h:332
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
StringRef getPlatformName() const
Retrieve the name of the platform as it is used in the availability attribute.
VersionTuple getPlatformMinVersion() const
Retrieve the minimum desired version of the platform, to which the program should be compiled.
std::string HLSLEntry
The entry point name for HLSL shader being compiled as specified by -E.
A convenient class for passing around template argument information.
void addArgument(const TemplateArgumentLoc &Loc)
The base class of all kinds of template declarations (e.g., class, function, etc.).
Stores a list of template parameters for a TemplateDecl and its derived classes.
The top declaration context.
Definition Decl.h:106
SourceLocation getBeginLoc() const
Get the begin source location.
Definition TypeLoc.cpp:193
A container of type source information.
Definition TypeBase.h:8399
TypeLoc getTypeLoc() const
Return the TypeLoc wrapper for the type source info.
Definition TypeLoc.h:267
The base class of the type hierarchy.
Definition TypeBase.h:1879
bool isVoidType() const
Definition TypeBase.h:9037
bool isBooleanType() const
Definition TypeBase.h:9174
bool isIncompleteArrayType() const
Definition TypeBase.h:8772
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition Type.h:26
bool isConstantArrayType() const
Definition TypeBase.h:8768
bool hasIntegerRepresentation() const
Determine whether this type has an integer representation of some sort, e.g., it is an integer type o...
Definition Type.cpp:2241
bool isArrayType() const
Definition TypeBase.h:8764
CXXRecordDecl * castAsCXXRecordDecl() const
Definition Type.h:36
bool isArithmeticType() const
Definition Type.cpp:2546
bool isConstantMatrixType() const
Definition TypeBase.h:8832
bool isHLSLBuiltinIntangibleType() const
Definition TypeBase.h:8982
bool isPointerType() const
Definition TypeBase.h:8665
CanQualType getCanonicalTypeUnqualified() const
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
Definition TypeBase.h:9081
const T * castAs() const
Member-template castAs<specific type>.
Definition TypeBase.h:9331
bool isReferenceType() const
Definition TypeBase.h:8689
bool isHLSLIntangibleType() const
Definition Type.cpp:5708
bool isEnumeralType() const
Definition TypeBase.h:8796
bool isScalarType() const
Definition TypeBase.h:9143
bool isIntegralType(const ASTContext &Ctx) const
Determine whether this type is an integral type.
Definition Type.cpp:2278
const Type * getArrayElementTypeNoTypeQual() const
If this is an array type, return the element type of the array, potentially with type qualifiers miss...
Definition Type.cpp:591
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:881
bool hasUnsignedIntegerRepresentation() const
Determine whether this type has an unsigned integer representation of some sort, e....
Definition Type.cpp:2500
bool isSpecificBuiltinType(unsigned K) const
Test for a particular builtin type.
Definition TypeBase.h:9006
bool isDependentType() const
Whether this type is a dependent type, meaning that its definition somehow depends on a template para...
Definition TypeBase.h:2859
bool isAggregateType() const
Determines whether the type is a C++ aggregate type or C aggregate or union type.
Definition Type.cpp:2627
ScalarTypeKind getScalarTypeKind() const
Given that this is a scalar type, classify it.
Definition Type.cpp:2578
bool hasSignedIntegerRepresentation() const
Determine whether this type has an signed integer representation of some sort, e.g....
Definition Type.cpp:2432
bool isMatrixType() const
Definition TypeBase.h:8828
bool isHLSLResourceRecord() const
Definition Type.cpp:5695
bool hasFloatingRepresentation() const
Determine whether this type has a floating-point representation of some sort, e.g....
Definition Type.cpp:2521
bool isVectorType() const
Definition TypeBase.h:8804
bool isRealFloatingType() const
Floating point categories.
Definition Type.cpp:2529
bool isHLSLAttributedResourceType() const
Definition TypeBase.h:8994
@ STK_FloatingComplex
Definition TypeBase.h:2841
@ STK_ObjCObjectPointer
Definition TypeBase.h:2835
@ STK_IntegralComplex
Definition TypeBase.h:2840
@ STK_MemberPointer
Definition TypeBase.h:2836
bool isFloatingType() const
Definition Type.cpp:2513
bool isSamplerT() const
Definition TypeBase.h:8909
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9264
const Type * getUnqualifiedDesugaredType() const
Return the specified type with any "sugar" removed from the type, removing any typedefs,...
Definition Type.cpp:782
bool isRecordType() const
Definition TypeBase.h:8792
bool isHLSLResourceRecordArray() const
Definition Type.cpp:5699
void setType(QualType newType)
Definition Decl.h:725
QualType getType() const
Definition Decl.h:724
Represents a variable declaration or definition.
Definition Decl.h:933
static VarDecl * Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, const IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, StorageClass S)
Definition Decl.cpp:2131
void setInitStyle(InitializationStyle Style)
Definition Decl.h:1477
@ CallInit
Call-style initialization (C++98)
Definition Decl.h:941
void setStorageClass(StorageClass SC)
Definition Decl.cpp:2143
bool hasGlobalStorage() const
Returns true for all variables that do not have local storage.
Definition Decl.h:1248
void setInit(Expr *I)
Definition Decl.cpp:2457
StorageClass getStorageClass() const
Returns the storage class as written in the source.
Definition Decl.h:1175
Represents a GCC generic vector type.
Definition TypeBase.h:4266
unsigned getNumElements() const
Definition TypeBase.h:4281
QualType getElementType() const
Definition TypeBase.h:4280
IdentifierInfo * getNameAsIdentifier(ASTContext &AST) const
Defines the clang::TargetInfo interface.
Definition SPIR.cpp:47
uint32_t getResourceDimensions(llvm::dxil::ResourceDimension Dim)
bool hasResourceOffset(llvm::dxil::ResourceDimension Dim)
bool hasCounterHandle(const CXXRecordDecl *RD)
SetTy< T > join(SetTy< T > A, SetTy< T > B, typename SetTy< T >::Factory &F)
Computes the union of two ImmutableSets.
Definition Utils.h:49
Top level wrappers for InstallAPI frontend operations.
bool isa(CodeGen::Address addr)
Definition Address.h:330
if(T->getSizeExpr()) TRY_TO(TraverseStmt(const_cast< Expr * >(T -> getSizeExpr())))
static bool CheckFloatOrHalfRepresentation(Sema *S, SourceLocation Loc, int ArgOrdinal, clang::QualType PassedType)
Definition SemaSPIRV.cpp:66
@ ICIS_NoInit
No in-class initializer.
Definition Specifiers.h:273
@ TemplateName
The identifier is a template name. FIXME: Add an annotation for that.
Definition Parser.h:61
@ OK_Ordinary
An ordinary object is located at an address in memory.
Definition Specifiers.h:152
static bool CheckAllArgTypesAreCorrect(Sema *S, CallExpr *TheCall, llvm::ArrayRef< llvm::function_ref< bool(Sema *, SourceLocation, int, QualType)> > Checks)
Definition SemaSPIRV.cpp:49
@ AS_public
Definition Specifiers.h:125
@ AS_none
Definition Specifiers.h:128
@ SC_Extern
Definition Specifiers.h:252
@ SC_Static
Definition Specifiers.h:253
@ SC_None
Definition Specifiers.h:251
@ AANT_ArgumentIdentifier
@ Result
The result type of a method or function.
Definition TypeBase.h:906
@ Ordinary
This parameter uses ordinary ABI rules for its type.
Definition Specifiers.h:381
const FunctionProtoType * T
llvm::Expected< QualType > ExpectedType
@ Template
We are parsing a template declaration.
Definition Parser.h:81
LLVM_READONLY bool isDigit(unsigned char c)
Return true if this character is an ASCII digit: [0-9].
Definition CharInfo.h:114
static bool CheckAllArgsHaveSameType(Sema *S, CallExpr *TheCall)
Definition SemaSPIRV.cpp:32
ExprResult ExprError()
Definition Ownership.h:265
@ Type
The name was classified as a type.
Definition Sema.h:558
LangAS
Defines the address space values used by the address space qualifier of QualType.
CastKind
CastKind - The kind of operation required for a conversion.
ExprValueKind
The categorization of expression values, currently following the C++11 scheme.
Definition Specifiers.h:133
@ VK_PRValue
A pr-value expression (in the C++11 taxonomy) produces a temporary value.
Definition Specifiers.h:136
@ VK_LValue
An l-value expression is a reference to an object with independent storage.
Definition Specifiers.h:140
bool CreateHLSLAttributedResourceType(Sema &S, QualType Wrapped, ArrayRef< const Attr * > AttrList, QualType &ResType, HLSLAttributedResourceLocInfo *LocInfo=nullptr, Expr *SampleCountExpr=nullptr)
DynamicRecursiveASTVisitorBase< false > DynamicRecursiveASTVisitor
U cast(CodeGen::Address addr)
Definition Address.h:327
@ None
No keyword precedes the qualified type name.
Definition TypeBase.h:6017
ActionResult< Expr * > ExprResult
Definition Ownership.h:249
Visibility
Describes the different kinds of visibility that a declaration may have.
Definition Visibility.h:34
unsigned long uint64_t
hash_code hash_value(const clang::dependencies::ModuleID &ID)
__DEVICE__ bool isnan(float __x)
__DEVICE__ _Tp abs(const std::complex< _Tp > &__c)
int __ovld __cnfn any(char)
Returns 1 if the most significant bit in any component of x is set; otherwise returns 0.
__builtin_elementwise_add_sat __builtin_elementwise_sub_sat uint32_t __packed_splat4 __packed_splat2 __packed_splat8 __packed_splat4 __packed_splat2 __packed_splat4 __packed_splat2 __packed_splat8 __packed_splat4 uint32_t
#define false
Definition stdbool.h:26
Describes how types, statements, expressions, and declarations should be printed.
void setCounterImplicitOrderID(unsigned Value) const
void setImplicitOrderID(unsigned Value) const
const SourceLocation & getLocation() const
Definition SemaHLSL.h:50
const llvm::hlsl::rootsig::RootElement & getElement() const
Definition SemaHLSL.h:49