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