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