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