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