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