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