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