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::HLSLIsArray:
2156 if (ResAttrs.IsArray) {
2157 S.Diag(A->getLocation(), diag::warn_duplicate_attribute_exact) << A;
2158 return false;
2159 }
2160 ResAttrs.IsArray = true;
2161 break;
2162 case attr::HLSLIsCounter:
2163 if (ResAttrs.IsCounter) {
2164 S.Diag(A->getLocation(), diag::warn_duplicate_attribute_exact) << A;
2165 return false;
2166 }
2167 ResAttrs.IsCounter = true;
2168 break;
2169 case attr::HLSLContainedType: {
2170 const HLSLContainedTypeAttr *CTAttr = cast<HLSLContainedTypeAttr>(A);
2171 QualType Ty = CTAttr->getType();
2172 if (!ContainedTy.isNull()) {
2173 S.Diag(A->getLocation(), ContainedTy == Ty
2174 ? diag::warn_duplicate_attribute_exact
2175 : diag::warn_duplicate_attribute)
2176 << A;
2177 return false;
2178 }
2179 ContainedTy = Ty;
2180 ContainedTyInfo = CTAttr->getTypeLoc();
2181 break;
2182 }
2183 default:
2184 llvm_unreachable("unhandled resource attribute type");
2185 }
2186 }
2187
2188 if (!HasResourceClass) {
2189 S.Diag(AttrList.back()->getRange().getEnd(),
2190 diag::err_hlsl_missing_resource_class);
2191 return false;
2192 }
2193
2195 Wrapped, ContainedTy, ResAttrs);
2196
2197 if (LocInfo && ContainedTyInfo) {
2198 LocInfo->Range = SourceRange(LocBegin, LocEnd);
2199 LocInfo->ContainedTyInfo = ContainedTyInfo;
2200 }
2201 return true;
2202}
2203
2204// Validates and creates an HLSL attribute that is applied as type attribute on
2205// HLSL resource. The attributes are collected in HLSLResourcesTypeAttrs and at
2206// the end of the declaration they are applied to the declaration type by
2207// wrapping it in HLSLAttributedResourceType.
2209 // only allow resource type attributes on intangible types
2210 if (!T->isHLSLResourceType()) {
2211 Diag(AL.getLoc(), diag::err_hlsl_attribute_needs_intangible_type)
2212 << AL << getASTContext().HLSLResourceTy;
2213 return false;
2214 }
2215
2216 // validate number of arguments
2217 if (!AL.checkExactlyNumArgs(SemaRef, AL.getMinArgs()))
2218 return false;
2219
2220 Attr *A = nullptr;
2221
2225 {
2226 AttributeCommonInfo::AS_CXX11, 0, false /*IsAlignas*/,
2227 false /*IsRegularKeywordAttribute*/
2228 });
2229
2230 switch (AL.getKind()) {
2231 case ParsedAttr::AT_HLSLResourceClass: {
2232 if (!AL.isArgIdent(0)) {
2233 Diag(AL.getLoc(), diag::err_attribute_argument_type)
2234 << AL << AANT_ArgumentIdentifier;
2235 return false;
2236 }
2237
2238 IdentifierLoc *Loc = AL.getArgAsIdent(0);
2239 StringRef Identifier = Loc->getIdentifierInfo()->getName();
2240 SourceLocation ArgLoc = Loc->getLoc();
2241
2242 // Validate resource class value
2243 ResourceClass RC;
2244 if (!HLSLResourceClassAttr::ConvertStrToResourceClass(Identifier, RC)) {
2245 Diag(ArgLoc, diag::warn_attribute_type_not_supported)
2246 << "ResourceClass" << Identifier;
2247 return false;
2248 }
2249 A = HLSLResourceClassAttr::Create(getASTContext(), RC, ACI);
2250 break;
2251 }
2252
2253 case ParsedAttr::AT_HLSLResourceDimension: {
2254 StringRef Identifier;
2255 SourceLocation ArgLoc;
2256 if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Identifier, &ArgLoc))
2257 return false;
2258
2259 // Validate resource dimension value
2260 llvm::dxil::ResourceDimension RD;
2261 if (!HLSLResourceDimensionAttr::ConvertStrToResourceDimension(Identifier,
2262 RD)) {
2263 Diag(ArgLoc, diag::warn_attribute_type_not_supported)
2264 << "ResourceDimension" << Identifier;
2265 return false;
2266 }
2267 A = HLSLResourceDimensionAttr::Create(getASTContext(), RD, ACI);
2268 break;
2269 }
2270
2271 case ParsedAttr::AT_HLSLROV:
2272 A = HLSLROVAttr::Create(getASTContext(), ACI);
2273 break;
2274
2275 case ParsedAttr::AT_HLSLRawBuffer:
2276 A = HLSLRawBufferAttr::Create(getASTContext(), ACI);
2277 break;
2278
2279 case ParsedAttr::AT_HLSLIsCounter:
2280 A = HLSLIsCounterAttr::Create(getASTContext(), ACI);
2281 break;
2282
2283 case ParsedAttr::AT_HLSLIsArray:
2284 A = HLSLIsArrayAttr::Create(getASTContext(), ACI);
2285 break;
2286
2287 case ParsedAttr::AT_HLSLContainedType: {
2288 if (AL.getNumArgs() != 1 && !AL.hasParsedType()) {
2289 Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1;
2290 return false;
2291 }
2292
2293 TypeSourceInfo *TSI = nullptr;
2294 QualType QT = SemaRef.GetTypeFromParser(AL.getTypeArg(), &TSI);
2295 assert(TSI && "no type source info for attribute argument");
2296 if (SemaRef.RequireCompleteType(TSI->getTypeLoc().getBeginLoc(), QT,
2297 diag::err_incomplete_type))
2298 return false;
2299 A = HLSLContainedTypeAttr::Create(getASTContext(), TSI, ACI);
2300 break;
2301 }
2302
2303 default:
2304 llvm_unreachable("unhandled HLSL attribute");
2305 }
2306
2307 HLSLResourcesTypeAttrs.emplace_back(A);
2308 return true;
2309}
2310
2311// Combines all resource type attributes and creates HLSLAttributedResourceType.
2313 if (!HLSLResourcesTypeAttrs.size())
2314 return CurrentType;
2315
2316 QualType QT = CurrentType;
2319 HLSLResourcesTypeAttrs, QT, &LocInfo)) {
2320 const HLSLAttributedResourceType *RT =
2322
2323 // Temporarily store TypeLoc information for the new type.
2324 // It will be transferred to HLSLAttributesResourceTypeLoc
2325 // shortly after the type is created by TypeSpecLocFiller which
2326 // will call the TakeLocForHLSLAttribute method below.
2327 LocsForHLSLAttributedResources.insert(std::pair(RT, LocInfo));
2328 }
2329 HLSLResourcesTypeAttrs.clear();
2330 return QT;
2331}
2332
2333// Returns source location for the HLSLAttributedResourceType
2335SemaHLSL::TakeLocForHLSLAttribute(const HLSLAttributedResourceType *RT) {
2336 HLSLAttributedResourceLocInfo LocInfo = {};
2337 auto I = LocsForHLSLAttributedResources.find(RT);
2338 if (I != LocsForHLSLAttributedResources.end()) {
2339 LocInfo = I->second;
2340 LocsForHLSLAttributedResources.erase(I);
2341 return LocInfo;
2342 }
2343 LocInfo.Range = SourceRange();
2344 return LocInfo;
2345}
2346
2347// Walks though the global variable declaration, collects all resource binding
2348// requirements and adds them to Bindings
2349void SemaHLSL::collectResourceBindingsOnUserRecordDecl(const VarDecl *VD,
2350 const RecordType *RT) {
2351 const RecordDecl *RD = RT->getDecl()->getDefinitionOrSelf();
2352 for (FieldDecl *FD : RD->fields()) {
2353 const Type *Ty = FD->getType()->getUnqualifiedDesugaredType();
2354
2355 // Unwrap arrays
2356 // FIXME: Calculate array size while unwrapping
2357 assert(!Ty->isIncompleteArrayType() &&
2358 "incomplete arrays inside user defined types are not supported");
2359 while (Ty->isConstantArrayType()) {
2362 }
2363
2364 if (!Ty->isRecordType())
2365 continue;
2366
2367 if (const HLSLAttributedResourceType *AttrResType =
2368 HLSLAttributedResourceType::findHandleTypeOnResource(Ty)) {
2369 // Add a new DeclBindingInfo to Bindings if it does not already exist
2370 ResourceClass RC = AttrResType->getAttrs().ResourceClass;
2371 DeclBindingInfo *DBI = Bindings.getDeclBindingInfo(VD, RC);
2372 if (!DBI)
2373 Bindings.addDeclBindingInfo(VD, RC);
2374 } else if (const RecordType *RT = dyn_cast<RecordType>(Ty)) {
2375 // Recursively scan embedded struct or class; it would be nice to do this
2376 // without recursion, but tricky to correctly calculate the size of the
2377 // binding, which is something we are probably going to need to do later
2378 // on. Hopefully nesting of structs in structs too many levels is
2379 // unlikely.
2380 collectResourceBindingsOnUserRecordDecl(VD, RT);
2381 }
2382 }
2383}
2384
2385// Diagnose localized register binding errors for a single binding; does not
2386// diagnose resource binding on user record types, that will be done later
2387// in processResourceBindingOnDecl based on the information collected in
2388// collectResourceBindingsOnVarDecl.
2389// Returns false if the register binding is not valid.
2391 Decl *D, RegisterType RegType,
2392 bool SpecifiedSpace) {
2393 int RegTypeNum = static_cast<int>(RegType);
2394
2395 // check if the decl type is groupshared
2396 if (D->hasAttr<HLSLGroupSharedAddressSpaceAttr>()) {
2397 S.Diag(ArgLoc, diag::err_hlsl_binding_type_mismatch) << RegTypeNum;
2398 return false;
2399 }
2400
2401 // Cbuffers and Tbuffers are HLSLBufferDecl types
2402 if (HLSLBufferDecl *CBufferOrTBuffer = dyn_cast<HLSLBufferDecl>(D)) {
2403 ResourceClass RC = CBufferOrTBuffer->isCBuffer() ? ResourceClass::CBuffer
2404 : ResourceClass::SRV;
2405 if (RegType == getRegisterType(RC))
2406 return true;
2407
2408 S.Diag(D->getLocation(), diag::err_hlsl_binding_type_mismatch)
2409 << RegTypeNum;
2410 return false;
2411 }
2412
2413 // Samplers, UAVs, and SRVs are VarDecl types
2414 assert(isa<VarDecl>(D) && "D is expected to be VarDecl or HLSLBufferDecl");
2415 VarDecl *VD = cast<VarDecl>(D);
2416
2417 // Resource
2418 if (const HLSLAttributedResourceType *AttrResType =
2419 HLSLAttributedResourceType::findHandleTypeOnResource(
2420 VD->getType().getTypePtr())) {
2421 if (RegType == getRegisterType(AttrResType))
2422 return true;
2423
2424 S.Diag(D->getLocation(), diag::err_hlsl_binding_type_mismatch)
2425 << RegTypeNum;
2426 return false;
2427 }
2428
2429 const clang::Type *Ty = VD->getType().getTypePtr();
2430 while (Ty->isArrayType())
2432
2433 // Basic types
2434 if (Ty->isArithmeticType() || Ty->isVectorType()) {
2435 bool DeclaredInCOrTBuffer = isa<HLSLBufferDecl>(D->getDeclContext());
2436 if (SpecifiedSpace && !DeclaredInCOrTBuffer)
2437 S.Diag(ArgLoc, diag::err_hlsl_space_on_global_constant);
2438
2439 if (!DeclaredInCOrTBuffer && (Ty->isIntegralType(S.getASTContext()) ||
2440 Ty->isFloatingType() || Ty->isVectorType())) {
2441 // Register annotation on default constant buffer declaration ($Globals)
2442 if (RegType == RegisterType::CBuffer)
2443 S.Diag(ArgLoc, diag::warn_hlsl_deprecated_register_type_b);
2444 else if (RegType != RegisterType::C)
2445 S.Diag(ArgLoc, diag::err_hlsl_binding_type_mismatch) << RegTypeNum;
2446 else
2447 return true;
2448 } else {
2449 if (RegType == RegisterType::C)
2450 S.Diag(ArgLoc, diag::warn_hlsl_register_type_c_packoffset);
2451 else
2452 S.Diag(ArgLoc, diag::err_hlsl_binding_type_mismatch) << RegTypeNum;
2453 }
2454 return false;
2455 }
2456 if (Ty->isRecordType())
2457 // RecordTypes will be diagnosed in processResourceBindingOnDecl
2458 // that is called from ActOnVariableDeclarator
2459 return true;
2460
2461 // Anything else is an error
2462 S.Diag(ArgLoc, diag::err_hlsl_binding_type_mismatch) << RegTypeNum;
2463 return false;
2464}
2465
2467 RegisterType regType) {
2468 // make sure that there are no two register annotations
2469 // applied to the decl with the same register type
2470 bool RegisterTypesDetected[5] = {false};
2471 RegisterTypesDetected[static_cast<int>(regType)] = true;
2472
2473 for (auto it = TheDecl->attr_begin(); it != TheDecl->attr_end(); ++it) {
2474 if (HLSLResourceBindingAttr *attr =
2475 dyn_cast<HLSLResourceBindingAttr>(*it)) {
2476
2477 RegisterType otherRegType = attr->getRegisterType();
2478 if (RegisterTypesDetected[static_cast<int>(otherRegType)]) {
2479 int otherRegTypeNum = static_cast<int>(otherRegType);
2480 S.Diag(TheDecl->getLocation(),
2481 diag::err_hlsl_duplicate_register_annotation)
2482 << otherRegTypeNum;
2483 return false;
2484 }
2485 RegisterTypesDetected[static_cast<int>(otherRegType)] = true;
2486 }
2487 }
2488 return true;
2489}
2490
2492 Decl *D, RegisterType RegType,
2493 bool SpecifiedSpace) {
2494
2495 // exactly one of these two types should be set
2496 assert(((isa<VarDecl>(D) && !isa<HLSLBufferDecl>(D)) ||
2497 (!isa<VarDecl>(D) && isa<HLSLBufferDecl>(D))) &&
2498 "expecting VarDecl or HLSLBufferDecl");
2499
2500 // check if the declaration contains resource matching the register type
2501 if (!DiagnoseLocalRegisterBinding(S, ArgLoc, D, RegType, SpecifiedSpace))
2502 return false;
2503
2504 // next, if multiple register annotations exist, check that none conflict.
2505 return ValidateMultipleRegisterAnnotations(S, D, RegType);
2506}
2507
2508// return false if the slot count exceeds the limit, true otherwise
2509static bool AccumulateHLSLResourceSlots(QualType Ty, uint64_t &StartSlot,
2510 const uint64_t &Limit,
2511 const ResourceClass ResClass,
2512 ASTContext &Ctx,
2513 uint64_t ArrayCount = 1) {
2514 Ty = Ty.getCanonicalType();
2515 const Type *T = Ty.getTypePtr();
2516
2517 // Early exit if already overflowed
2518 if (StartSlot > Limit)
2519 return false;
2520
2521 // Case 1: array type
2522 if (const auto *AT = dyn_cast<ArrayType>(T)) {
2523 uint64_t Count = 1;
2524
2525 if (const auto *CAT = dyn_cast<ConstantArrayType>(AT))
2526 Count = CAT->getSize().getZExtValue();
2527
2528 QualType ElemTy = AT->getElementType();
2529 return AccumulateHLSLResourceSlots(ElemTy, StartSlot, Limit, ResClass, Ctx,
2530 ArrayCount * Count);
2531 }
2532
2533 // Case 2: resource leaf
2534 if (auto ResTy = dyn_cast<HLSLAttributedResourceType>(T)) {
2535 // First ensure this resource counts towards the corresponding
2536 // register type limit.
2537 if (ResTy->getAttrs().ResourceClass != ResClass)
2538 return true;
2539
2540 // Validate highest slot used
2541 uint64_t EndSlot = StartSlot + ArrayCount - 1;
2542 if (EndSlot > Limit)
2543 return false;
2544
2545 // Advance SlotCount past the consumed range
2546 StartSlot = EndSlot + 1;
2547 return true;
2548 }
2549
2550 // Case 3: struct / record
2551 if (const auto *RT = dyn_cast<RecordType>(T)) {
2552 const RecordDecl *RD = RT->getDecl();
2553
2554 if (const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
2555 for (const CXXBaseSpecifier &Base : CXXRD->bases()) {
2556 if (!AccumulateHLSLResourceSlots(Base.getType(), StartSlot, Limit,
2557 ResClass, Ctx, ArrayCount))
2558 return false;
2559 }
2560 }
2561
2562 for (const FieldDecl *Field : RD->fields()) {
2563 if (!AccumulateHLSLResourceSlots(Field->getType(), StartSlot, Limit,
2564 ResClass, Ctx, ArrayCount))
2565 return false;
2566 }
2567
2568 return true;
2569 }
2570
2571 // Case 4: everything else
2572 return true;
2573}
2574
2575// return true if there is something invalid, false otherwise
2576static bool ValidateRegisterNumber(uint64_t SlotNum, Decl *TheDecl,
2577 ASTContext &Ctx, RegisterType RegTy) {
2578 const uint64_t Limit = UINT32_MAX;
2579 if (SlotNum > Limit)
2580 return true;
2581
2582 // after verifying the number doesn't exceed uint32max, we don't need
2583 // to look further into c or i register types
2584 if (RegTy == RegisterType::C || RegTy == RegisterType::I)
2585 return false;
2586
2587 if (VarDecl *VD = dyn_cast<VarDecl>(TheDecl)) {
2588 uint64_t BaseSlot = SlotNum;
2589
2590 if (!AccumulateHLSLResourceSlots(VD->getType(), SlotNum, Limit,
2591 getResourceClass(RegTy), Ctx))
2592 return true;
2593
2594 // After AccumulateHLSLResourceSlots runs, SlotNum is now
2595 // the first free slot; last used was SlotNum - 1
2596 return (BaseSlot > Limit);
2597 }
2598 // handle the cbuffer/tbuffer case
2599 if (isa<HLSLBufferDecl>(TheDecl))
2600 // resources cannot be put within a cbuffer, so no need
2601 // to analyze the structure since the register number
2602 // won't be pushed any higher.
2603 return (SlotNum > Limit);
2604
2605 // we don't expect any other decl type, so fail
2606 llvm_unreachable("unexpected decl type");
2607}
2608
2610 if (VarDecl *VD = dyn_cast<VarDecl>(TheDecl)) {
2611 QualType Ty = VD->getType();
2612 if (const auto *IAT = dyn_cast<IncompleteArrayType>(Ty))
2613 Ty = IAT->getElementType();
2614 if (SemaRef.RequireCompleteType(TheDecl->getBeginLoc(), Ty,
2615 diag::err_incomplete_type))
2616 return;
2617 }
2618
2619 StringRef Slot = "";
2620 StringRef Space = "";
2621 SourceLocation SlotLoc, SpaceLoc;
2622
2623 if (!AL.isArgIdent(0)) {
2624 Diag(AL.getLoc(), diag::err_attribute_argument_type)
2625 << AL << AANT_ArgumentIdentifier;
2626 return;
2627 }
2628 IdentifierLoc *Loc = AL.getArgAsIdent(0);
2629
2630 if (AL.getNumArgs() == 2) {
2631 Slot = Loc->getIdentifierInfo()->getName();
2632 SlotLoc = Loc->getLoc();
2633 if (!AL.isArgIdent(1)) {
2634 Diag(AL.getLoc(), diag::err_attribute_argument_type)
2635 << AL << AANT_ArgumentIdentifier;
2636 return;
2637 }
2638 Loc = AL.getArgAsIdent(1);
2639 Space = Loc->getIdentifierInfo()->getName();
2640 SpaceLoc = Loc->getLoc();
2641 } else {
2642 StringRef Str = Loc->getIdentifierInfo()->getName();
2643 if (Str.starts_with("space")) {
2644 Space = Str;
2645 SpaceLoc = Loc->getLoc();
2646 } else {
2647 Slot = Str;
2648 SlotLoc = Loc->getLoc();
2649 Space = "space0";
2650 }
2651 }
2652
2653 RegisterType RegType = RegisterType::SRV;
2654 std::optional<unsigned> SlotNum;
2655 unsigned SpaceNum = 0;
2656
2657 // Validate slot
2658 if (!Slot.empty()) {
2659 if (!convertToRegisterType(Slot, &RegType)) {
2660 Diag(SlotLoc, diag::err_hlsl_binding_type_invalid) << Slot.substr(0, 1);
2661 return;
2662 }
2663 if (RegType == RegisterType::I) {
2664 Diag(SlotLoc, diag::warn_hlsl_deprecated_register_type_i);
2665 return;
2666 }
2667 const StringRef SlotNumStr = Slot.substr(1);
2668
2669 uint64_t N;
2670
2671 // validate that the slot number is a non-empty number
2672 if (SlotNumStr.getAsInteger(10, N)) {
2673 Diag(SlotLoc, diag::err_hlsl_unsupported_register_number);
2674 return;
2675 }
2676
2677 // Validate register number. It should not exceed UINT32_MAX,
2678 // including if the resource type is an array that starts
2679 // before UINT32_MAX, but ends afterwards.
2680 if (ValidateRegisterNumber(N, TheDecl, getASTContext(), RegType)) {
2681 Diag(SlotLoc, diag::err_hlsl_register_number_too_large);
2682 return;
2683 }
2684
2685 // the slot number has been validated and does not exceed UINT32_MAX
2686 SlotNum = (unsigned)N;
2687 }
2688
2689 // Validate space
2690 if (!Space.starts_with("space")) {
2691 Diag(SpaceLoc, diag::err_hlsl_expected_space) << Space;
2692 return;
2693 }
2694 StringRef SpaceNumStr = Space.substr(5);
2695 if (SpaceNumStr.getAsInteger(10, SpaceNum)) {
2696 Diag(SpaceLoc, diag::err_hlsl_expected_space) << Space;
2697 return;
2698 }
2699
2700 // If we have slot, diagnose it is the right register type for the decl
2701 if (SlotNum.has_value())
2702 if (!DiagnoseHLSLRegisterAttribute(SemaRef, SlotLoc, TheDecl, RegType,
2703 !SpaceLoc.isInvalid()))
2704 return;
2705
2706 HLSLResourceBindingAttr *NewAttr =
2707 HLSLResourceBindingAttr::Create(getASTContext(), Slot, Space, AL);
2708 if (NewAttr) {
2709 NewAttr->setBinding(RegType, SlotNum, SpaceNum);
2710 TheDecl->addAttr(NewAttr);
2711 }
2712}
2713
2715 HLSLParamModifierAttr *NewAttr = mergeParamModifierAttr(
2716 D, AL,
2717 static_cast<HLSLParamModifierAttr::Spelling>(AL.getSemanticSpelling()));
2718 if (NewAttr)
2719 D->addAttr(NewAttr);
2720}
2721
2722static bool isMatrixOrArrayOfMatrix(const ASTContext &Ctx, QualType QT) {
2723 const Type *Ty = QT->getUnqualifiedDesugaredType();
2724 while (isa<ArrayType>(Ty))
2726 return Ty->isDependentType() || Ty->isConstantMatrixType();
2727}
2728
2729/// Walks the existing AttributedType sugar of \p T looking for a previously
2730/// applied HLSLRowMajor/HLSLColumnMajor marker. If one is found, populates
2731/// \p ExistingKind with its attr::Kind and returns true.
2733 attr::Kind &ExistingKind) {
2734 QualType Cur = T;
2735 while (const auto *AT = Cur->getAs<AttributedType>()) {
2736 attr::Kind K = AT->getAttrKind();
2737 if (K == attr::HLSLRowMajor || K == attr::HLSLColumnMajor) {
2738 ExistingKind = K;
2739 return true;
2740 }
2741 Cur = AT->getModifiedType();
2742 }
2743 return false;
2744}
2745
2747 if (T.isNull())
2748 return nullptr;
2749
2750 ASTContext &Ctx = getASTContext();
2751 attr::Kind AttrK = AL.getKind() == ParsedAttr::AT_HLSLRowMajor
2752 ? attr::HLSLRowMajor
2753 : attr::HLSLColumnMajor;
2754
2755 // For non-dependent types, the operand must be a matrix (or array of
2756 // matrices).
2757 if (!T->isDependentType() && !isMatrixOrArrayOfMatrix(Ctx, T)) {
2758 Diag(AL.getLoc(), diag::err_hlsl_matrix_layout_non_matrix)
2759 << AL.getAttrName();
2760 AL.setInvalid();
2761 return nullptr;
2762 }
2763
2764 // Conflict / duplicate detection by walking existing sugar.
2765 attr::Kind ExistingKind;
2766 if (findExistingMatrixLayoutMarker(T, ExistingKind)) {
2767 if (ExistingKind == AttrK) {
2768 Diag(AL.getLoc(), diag::warn_duplicate_attribute_exact)
2769 << AL.getAttrName();
2770 Diag(AL.getLoc(), diag::note_previous_attribute);
2771 return nullptr;
2772 }
2773 IdentifierInfo *ExistingII = &Ctx.Idents.get(
2774 ExistingKind == attr::HLSLRowMajor ? "row_major" : "column_major");
2775 Diag(AL.getLoc(), diag::err_hlsl_matrix_layout_conflict)
2776 << AL.getAttrName() << ExistingII;
2777 Diag(AL.getLoc(), diag::note_conflicting_attribute);
2778 AL.setInvalid();
2779 return nullptr;
2780 }
2781
2782 if (AttrK == attr::HLSLRowMajor)
2783 return ::new (Ctx) HLSLRowMajorAttr(Ctx, AL);
2784 return ::new (Ctx) HLSLColumnMajorAttr(Ctx, AL);
2785}
2786
2787// Re-validates an HLSL `row_major` / `column_major` attribute after template
2788// substitution. The parse-time check in `buildMatrixLayoutTypeAttr` is skipped
2789// for dependent types; `TransformAttributedType` calls this once the type is
2790// concrete. Returns `true` (and emits a diagnostic) if the substituted type is
2791// not a matrix or array of matrices, signaling the caller to abort the
2792// transform.
2794 SourceLocation Loc) {
2795 if (K != attr::HLSLRowMajor && K != attr::HLSLColumnMajor)
2796 return false;
2797 if (T.isNull() || T->isDependentType())
2798 return false;
2800 return false;
2802 K == attr::HLSLRowMajor ? "row_major" : "column_major");
2803 Diag(Loc, diag::err_hlsl_matrix_layout_non_matrix) << II;
2804 return true;
2805}
2806
2807// Transpose and matrix mul need to read the destination layout.
2808// Elementwise builtins reuse the operand layout instead.
2809static bool isLayoutAdaptingMatrixBuiltin(unsigned BuiltinID) {
2810 switch (BuiltinID) {
2811 case Builtin::BI__builtin_hlsl_mul:
2812 case Builtin::BI__builtin_hlsl_transpose:
2813 return true;
2814 default:
2815 return false;
2816 }
2817}
2818
2820 if (!E || DestType.isNull())
2821 return;
2822 const auto *DestMat = DestType->getAs<ConstantMatrixType>();
2823 if (!DestMat)
2824 return;
2825 auto *Call = dyn_cast<CallExpr>(E->IgnoreParenImpCasts());
2826 if (!Call)
2827 return;
2828 const FunctionDecl *Callee = Call->getDirectCallee();
2829 if (!Callee || !isLayoutAdaptingMatrixBuiltin(Callee->getBuiltinID()))
2830 return;
2831 const auto *CallMat = Call->getType()->getAs<ConstantMatrixType>();
2832 if (!CallMat || CallMat->getNumRows() != DestMat->getNumRows() ||
2833 CallMat->getNumColumns() != DestMat->getNumColumns())
2834 return;
2835 // Re-type the call with the destination sugar so CodeGen lowers into that
2836 // layout, not the TU default.
2837 Call->setType(DestType.getUnqualifiedType());
2838}
2839
2840namespace {
2841
2842/// This class implements HLSL availability diagnostics for default
2843/// and relaxed mode
2844///
2845/// The goal of this diagnostic is to emit an error or warning when an
2846/// unavailable API is found in code that is reachable from the shader
2847/// entry function or from an exported function (when compiling a shader
2848/// library).
2849///
2850/// This is done by traversing the AST of all shader entry point functions
2851/// and of all exported functions, and any functions that are referenced
2852/// from this AST. In other words, any functions that are reachable from
2853/// the entry points.
2854class DiagnoseHLSLAvailability : public DynamicRecursiveASTVisitor {
2855 Sema &SemaRef;
2856
2857 // Stack of functions to be scaned
2859
2860 // Tracks which environments functions have been scanned in.
2861 //
2862 // Maps FunctionDecl to an unsigned number that represents the set of shader
2863 // environments the function has been scanned for.
2864 // The llvm::Triple::EnvironmentType enum values for shader stages guaranteed
2865 // to be numbered from llvm::Triple::Pixel to llvm::Triple::Amplification
2866 // (verified by static_asserts in Triple.cpp), we can use it to index
2867 // individual bits in the set, as long as we shift the values to start with 0
2868 // by subtracting the value of llvm::Triple::Pixel first.
2869 //
2870 // The N'th bit in the set will be set if the function has been scanned
2871 // in shader environment whose llvm::Triple::EnvironmentType integer value
2872 // equals (llvm::Triple::Pixel + N).
2873 //
2874 // For example, if a function has been scanned in compute and pixel stage
2875 // environment, the value will be 0x21 (100001 binary) because:
2876 //
2877 // (int)(llvm::Triple::Pixel - llvm::Triple::Pixel) == 0
2878 // (int)(llvm::Triple::Compute - llvm::Triple::Pixel) == 5
2879 //
2880 // A FunctionDecl is mapped to 0 (or not included in the map) if it has not
2881 // been scanned in any environment.
2882 llvm::DenseMap<const FunctionDecl *, unsigned> ScannedDecls;
2883
2884 // Do not access these directly, use the get/set methods below to make
2885 // sure the values are in sync
2886 llvm::Triple::EnvironmentType CurrentShaderEnvironment;
2887 unsigned CurrentShaderStageBit;
2888
2889 // True if scanning a function that was already scanned in a different
2890 // shader stage context, and therefore we should not report issues that
2891 // depend only on shader model version because they would be duplicate.
2892 bool ReportOnlyShaderStageIssues;
2893
2894 // Helper methods for dealing with current stage context / environment
2895 void SetShaderStageContext(llvm::Triple::EnvironmentType ShaderType) {
2896 static_assert(sizeof(unsigned) >= 4);
2897 assert(HLSLShaderAttr::isValidShaderType(ShaderType));
2898 assert((unsigned)(ShaderType - llvm::Triple::Pixel) < 31 &&
2899 "ShaderType is too big for this bitmap"); // 31 is reserved for
2900 // "unknown"
2901
2902 unsigned bitmapIndex = ShaderType - llvm::Triple::Pixel;
2903 CurrentShaderEnvironment = ShaderType;
2904 CurrentShaderStageBit = (1 << bitmapIndex);
2905 }
2906
2907 void SetUnknownShaderStageContext() {
2908 CurrentShaderEnvironment = llvm::Triple::UnknownEnvironment;
2909 CurrentShaderStageBit = (1 << 31);
2910 }
2911
2912 llvm::Triple::EnvironmentType GetCurrentShaderEnvironment() const {
2913 return CurrentShaderEnvironment;
2914 }
2915
2916 bool InUnknownShaderStageContext() const {
2917 return CurrentShaderEnvironment == llvm::Triple::UnknownEnvironment;
2918 }
2919
2920 // Helper methods for dealing with shader stage bitmap
2921 void AddToScannedFunctions(const FunctionDecl *FD) {
2922 unsigned &ScannedStages = ScannedDecls[FD];
2923 ScannedStages |= CurrentShaderStageBit;
2924 }
2925
2926 unsigned GetScannedStages(const FunctionDecl *FD) { return ScannedDecls[FD]; }
2927
2928 bool WasAlreadyScannedInCurrentStage(const FunctionDecl *FD) {
2929 return WasAlreadyScannedInCurrentStage(GetScannedStages(FD));
2930 }
2931
2932 bool WasAlreadyScannedInCurrentStage(unsigned ScannerStages) {
2933 return ScannerStages & CurrentShaderStageBit;
2934 }
2935
2936 static bool NeverBeenScanned(unsigned ScannedStages) {
2937 return ScannedStages == 0;
2938 }
2939
2940 // Scanning methods
2941 void HandleFunctionOrMethodRef(FunctionDecl *FD, Expr *RefExpr);
2942 void CheckDeclAvailability(NamedDecl *D, const AvailabilityAttr *AA,
2943 SourceRange Range);
2944 const AvailabilityAttr *FindAvailabilityAttr(const Decl *D);
2945 bool HasMatchingEnvironmentOrNone(const AvailabilityAttr *AA);
2946
2947public:
2948 DiagnoseHLSLAvailability(Sema &SemaRef)
2949 : SemaRef(SemaRef),
2950 CurrentShaderEnvironment(llvm::Triple::UnknownEnvironment),
2951 CurrentShaderStageBit(0), ReportOnlyShaderStageIssues(false) {}
2952
2953 // AST traversal methods
2954 void RunOnTranslationUnit(const TranslationUnitDecl *TU);
2955 void RunOnFunction(const FunctionDecl *FD);
2956
2957 bool VisitDeclRefExpr(DeclRefExpr *DRE) override {
2958 FunctionDecl *FD = llvm::dyn_cast<FunctionDecl>(DRE->getDecl());
2959 if (FD)
2960 HandleFunctionOrMethodRef(FD, DRE);
2961 return true;
2962 }
2963
2964 bool VisitMemberExpr(MemberExpr *ME) override {
2965 FunctionDecl *FD = llvm::dyn_cast<FunctionDecl>(ME->getMemberDecl());
2966 if (FD)
2967 HandleFunctionOrMethodRef(FD, ME);
2968 return true;
2969 }
2970};
2971
2972void DiagnoseHLSLAvailability::HandleFunctionOrMethodRef(FunctionDecl *FD,
2973 Expr *RefExpr) {
2974 assert((isa<DeclRefExpr>(RefExpr) || isa<MemberExpr>(RefExpr)) &&
2975 "expected DeclRefExpr or MemberExpr");
2976
2977 // has a definition -> add to stack to be scanned
2978 const FunctionDecl *FDWithBody = nullptr;
2979 if (FD->hasBody(FDWithBody)) {
2980 if (!WasAlreadyScannedInCurrentStage(FDWithBody))
2981 DeclsToScan.push_back(FDWithBody);
2982 return;
2983 }
2984
2985 // no body -> diagnose availability
2986 const AvailabilityAttr *AA = FindAvailabilityAttr(FD);
2987 if (AA)
2988 CheckDeclAvailability(
2989 FD, AA, SourceRange(RefExpr->getBeginLoc(), RefExpr->getEndLoc()));
2990}
2991
2992void DiagnoseHLSLAvailability::RunOnTranslationUnit(
2993 const TranslationUnitDecl *TU) {
2994
2995 // Iterate over all shader entry functions and library exports, and for those
2996 // that have a body (definiton), run diag scan on each, setting appropriate
2997 // shader environment context based on whether it is a shader entry function
2998 // or an exported function. Exported functions can be in namespaces and in
2999 // export declarations so we need to scan those declaration contexts as well.
3001 DeclContextsToScan.push_back(TU);
3002
3003 while (!DeclContextsToScan.empty()) {
3004 const DeclContext *DC = DeclContextsToScan.pop_back_val();
3005 for (auto &D : DC->decls()) {
3006 // do not scan implicit declaration generated by the implementation
3007 if (D->isImplicit())
3008 continue;
3009
3010 // for namespace or export declaration add the context to the list to be
3011 // scanned later
3012 if (llvm::dyn_cast<NamespaceDecl>(D) || llvm::dyn_cast<ExportDecl>(D)) {
3013 DeclContextsToScan.push_back(llvm::dyn_cast<DeclContext>(D));
3014 continue;
3015 }
3016
3017 // skip over other decls or function decls without body
3018 const FunctionDecl *FD = llvm::dyn_cast<FunctionDecl>(D);
3019 if (!FD || !FD->isThisDeclarationADefinition())
3020 continue;
3021
3022 // shader entry point
3023 if (HLSLShaderAttr *ShaderAttr = FD->getAttr<HLSLShaderAttr>()) {
3024 SetShaderStageContext(ShaderAttr->getType());
3025 RunOnFunction(FD);
3026 continue;
3027 }
3028 // exported library function
3029 // FIXME: replace this loop with external linkage check once issue #92071
3030 // is resolved
3031 bool isExport = FD->isInExportDeclContext();
3032 if (!isExport) {
3033 for (const auto *Redecl : FD->redecls()) {
3034 if (Redecl->isInExportDeclContext()) {
3035 isExport = true;
3036 break;
3037 }
3038 }
3039 }
3040 if (isExport) {
3041 SetUnknownShaderStageContext();
3042 RunOnFunction(FD);
3043 continue;
3044 }
3045 }
3046 }
3047}
3048
3049void DiagnoseHLSLAvailability::RunOnFunction(const FunctionDecl *FD) {
3050 assert(DeclsToScan.empty() && "DeclsToScan should be empty");
3051 DeclsToScan.push_back(FD);
3052
3053 while (!DeclsToScan.empty()) {
3054 // Take one decl from the stack and check it by traversing its AST.
3055 // For any CallExpr found during the traversal add it's callee to the top of
3056 // the stack to be processed next. Functions already processed are stored in
3057 // ScannedDecls.
3058 const FunctionDecl *FD = DeclsToScan.pop_back_val();
3059
3060 // Decl was already scanned
3061 const unsigned ScannedStages = GetScannedStages(FD);
3062 if (WasAlreadyScannedInCurrentStage(ScannedStages))
3063 continue;
3064
3065 ReportOnlyShaderStageIssues = !NeverBeenScanned(ScannedStages);
3066
3067 AddToScannedFunctions(FD);
3068 TraverseStmt(FD->getBody());
3069 }
3070}
3071
3072bool DiagnoseHLSLAvailability::HasMatchingEnvironmentOrNone(
3073 const AvailabilityAttr *AA) {
3074 const IdentifierInfo *IIEnvironment = AA->getEnvironment();
3075 if (!IIEnvironment)
3076 return true;
3077
3078 llvm::Triple::EnvironmentType CurrentEnv = GetCurrentShaderEnvironment();
3079 if (CurrentEnv == llvm::Triple::UnknownEnvironment)
3080 return false;
3081
3082 llvm::Triple::EnvironmentType AttrEnv =
3083 AvailabilityAttr::getEnvironmentType(IIEnvironment->getName());
3084
3085 return CurrentEnv == AttrEnv;
3086}
3087
3088const AvailabilityAttr *
3089DiagnoseHLSLAvailability::FindAvailabilityAttr(const Decl *D) {
3090 AvailabilityAttr const *PartialMatch = nullptr;
3091 // Check each AvailabilityAttr to find the one for this platform.
3092 // For multiple attributes with the same platform try to find one for this
3093 // environment.
3094 for (const auto *A : D->attrs()) {
3095 if (const auto *Avail = dyn_cast<AvailabilityAttr>(A)) {
3096 const AvailabilityAttr *EffectiveAvail = Avail->getEffectiveAttr();
3097 StringRef AttrPlatform = EffectiveAvail->getPlatform()->getName();
3098 StringRef TargetPlatform =
3100
3101 // Match the platform name.
3102 if (AttrPlatform == TargetPlatform) {
3103 // Find the best matching attribute for this environment
3104 if (HasMatchingEnvironmentOrNone(EffectiveAvail))
3105 return Avail;
3106 PartialMatch = Avail;
3107 }
3108 }
3109 }
3110 return PartialMatch;
3111}
3112
3113// Check availability against target shader model version and current shader
3114// stage and emit diagnostic
3115void DiagnoseHLSLAvailability::CheckDeclAvailability(NamedDecl *D,
3116 const AvailabilityAttr *AA,
3117 SourceRange Range) {
3118
3119 const IdentifierInfo *IIEnv = AA->getEnvironment();
3120
3121 if (!IIEnv) {
3122 // The availability attribute does not have environment -> it depends only
3123 // on shader model version and not on specific the shader stage.
3124
3125 // Skip emitting the diagnostics if the diagnostic mode is set to
3126 // strict (-fhlsl-strict-availability) because all relevant diagnostics
3127 // were already emitted in the DiagnoseUnguardedAvailability scan
3128 // (SemaAvailability.cpp).
3129 if (SemaRef.getLangOpts().HLSLStrictAvailability)
3130 return;
3131
3132 // Do not report shader-stage-independent issues if scanning a function
3133 // that was already scanned in a different shader stage context (they would
3134 // be duplicate)
3135 if (ReportOnlyShaderStageIssues)
3136 return;
3137
3138 } else {
3139 // The availability attribute has environment -> we need to know
3140 // the current stage context to property diagnose it.
3141 if (InUnknownShaderStageContext())
3142 return;
3143 }
3144
3145 // Check introduced version and if environment matches
3146 bool EnvironmentMatches = HasMatchingEnvironmentOrNone(AA);
3147 VersionTuple Introduced = AA->getIntroduced();
3148 VersionTuple TargetVersion =
3150
3151 if (TargetVersion >= Introduced && EnvironmentMatches)
3152 return;
3153
3154 // Emit diagnostic message
3155 const TargetInfo &TI = SemaRef.getASTContext().getTargetInfo();
3156 llvm::StringRef PlatformName(
3157 AvailabilityAttr::getPrettyPlatformName(TI.getPlatformName()));
3158
3159 llvm::StringRef CurrentEnvStr =
3160 llvm::Triple::getEnvironmentTypeName(GetCurrentShaderEnvironment());
3161
3162 llvm::StringRef AttrEnvStr =
3163 AA->getEnvironment() ? AA->getEnvironment()->getName() : "";
3164 bool UseEnvironment = !AttrEnvStr.empty();
3165
3166 if (EnvironmentMatches) {
3167 SemaRef.Diag(Range.getBegin(), diag::warn_hlsl_availability)
3168 << Range << D << PlatformName << Introduced.getAsString()
3169 << UseEnvironment << CurrentEnvStr;
3170 } else {
3171 SemaRef.Diag(Range.getBegin(), diag::warn_hlsl_availability_unavailable)
3172 << Range << D;
3173 }
3174
3175 SemaRef.Diag(D->getLocation(), diag::note_partial_availability_specified_here)
3176 << D << PlatformName << Introduced.getAsString()
3177 << SemaRef.Context.getTargetInfo().getPlatformMinVersion().getAsString()
3178 << UseEnvironment << AttrEnvStr << CurrentEnvStr;
3179}
3180
3181} // namespace
3182
3184 // process default CBuffer - create buffer layout struct and invoke codegenCGH
3185 if (!DefaultCBufferDecls.empty()) {
3187 SemaRef.getASTContext(), SemaRef.getCurLexicalContext(),
3188 DefaultCBufferDecls);
3189 addImplicitBindingAttrToDecl(SemaRef, DefaultCBuffer, RegisterType::CBuffer,
3191 SemaRef.getCurLexicalContext()->addDecl(DefaultCBuffer);
3193
3194 // Set HasValidPackoffset if any of the decls has a register(c#) annotation;
3195 for (const Decl *VD : DefaultCBufferDecls) {
3196 const HLSLResourceBindingAttr *RBA =
3197 VD->getAttr<HLSLResourceBindingAttr>();
3198 if (RBA && RBA->hasRegisterSlot() &&
3199 RBA->getRegisterType() == HLSLResourceBindingAttr::RegisterType::C) {
3200 DefaultCBuffer->setHasValidPackoffset(true);
3201 break;
3202 }
3203 }
3204
3205 DeclGroupRef DG(DefaultCBuffer);
3206 SemaRef.Consumer.HandleTopLevelDecl(DG);
3207 }
3208 diagnoseAvailabilityViolations(TU);
3209}
3210
3211// For resource member access through a global struct array, verify that the
3212// array index selecting the struct element is a constant integer expression.
3213// Returns false if the member expression is invalid.
3215 assert((ME->getType()->isHLSLResourceRecord() ||
3217 "expected member expr to have resource record type or array of them");
3218
3219 // Walk the AST from MemberExpr to the VarDecl of the parent struct instance
3220 // and take note of any non-constant array indexing along the way. If the
3221 // VarDecl we find is a global variable, report error if there was any
3222 // non-constant array index in the resource member access along the way.
3223 const Expr *NonConstIndexExpr = nullptr;
3224 const Expr *E = ME->getBase();
3225 while (E) {
3226 if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
3227 if (!NonConstIndexExpr)
3228 return true;
3229
3230 const VarDecl *VD = cast<VarDecl>(DRE->getDecl());
3231 if (!VD->hasGlobalStorage())
3232 return true;
3233
3234 SemaRef.Diag(NonConstIndexExpr->getExprLoc(),
3235 diag::err_hlsl_resource_member_array_access_not_constant);
3236 return false;
3237 }
3238
3239 if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(E)) {
3240 const Expr *IdxExpr = ASE->getIdx();
3241 if (!IdxExpr->isIntegerConstantExpr(SemaRef.getASTContext()))
3242 NonConstIndexExpr = IdxExpr;
3243 E = ASE->getBase();
3244 } else if (const auto *SubME = dyn_cast<MemberExpr>(E)) {
3245 E = SubME->getBase();
3246 } else if (const auto *ICE = dyn_cast<ImplicitCastExpr>(E)) {
3247 E = ICE->getSubExpr();
3248 } else {
3249 llvm_unreachable("unexpected expr type in resource member access");
3250 }
3251 }
3252 return true;
3253}
3254
3256 CXXRecordDecl *RD) {
3257 QualType AddrSpaceType =
3258 SemaRef.Context.getCanonicalType(SemaRef.Context.getAddrSpaceQualType(
3259 Type.withConst(), LangAS::hlsl_constant));
3260 QualType ReturnTy = SemaRef.Context.getCanonicalType(
3261 SemaRef.Context.getLValueReferenceType(AddrSpaceType));
3262
3263 DeclarationName ConvName =
3264 SemaRef.Context.DeclarationNames.getCXXConversionFunctionName(
3265 CanQualType::CreateUnsafe(ReturnTy));
3266 LookupResult ConvR(SemaRef, ConvName, SourceLocation(),
3268 [[maybe_unused]] bool LookupSucceeded =
3269 SemaRef.LookupQualifiedName(ConvR, RD);
3270 assert(LookupSucceeded);
3271
3272 for (NamedDecl *D : ConvR) {
3274 return D;
3275 }
3276 return nullptr;
3277}
3278
3279std::optional<ExprResult>
3281 QualType BaseType = BaseExpr.get()->getType();
3282 const HLSLAttributedResourceType *ResTy =
3283 HLSLAttributedResourceType::findHandleTypeOnResource(
3284 BaseType.getTypePtr());
3285 if (!ResTy ||
3286 ResTy->getAttrs().ResourceClass != llvm::dxil::ResourceClass::CBuffer)
3287 return std::nullopt;
3288
3289 QualType TemplateType = ResTy->getContainedType();
3290
3291 NamedDecl *NamedConversionDecl = getConstantBufferConversionFunction(
3292 TemplateType, BaseType->getAsCXXRecordDecl());
3293 assert(NamedConversionDecl &&
3294 "Could not find conversion function for ConstantBuffer.");
3295 auto *ConversionDecl =
3296 cast<CXXConversionDecl>(NamedConversionDecl->getUnderlyingDecl());
3297
3298 return SemaRef.BuildCXXMemberCallExpr(BaseExpr.get(), NamedConversionDecl,
3299 ConversionDecl,
3300 /*HadMultipleCandidates=*/false);
3301}
3302
3303void SemaHLSL::diagnoseAvailabilityViolations(TranslationUnitDecl *TU) {
3304 // Skip running the diagnostics scan if the diagnostic mode is
3305 // strict (-fhlsl-strict-availability) and the target shader stage is known
3306 // because all relevant diagnostics were already emitted in the
3307 // DiagnoseUnguardedAvailability scan (SemaAvailability.cpp).
3309 if (SemaRef.getLangOpts().HLSLStrictAvailability &&
3310 TI.getTriple().getEnvironment() != llvm::Triple::EnvironmentType::Library)
3311 return;
3312
3313 DiagnoseHLSLAvailability(SemaRef).RunOnTranslationUnit(TU);
3314}
3315
3316static bool CheckAllArgsHaveSameType(Sema *S, CallExpr *TheCall) {
3317 assert(TheCall->getNumArgs() > 1);
3318 QualType ArgTy0 = TheCall->getArg(0)->getType();
3319
3320 for (unsigned I = 1, N = TheCall->getNumArgs(); I < N; ++I) {
3322 ArgTy0, TheCall->getArg(I)->getType())) {
3323 S->Diag(TheCall->getBeginLoc(), diag::err_vec_builtin_incompatible_vector)
3324 << TheCall->getDirectCallee() << /*useAllTerminology*/ true
3325 << SourceRange(TheCall->getArg(0)->getBeginLoc(),
3326 TheCall->getArg(N - 1)->getEndLoc());
3327 return true;
3328 }
3329 }
3330 return false;
3331}
3332
3334 QualType ArgType = Arg->getType();
3336 S->Diag(Arg->getBeginLoc(), diag::err_typecheck_convert_incompatible)
3337 << ArgType << ExpectedType << 1 << 0 << 0;
3338 return true;
3339 }
3340 return false;
3341}
3342
3344 Sema *S, CallExpr *TheCall,
3345 llvm::function_ref<bool(Sema *S, SourceLocation Loc, int ArgOrdinal,
3346 clang::QualType PassedType)>
3347 Check) {
3348 for (unsigned I = 0; I < TheCall->getNumArgs(); ++I) {
3349 Expr *Arg = TheCall->getArg(I);
3350 if (Check(S, Arg->getBeginLoc(), I + 1, Arg->getType()))
3351 return true;
3352 }
3353 return false;
3354}
3355
3357 int ArgOrdinal,
3358 clang::QualType PassedType) {
3359 clang::QualType BaseType =
3360 PassedType->isVectorType()
3361 ? PassedType->castAs<clang::VectorType>()->getElementType()
3362 : PassedType;
3363 if (!BaseType->isFloat32Type())
3364 return S->Diag(Loc, diag::err_builtin_invalid_arg_type)
3365 << ArgOrdinal << /* scalar or vector of */ 5 << /* no int */ 0
3366 << /* float */ 1 << PassedType;
3367 return false;
3368}
3369
3371 int ArgOrdinal,
3372 clang::QualType PassedType) {
3373 clang::QualType BaseType = PassedType;
3374 if (const auto *VT = PassedType->getAs<clang::VectorType>())
3375 BaseType = VT->getElementType();
3376 else if (const auto *MT = PassedType->getAs<clang::MatrixType>())
3377 BaseType = MT->getElementType();
3378
3379 if (!BaseType->isHalfType() && !BaseType->isFloat32Type())
3380 return S->Diag(Loc, diag::err_builtin_invalid_arg_type)
3381 << ArgOrdinal << /* scalar or vector of */ 5 << /* no int */ 0
3382 << /* half or float */ 2 << PassedType;
3383 return false;
3384}
3385
3387 int ArgOrdinal,
3388 clang::QualType PassedType) {
3389 clang::QualType BaseType =
3390 PassedType->isVectorType()
3391 ? PassedType->castAs<clang::VectorType>()->getElementType()
3392 : PassedType->isMatrixType()
3393 ? PassedType->castAs<clang::MatrixType>()->getElementType()
3394 : PassedType;
3395 if (!BaseType->isDoubleType()) {
3396 // FIXME: adopt standard `err_builtin_invalid_arg_type` instead of using
3397 // this custom error.
3398 return S->Diag(Loc, diag::err_builtin_requires_double_type)
3399 << ArgOrdinal << PassedType;
3400 }
3401
3402 return false;
3403}
3404
3405static bool CheckModifiableLValue(Sema *S, CallExpr *TheCall,
3406 unsigned ArgIndex) {
3407 auto *Arg = TheCall->getArg(ArgIndex);
3408 SourceLocation OrigLoc = Arg->getExprLoc();
3409 if (Arg->IgnoreCasts()->isModifiableLvalue(S->Context, &OrigLoc) ==
3411 return false;
3412 S->Diag(OrigLoc, diag::error_hlsl_inout_lvalue) << Arg << 0;
3413 return true;
3414}
3415
3416// Verifies that the argument at `ArgIndex` of `TheCall` refers to memory in
3417// one of `AllowedSpaces`. Intended for HLSL builtins (e.g. atomics).
3418static bool CheckArgAddrSpaceOneOf(Sema *S, CallExpr *TheCall,
3419 unsigned ArgIndex,
3420 ArrayRef<LangAS> AllowedSpaces) {
3421 Expr *Arg = TheCall->getArg(ArgIndex);
3422 QualType LValueTy = Arg->IgnoreCasts()->getType();
3423 if (llvm::is_contained(AllowedSpaces, LValueTy.getAddressSpace()))
3424 return false;
3425 S->Diag(Arg->getBeginLoc(), diag::err_hlsl_atomic_arg_addr_space)
3426 << (ArgIndex + 1) << LValueTy;
3427 return true;
3428}
3429
3430static bool CheckNoDoubleVectors(Sema *S, SourceLocation Loc, int ArgOrdinal,
3431 clang::QualType PassedType) {
3432 const auto *VecTy = PassedType->getAs<VectorType>();
3433 if (!VecTy)
3434 return false;
3435
3436 if (VecTy->getElementType()->isDoubleType())
3437 return S->Diag(Loc, diag::err_builtin_invalid_arg_type)
3438 << ArgOrdinal << /* scalar */ 1 << /* no int */ 0 << /* fp */ 1
3439 << PassedType;
3440 return false;
3441}
3442
3444 int ArgOrdinal,
3445 clang::QualType PassedType) {
3446 if (!PassedType->hasIntegerRepresentation() &&
3447 !PassedType->hasFloatingRepresentation())
3448 return S->Diag(Loc, diag::err_builtin_invalid_arg_type)
3449 << ArgOrdinal << /* scalar or vector of */ 5 << /* integer */ 1
3450 << /* fp */ 1 << PassedType;
3451 return false;
3452}
3453
3455 int ArgOrdinal,
3456 clang::QualType PassedType) {
3457 if (auto *VecTy = PassedType->getAs<VectorType>())
3458 if (VecTy->getElementType()->isUnsignedIntegerType())
3459 return false;
3460
3461 return S->Diag(Loc, diag::err_builtin_invalid_arg_type)
3462 << ArgOrdinal << /* vector of */ 4 << /* uint */ 3 << /* no fp */ 0
3463 << PassedType;
3464}
3465
3466// checks for unsigned ints of all sizes
3468 int ArgOrdinal,
3469 clang::QualType PassedType) {
3470 if (!PassedType->hasUnsignedIntegerRepresentation())
3471 return S->Diag(Loc, diag::err_builtin_invalid_arg_type)
3472 << ArgOrdinal << /* scalar or vector of */ 5 << /* unsigned int */ 3
3473 << /* no fp */ 0 << PassedType;
3474 return false;
3475}
3476
3477static bool CheckExpectedBitWidth(Sema *S, CallExpr *TheCall,
3478 unsigned ArgOrdinal, unsigned Width) {
3479 QualType ArgTy = TheCall->getArg(0)->getType();
3480 if (auto *VTy = ArgTy->getAs<VectorType>())
3481 ArgTy = VTy->getElementType();
3482 // ensure arg type has expected bit width
3483 uint64_t ElementBitCount =
3485 if (ElementBitCount != Width) {
3486 S->Diag(TheCall->getArg(0)->getBeginLoc(),
3487 diag::err_integer_incorrect_bit_count)
3488 << Width << ElementBitCount;
3489 return true;
3490 }
3491 return false;
3492}
3493
3495 QualType ReturnType) {
3496 auto *VecTyA = TheCall->getArg(0)->getType()->getAs<VectorType>();
3497 if (VecTyA)
3498 ReturnType =
3499 S->Context.getExtVectorType(ReturnType, VecTyA->getNumElements());
3500
3501 TheCall->setType(ReturnType);
3502}
3503
3504static bool CheckScalarOrVector(Sema *S, CallExpr *TheCall, QualType Scalar,
3505 unsigned ArgIndex) {
3506 assert(TheCall->getNumArgs() >= ArgIndex);
3507 QualType ArgType = TheCall->getArg(ArgIndex)->getType();
3508 auto *VTy = ArgType->getAs<VectorType>();
3509 // not the scalar or vector<scalar>
3510 if (!(S->Context.hasSameUnqualifiedType(ArgType, Scalar) ||
3511 (VTy &&
3512 S->Context.hasSameUnqualifiedType(VTy->getElementType(), Scalar)))) {
3513 S->Diag(TheCall->getArg(0)->getBeginLoc(),
3514 diag::err_typecheck_expect_scalar_or_vector)
3515 << ArgType << Scalar;
3516 return true;
3517 }
3518 return false;
3519}
3520
3522 QualType Scalar, unsigned ArgIndex) {
3523 assert(TheCall->getNumArgs() > ArgIndex);
3524
3525 Expr *Arg = TheCall->getArg(ArgIndex);
3526 QualType ArgType = Arg->getType();
3527
3528 // Scalar: T
3529 if (S->Context.hasSameUnqualifiedType(ArgType, Scalar))
3530 return false;
3531
3532 // Vector: vector<T>
3533 if (const auto *VTy = ArgType->getAs<VectorType>()) {
3534 if (S->Context.hasSameUnqualifiedType(VTy->getElementType(), Scalar))
3535 return false;
3536 }
3537
3538 // Matrix: ConstantMatrixType with element type T
3539 if (const auto *MTy = ArgType->getAs<ConstantMatrixType>()) {
3540 if (S->Context.hasSameUnqualifiedType(MTy->getElementType(), Scalar))
3541 return false;
3542 }
3543
3544 // Not a scalar/vector/matrix-of-scalar
3545 S->Diag(Arg->getBeginLoc(),
3546 diag::err_typecheck_expect_scalar_or_vector_or_matrix)
3547 << ArgType << Scalar;
3548 return true;
3549}
3550
3551static bool CheckAnyScalarOrVector(Sema *S, CallExpr *TheCall,
3552 unsigned ArgIndex) {
3553 assert(TheCall->getNumArgs() >= ArgIndex);
3554 QualType ArgType = TheCall->getArg(ArgIndex)->getType();
3555 auto *VTy = ArgType->getAs<VectorType>();
3556 // not the scalar or vector<scalar>
3557 if (!(ArgType->isScalarType() ||
3558 (VTy && VTy->getElementType()->isScalarType()))) {
3559 S->Diag(TheCall->getArg(0)->getBeginLoc(),
3560 diag::err_typecheck_expect_any_scalar_or_vector)
3561 << ArgType << 1;
3562 return true;
3563 }
3564 return false;
3565}
3566
3567// Check that the argument is not a bool or vector<bool>
3568// Returns true on error
3570 unsigned ArgIndex) {
3571 QualType BoolType = S->getASTContext().BoolTy;
3572 assert(ArgIndex < TheCall->getNumArgs());
3573 QualType ArgType = TheCall->getArg(ArgIndex)->getType();
3574 auto *VTy = ArgType->getAs<VectorType>();
3575 // is the bool or vector<bool>
3576 if (S->Context.hasSameUnqualifiedType(ArgType, BoolType) ||
3577 (VTy &&
3578 S->Context.hasSameUnqualifiedType(VTy->getElementType(), BoolType))) {
3579 S->Diag(TheCall->getArg(0)->getBeginLoc(),
3580 diag::err_typecheck_expect_any_scalar_or_vector)
3581 << ArgType << 0;
3582 return true;
3583 }
3584 return false;
3585}
3586
3587static bool CheckWaveActive(Sema *S, CallExpr *TheCall) {
3588 if (CheckNotBoolScalarOrVector(S, TheCall, 0))
3589 return true;
3590 return false;
3591}
3592
3593static bool CheckWavePrefix(Sema *S, CallExpr *TheCall) {
3594 if (CheckNotBoolScalarOrVector(S, TheCall, 0))
3595 return true;
3596 return false;
3597}
3598
3599static bool CheckBoolSelect(Sema *S, CallExpr *TheCall) {
3600 assert(TheCall->getNumArgs() == 3);
3601 Expr *Arg1 = TheCall->getArg(1);
3602 Expr *Arg2 = TheCall->getArg(2);
3603 if (!S->Context.hasSameUnqualifiedType(Arg1->getType(), Arg2->getType())) {
3604 S->Diag(TheCall->getBeginLoc(),
3605 diag::err_typecheck_call_different_arg_types)
3606 << Arg1->getType() << Arg2->getType() << Arg1->getSourceRange()
3607 << Arg2->getSourceRange();
3608 return true;
3609 }
3610
3611 TheCall->setType(Arg1->getType());
3612 return false;
3613}
3614
3615static bool CheckVectorSelect(Sema *S, CallExpr *TheCall) {
3616 assert(TheCall->getNumArgs() == 3);
3617 Expr *Arg1 = TheCall->getArg(1);
3618 QualType Arg1Ty = Arg1->getType();
3619 Expr *Arg2 = TheCall->getArg(2);
3620 QualType Arg2Ty = Arg2->getType();
3621
3622 QualType Arg1ScalarTy = Arg1Ty;
3623 if (auto VTy = Arg1ScalarTy->getAs<VectorType>())
3624 Arg1ScalarTy = VTy->getElementType();
3625
3626 QualType Arg2ScalarTy = Arg2Ty;
3627 if (auto VTy = Arg2ScalarTy->getAs<VectorType>())
3628 Arg2ScalarTy = VTy->getElementType();
3629
3630 if (!S->Context.hasSameUnqualifiedType(Arg1ScalarTy, Arg2ScalarTy))
3631 S->Diag(Arg1->getBeginLoc(), diag::err_hlsl_builtin_scalar_vector_mismatch)
3632 << /* second and third */ 1 << TheCall->getCallee() << Arg1Ty << Arg2Ty;
3633
3634 QualType Arg0Ty = TheCall->getArg(0)->getType();
3635 unsigned Arg0Length = Arg0Ty->getAs<VectorType>()->getNumElements();
3636 unsigned Arg1Length = Arg1Ty->isVectorType()
3637 ? Arg1Ty->getAs<VectorType>()->getNumElements()
3638 : 0;
3639 unsigned Arg2Length = Arg2Ty->isVectorType()
3640 ? Arg2Ty->getAs<VectorType>()->getNumElements()
3641 : 0;
3642 if (Arg1Length > 0 && Arg0Length != Arg1Length) {
3643 S->Diag(TheCall->getBeginLoc(),
3644 diag::err_typecheck_vector_lengths_not_equal)
3645 << Arg0Ty << Arg1Ty << TheCall->getArg(0)->getSourceRange()
3646 << Arg1->getSourceRange();
3647 return true;
3648 }
3649
3650 if (Arg2Length > 0 && Arg0Length != Arg2Length) {
3651 S->Diag(TheCall->getBeginLoc(),
3652 diag::err_typecheck_vector_lengths_not_equal)
3653 << Arg0Ty << Arg2Ty << TheCall->getArg(0)->getSourceRange()
3654 << Arg2->getSourceRange();
3655 return true;
3656 }
3657
3658 TheCall->setType(
3659 S->getASTContext().getExtVectorType(Arg1ScalarTy, Arg0Length));
3660 return false;
3661}
3662
3663static bool CheckIndexType(Sema *S, CallExpr *TheCall, unsigned IndexArgIndex) {
3664 assert(TheCall->getNumArgs() > IndexArgIndex && "Index argument missing");
3665 QualType ArgType = TheCall->getArg(IndexArgIndex)->getType();
3666 QualType IndexTy = ArgType;
3667 unsigned int ActualDim = 1;
3668 if (const auto *VTy = IndexTy->getAs<VectorType>()) {
3669 ActualDim = VTy->getNumElements();
3670 IndexTy = VTy->getElementType();
3671 }
3672 if (!IndexTy->isIntegerType()) {
3673 S->Diag(TheCall->getArg(IndexArgIndex)->getBeginLoc(),
3674 diag::err_typecheck_expect_int)
3675 << ArgType;
3676 return true;
3677 }
3678
3679 QualType ResourceArgTy = TheCall->getArg(0)->getType();
3680 const HLSLAttributedResourceType *ResTy =
3681 ResourceArgTy.getTypePtr()->getAs<HLSLAttributedResourceType>();
3682 assert(ResTy && "Resource argument must be a resource");
3683 HLSLAttributedResourceType::Attributes ResAttrs = ResTy->getAttrs();
3684
3685 unsigned int ExpectedDim = 1;
3686 if (ResAttrs.ResourceDimension != llvm::dxil::ResourceDimension::Unknown)
3687 ExpectedDim = getResourceDimensions(ResAttrs.ResourceDimension);
3688
3689 if (ActualDim != ExpectedDim) {
3690 S->Diag(TheCall->getArg(IndexArgIndex)->getBeginLoc(),
3691 diag::err_hlsl_builtin_resource_coordinate_dimension_mismatch)
3692 << cast<NamedDecl>(TheCall->getCalleeDecl()) << ExpectedDim
3693 << ActualDim;
3694 return true;
3695 }
3696
3697 return false;
3698}
3699
3701 Sema *S, CallExpr *TheCall, unsigned ArgIndex,
3702 llvm::function_ref<bool(const HLSLAttributedResourceType *ResType)> Check =
3703 nullptr) {
3704 assert(TheCall->getNumArgs() >= ArgIndex);
3705 QualType ArgType = TheCall->getArg(ArgIndex)->getType();
3706 const HLSLAttributedResourceType *ResTy =
3707 ArgType.getTypePtr()->getAs<HLSLAttributedResourceType>();
3708 if (!ResTy) {
3709 S->Diag(TheCall->getArg(ArgIndex)->getBeginLoc(),
3710 diag::err_typecheck_expect_hlsl_resource)
3711 << ArgType;
3712 return true;
3713 }
3714 if (Check && Check(ResTy)) {
3715 S->Diag(TheCall->getArg(ArgIndex)->getExprLoc(),
3716 diag::err_invalid_hlsl_resource_type)
3717 << ArgType;
3718 return true;
3719 }
3720 return false;
3721}
3722
3723static bool CheckVectorElementCount(Sema *S, QualType PassedType,
3724 QualType BaseType, unsigned ExpectedCount,
3725 SourceLocation Loc) {
3726 unsigned PassedCount = 1;
3727 if (const auto *VecTy = PassedType->getAs<VectorType>())
3728 PassedCount = VecTy->getNumElements();
3729
3730 if (PassedCount != ExpectedCount) {
3732 S->Context.getExtVectorType(BaseType, ExpectedCount);
3733 S->Diag(Loc, diag::err_typecheck_convert_incompatible)
3734 << PassedType << ExpectedType << 1 << 0 << 0;
3735 return true;
3736 }
3737 return false;
3738}
3739
3740enum class SampleKind { Sample, Bias, Grad, Level, Cmp, CmpLevelZero };
3741
3743 // Check the texture handle.
3744 if (CheckResourceHandle(&S, TheCall, 0,
3745 [](const HLSLAttributedResourceType *ResType) {
3746 return ResType->getAttrs().ResourceDimension ==
3747 llvm::dxil::ResourceDimension::Unknown;
3748 }))
3749 return true;
3750
3751 // Check the sampler handle.
3752 if (CheckResourceHandle(&S, TheCall, 1,
3753 [](const HLSLAttributedResourceType *ResType) {
3754 return ResType->getAttrs().ResourceClass !=
3755 llvm::hlsl::ResourceClass::Sampler;
3756 }))
3757 return true;
3758
3759 auto *ResourceTy =
3760 TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
3761
3762 // Check the location.
3763 unsigned ExpectedDim =
3764 getResourceDimensions(ResourceTy->getAttrs().ResourceDimension);
3765 if (CheckVectorElementCount(&S, TheCall->getArg(2)->getType(),
3766 S.Context.FloatTy, ExpectedDim,
3767 TheCall->getBeginLoc()))
3768 return true;
3769
3770 return false;
3771}
3772
3773static bool CheckCalculateLodBuiltin(Sema &S, CallExpr *TheCall) {
3774 if (S.checkArgCount(TheCall, 3))
3775 return true;
3776
3777 if (CheckTextureSamplerAndLocation(S, TheCall))
3778 return true;
3779
3780 TheCall->setType(S.Context.FloatTy);
3781 return false;
3782}
3783
3784static bool CheckGatherBuiltin(Sema &S, CallExpr *TheCall, bool IsCmp) {
3785 if (S.checkArgCountRange(TheCall, IsCmp ? 5 : 4, IsCmp ? 6 : 5))
3786 return true;
3787
3788 if (CheckTextureSamplerAndLocation(S, TheCall))
3789 return true;
3790
3791 unsigned NextIdx = 3;
3792 if (IsCmp) {
3793 // Check the compare value.
3794 QualType CmpTy = TheCall->getArg(NextIdx)->getType();
3795 if (!CmpTy->isFloatingType() || CmpTy->isVectorType()) {
3796 S.Diag(TheCall->getArg(NextIdx)->getBeginLoc(),
3797 diag::err_typecheck_convert_incompatible)
3798 << CmpTy << S.Context.FloatTy << 1 << 0 << 0;
3799 return true;
3800 }
3801 NextIdx++;
3802 }
3803
3804 // Check the component operand.
3805 Expr *ComponentArg = TheCall->getArg(NextIdx);
3806 QualType ComponentTy = ComponentArg->getType();
3807 if (!ComponentTy->isIntegerType() || ComponentTy->isVectorType()) {
3808 S.Diag(ComponentArg->getBeginLoc(),
3809 diag::err_typecheck_convert_incompatible)
3810 << ComponentTy << S.Context.UnsignedIntTy << 1 << 0 << 0;
3811 return true;
3812 }
3813
3814 // GatherCmp operations on Vulkan target must use component 0 (Red).
3815 if (IsCmp && S.getASTContext().getTargetInfo().getTriple().isSPIRV()) {
3816 std::optional<llvm::APSInt> ComponentOpt =
3817 ComponentArg->getIntegerConstantExpr(S.getASTContext());
3818 if (ComponentOpt) {
3819 int64_t ComponentVal = ComponentOpt->getSExtValue();
3820 if (ComponentVal != 0) {
3821 // Issue an error if the component is not 0 (Red).
3822 // 0 -> Red, 1 -> Green, 2 -> Blue, 3 -> Alpha
3823 assert(ComponentVal >= 0 && ComponentVal <= 3 &&
3824 "The component is not in the expected range.");
3825 S.Diag(ComponentArg->getBeginLoc(),
3826 diag::err_hlsl_gathercmp_invalid_component)
3827 << ComponentVal;
3828 return true;
3829 }
3830 }
3831 }
3832
3833 NextIdx++;
3834
3835 // Check the offset operand.
3836 const HLSLAttributedResourceType *ResourceTy =
3837 TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
3838 if (TheCall->getNumArgs() > NextIdx) {
3839 unsigned ExpectedDim =
3840 getResourceDimensions(ResourceTy->getAttrs().ResourceDimension);
3841 if (CheckVectorElementCount(&S, TheCall->getArg(NextIdx)->getType(),
3842 S.Context.IntTy, ExpectedDim,
3843 TheCall->getArg(NextIdx)->getBeginLoc()))
3844 return true;
3845 NextIdx++;
3846 }
3847
3848 assert(ResourceTy->hasContainedType() &&
3849 "Expecting a contained type for resource with a dimension "
3850 "attribute.");
3851 QualType ReturnType = ResourceTy->getContainedType();
3852
3853 if (IsCmp) {
3854 if (!ReturnType->hasFloatingRepresentation()) {
3855 S.Diag(TheCall->getBeginLoc(), diag::err_hlsl_samplecmp_requires_float);
3856 return true;
3857 }
3858 }
3859
3860 if (const auto *VecTy = ReturnType->getAs<VectorType>())
3861 ReturnType = VecTy->getElementType();
3862 ReturnType = S.Context.getExtVectorType(ReturnType, 4);
3863
3864 TheCall->setType(ReturnType);
3865
3866 return false;
3867}
3868static bool CheckLoadLevelBuiltin(Sema &S, CallExpr *TheCall) {
3869 if (S.checkArgCountRange(TheCall, 2, 3))
3870 return true;
3871
3872 // Check the texture handle.
3873 if (CheckResourceHandle(&S, TheCall, 0,
3874 [](const HLSLAttributedResourceType *ResType) {
3875 return ResType->getAttrs().ResourceDimension ==
3876 llvm::dxil::ResourceDimension::Unknown;
3877 }))
3878 return true;
3879
3880 auto *ResourceTy =
3881 TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
3882
3883 // Check the location + lod (int3 for Texture2D).
3884 unsigned ExpectedDim =
3885 getResourceDimensions(ResourceTy->getAttrs().ResourceDimension);
3886 QualType CoordLODTy = TheCall->getArg(1)->getType();
3887 if (CheckVectorElementCount(&S, CoordLODTy, S.Context.IntTy, ExpectedDim + 1,
3888 TheCall->getArg(1)->getBeginLoc()))
3889 return true;
3890
3891 QualType EltTy = CoordLODTy;
3892 if (const auto *VTy = EltTy->getAs<VectorType>())
3893 EltTy = VTy->getElementType();
3894 if (!EltTy->isIntegerType()) {
3895 S.Diag(TheCall->getArg(1)->getBeginLoc(), diag::err_typecheck_expect_int)
3896 << CoordLODTy;
3897 return true;
3898 }
3899
3900 // Check the offset operand.
3901 if (TheCall->getNumArgs() > 2) {
3902 if (CheckVectorElementCount(&S, TheCall->getArg(2)->getType(),
3903 S.Context.IntTy, ExpectedDim,
3904 TheCall->getArg(2)->getBeginLoc()))
3905 return true;
3906 }
3907
3908 TheCall->setType(ResourceTy->getContainedType());
3909 return false;
3910}
3911
3912static bool CheckSamplingBuiltin(Sema &S, CallExpr *TheCall, SampleKind Kind) {
3913 unsigned MinArgs, MaxArgs;
3914 if (Kind == SampleKind::Sample) {
3915 MinArgs = 3;
3916 MaxArgs = 5;
3917 } else if (Kind == SampleKind::Bias) {
3918 MinArgs = 4;
3919 MaxArgs = 6;
3920 } else if (Kind == SampleKind::Grad) {
3921 MinArgs = 5;
3922 MaxArgs = 7;
3923 } else if (Kind == SampleKind::Level) {
3924 MinArgs = 4;
3925 MaxArgs = 5;
3926 } else if (Kind == SampleKind::Cmp) {
3927 MinArgs = 4;
3928 MaxArgs = 6;
3929 } else {
3930 assert(Kind == SampleKind::CmpLevelZero);
3931 MinArgs = 4;
3932 MaxArgs = 5;
3933 }
3934
3935 if (S.checkArgCountRange(TheCall, MinArgs, MaxArgs))
3936 return true;
3937
3938 if (CheckTextureSamplerAndLocation(S, TheCall))
3939 return true;
3940
3941 const HLSLAttributedResourceType *ResourceTy =
3942 TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
3943 unsigned ExpectedDim =
3944 getResourceDimensions(ResourceTy->getAttrs().ResourceDimension);
3945
3946 unsigned NextIdx = 3;
3947 if (Kind == SampleKind::Bias || Kind == SampleKind::Level ||
3948 Kind == SampleKind::Cmp || Kind == SampleKind::CmpLevelZero) {
3949 // Check the bias, lod level, or compare value, depending on the kind.
3950 // All of them must be a scalar float value.
3951 QualType BiasOrLODOrCmpTy = TheCall->getArg(NextIdx)->getType();
3952 if (!BiasOrLODOrCmpTy->isFloatingType() ||
3953 BiasOrLODOrCmpTy->isVectorType()) {
3954 S.Diag(TheCall->getArg(NextIdx)->getBeginLoc(),
3955 diag::err_typecheck_convert_incompatible)
3956 << BiasOrLODOrCmpTy << S.Context.FloatTy << 1 << 0 << 0;
3957 return true;
3958 }
3959 NextIdx++;
3960 } else if (Kind == SampleKind::Grad) {
3961 // Check the DDX operand.
3962 if (CheckVectorElementCount(&S, TheCall->getArg(NextIdx)->getType(),
3963 S.Context.FloatTy, ExpectedDim,
3964 TheCall->getArg(NextIdx)->getBeginLoc()))
3965 return true;
3966
3967 // Check the DDY operand.
3968 if (CheckVectorElementCount(&S, TheCall->getArg(NextIdx + 1)->getType(),
3969 S.Context.FloatTy, ExpectedDim,
3970 TheCall->getArg(NextIdx + 1)->getBeginLoc()))
3971 return true;
3972 NextIdx += 2;
3973 }
3974
3975 // Check the offset operand.
3976 if (TheCall->getNumArgs() > NextIdx) {
3977 if (CheckVectorElementCount(&S, TheCall->getArg(NextIdx)->getType(),
3978 S.Context.IntTy, ExpectedDim,
3979 TheCall->getArg(NextIdx)->getBeginLoc()))
3980 return true;
3981 NextIdx++;
3982 }
3983
3984 // Check the clamp operand.
3985 if (Kind != SampleKind::Level && Kind != SampleKind::CmpLevelZero &&
3986 TheCall->getNumArgs() > NextIdx) {
3987 QualType ClampTy = TheCall->getArg(NextIdx)->getType();
3988 if (!ClampTy->isFloatingType() || ClampTy->isVectorType()) {
3989 S.Diag(TheCall->getArg(NextIdx)->getBeginLoc(),
3990 diag::err_typecheck_convert_incompatible)
3991 << ClampTy << S.Context.FloatTy << 1 << 0 << 0;
3992 return true;
3993 }
3994 }
3995
3996 assert(ResourceTy->hasContainedType() &&
3997 "Expecting a contained type for resource with a dimension "
3998 "attribute.");
3999 QualType ReturnType = ResourceTy->getContainedType();
4000 if (Kind == SampleKind::Cmp || Kind == SampleKind::CmpLevelZero) {
4001 if (!ReturnType->hasFloatingRepresentation()) {
4002 S.Diag(TheCall->getBeginLoc(), diag::err_hlsl_samplecmp_requires_float);
4003 return true;
4004 }
4005 ReturnType = S.Context.FloatTy;
4006 }
4007 TheCall->setType(ReturnType);
4008
4009 return false;
4010}
4011
4012// Note: returning true in this case results in CheckBuiltinFunctionCall
4013// returning an ExprError
4014bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
4015 switch (BuiltinID) {
4016 case Builtin::BI__builtin_hlsl_adduint64: {
4017 if (SemaRef.checkArgCount(TheCall, 2))
4018 return true;
4019
4020 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
4022 return true;
4023
4024 // ensure arg integers are 32-bits
4025 if (CheckExpectedBitWidth(&SemaRef, TheCall, 0, 32))
4026 return true;
4027
4028 // ensure both args are vectors of total bit size of a multiple of 64
4029 auto *VTy = TheCall->getArg(0)->getType()->getAs<VectorType>();
4030 int NumElementsArg = VTy->getNumElements();
4031 if (NumElementsArg != 2 && NumElementsArg != 4) {
4032 SemaRef.Diag(TheCall->getBeginLoc(), diag::err_vector_incorrect_bit_count)
4033 << 1 /*a multiple of*/ << 64 << NumElementsArg * 32;
4034 return true;
4035 }
4036
4037 // ensure first arg and second arg have the same type
4038 if (CheckAllArgsHaveSameType(&SemaRef, TheCall))
4039 return true;
4040
4041 ExprResult A = TheCall->getArg(0);
4042 QualType ArgTyA = A.get()->getType();
4043 // return type is the same as the input type
4044 TheCall->setType(ArgTyA);
4045 break;
4046 }
4047 case Builtin::BI__builtin_hlsl_resource_getpointer: {
4048 if (SemaRef.checkArgCountRange(TheCall, 1, 2) ||
4049 CheckResourceHandle(&SemaRef, TheCall, 0) ||
4050 (TheCall->getNumArgs() == 2 && CheckIndexType(&SemaRef, TheCall, 1)))
4051 return true;
4052
4053 auto *ResourceTy =
4054 TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
4055 QualType ContainedTy = ResourceTy->getContainedType();
4056 auto ReturnType = SemaRef.Context.getAddrSpaceQualType(
4057 ContainedTy,
4058 getLangASFromResourceClass(ResourceTy->getAttrs().ResourceClass));
4059 ReturnType = SemaRef.Context.getPointerType(ReturnType);
4060 TheCall->setType(ReturnType);
4061
4062 break;
4063 }
4064 case Builtin::BI__builtin_hlsl_resource_getpointer_typed: {
4065 if (SemaRef.checkArgCount(TheCall, 3) ||
4066 CheckResourceHandle(&SemaRef, TheCall, 0) ||
4067 CheckIndexType(&SemaRef, TheCall, 1))
4068 return true;
4069
4070 QualType ElementTy = TheCall->getArg(2)->getType();
4071 assert(ElementTy->isPointerType() &&
4072 "expected pointer type for second argument");
4073 ElementTy = ElementTy->getPointeeType();
4074
4075 // Reject array types
4076 if (ElementTy->isArrayType())
4077 return SemaRef.Diag(
4078 cast<FunctionDecl>(SemaRef.CurContext)->getPointOfInstantiation(),
4079 diag::err_invalid_use_of_array_type);
4080
4081 auto *ResourceTy =
4082 TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
4083 auto ReturnType = SemaRef.Context.getAddrSpaceQualType(
4084 ElementTy,
4085 getLangASFromResourceClass(ResourceTy->getAttrs().ResourceClass));
4086 ReturnType = SemaRef.Context.getPointerType(ReturnType);
4087 TheCall->setType(ReturnType);
4088
4089 break;
4090 }
4091 case Builtin::BI__builtin_hlsl_resource_load_with_status: {
4092 if (SemaRef.checkArgCount(TheCall, 3) ||
4093 CheckResourceHandle(&SemaRef, TheCall, 0) ||
4094 CheckArgTypeMatches(&SemaRef, TheCall->getArg(1),
4095 SemaRef.getASTContext().UnsignedIntTy) ||
4096 CheckArgTypeMatches(&SemaRef, TheCall->getArg(2),
4097 SemaRef.getASTContext().UnsignedIntTy) ||
4098 CheckModifiableLValue(&SemaRef, TheCall, 2))
4099 return true;
4100
4101 auto *ResourceTy =
4102 TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
4103 QualType ReturnType = ResourceTy->getContainedType();
4104 TheCall->setType(ReturnType);
4105
4106 break;
4107 }
4108 case Builtin::BI__builtin_hlsl_resource_load_with_status_typed: {
4109 if (SemaRef.checkArgCount(TheCall, 4) ||
4110 CheckResourceHandle(&SemaRef, TheCall, 0) ||
4111 CheckArgTypeMatches(&SemaRef, TheCall->getArg(1),
4112 SemaRef.getASTContext().UnsignedIntTy) ||
4113 CheckArgTypeMatches(&SemaRef, TheCall->getArg(2),
4114 SemaRef.getASTContext().UnsignedIntTy) ||
4115 CheckModifiableLValue(&SemaRef, TheCall, 2))
4116 return true;
4117
4118 QualType ReturnType = TheCall->getArg(3)->getType();
4119 assert(ReturnType->isPointerType() &&
4120 "expected pointer type for second argument");
4121 ReturnType = ReturnType->getPointeeType();
4122
4123 // Reject array types
4124 if (ReturnType->isArrayType())
4125 return SemaRef.Diag(
4126 cast<FunctionDecl>(SemaRef.CurContext)->getPointOfInstantiation(),
4127 diag::err_invalid_use_of_array_type);
4128
4129 TheCall->setType(ReturnType);
4130
4131 break;
4132 }
4133 case Builtin::BI__builtin_hlsl_resource_load_level:
4134 return CheckLoadLevelBuiltin(SemaRef, TheCall);
4135 case Builtin::BI__builtin_hlsl_resource_sample:
4137 case Builtin::BI__builtin_hlsl_resource_sample_bias:
4139 case Builtin::BI__builtin_hlsl_resource_sample_grad:
4141 case Builtin::BI__builtin_hlsl_resource_sample_level:
4143 case Builtin::BI__builtin_hlsl_resource_sample_cmp:
4145 case Builtin::BI__builtin_hlsl_resource_sample_cmp_level_zero:
4147 case Builtin::BI__builtin_hlsl_resource_calculate_lod:
4148 case Builtin::BI__builtin_hlsl_resource_calculate_lod_unclamped:
4149 return CheckCalculateLodBuiltin(SemaRef, TheCall);
4150 case Builtin::BI__builtin_hlsl_resource_gather:
4151 return CheckGatherBuiltin(SemaRef, TheCall, /*IsCmp=*/false);
4152 case Builtin::BI__builtin_hlsl_resource_gather_cmp:
4153 return CheckGatherBuiltin(SemaRef, TheCall, /*IsCmp=*/true);
4154 case Builtin::BI__builtin_hlsl_resource_uninitializedhandle: {
4155 assert(TheCall->getNumArgs() == 1 && "expected 1 arg");
4156 // Update return type to be the attributed resource type from arg0.
4157 QualType ResourceTy = TheCall->getArg(0)->getType();
4158 TheCall->setType(ResourceTy);
4159 break;
4160 }
4161 case Builtin::BI__builtin_hlsl_resource_handlefrombinding: {
4162 assert(TheCall->getNumArgs() == 6 && "expected 6 args");
4163 // Update return type to be the attributed resource type from arg0.
4164 QualType ResourceTy = TheCall->getArg(0)->getType();
4165 TheCall->setType(ResourceTy);
4166 break;
4167 }
4168 case Builtin::BI__builtin_hlsl_resource_handlefromimplicitbinding: {
4169 assert(TheCall->getNumArgs() == 6 && "expected 6 args");
4170 // Update return type to be the attributed resource type from arg0.
4171 QualType ResourceTy = TheCall->getArg(0)->getType();
4172 TheCall->setType(ResourceTy);
4173 break;
4174 }
4175 case Builtin::BI__builtin_hlsl_resource_counterhandlefromimplicitbinding: {
4176 assert(TheCall->getNumArgs() == 3 && "expected 3 args");
4177 ASTContext &AST = SemaRef.getASTContext();
4178 QualType MainHandleTy = TheCall->getArg(0)->getType();
4179 auto *MainResType = MainHandleTy->getAs<HLSLAttributedResourceType>();
4180 auto MainAttrs = MainResType->getAttrs();
4181 assert(!MainAttrs.IsCounter && "cannot create a counter from a counter");
4182 MainAttrs.IsCounter = true;
4183 QualType CounterHandleTy = AST.getHLSLAttributedResourceType(
4184 MainResType->getWrappedType(), MainResType->getContainedType(),
4185 MainAttrs);
4186 // Update return type to be the attributed resource type from arg0
4187 // with added IsCounter flag.
4188 TheCall->setType(CounterHandleTy);
4189 break;
4190 }
4191 case Builtin::BI__builtin_hlsl_and:
4192 case Builtin::BI__builtin_hlsl_or: {
4193 if (SemaRef.checkArgCount(TheCall, 2))
4194 return true;
4195 if (CheckScalarOrVectorOrMatrix(&SemaRef, TheCall, getASTContext().BoolTy,
4196 0))
4197 return true;
4198 if (CheckAllArgsHaveSameType(&SemaRef, TheCall))
4199 return true;
4200
4201 ExprResult A = TheCall->getArg(0);
4202 QualType ArgTyA = A.get()->getType();
4203 // return type is the same as the input type
4204 TheCall->setType(ArgTyA);
4205 break;
4206 }
4207 case Builtin::BI__builtin_hlsl_all:
4208 case Builtin::BI__builtin_hlsl_any: {
4209 if (SemaRef.checkArgCount(TheCall, 1))
4210 return true;
4211 if (CheckAnyScalarOrVector(&SemaRef, TheCall, 0))
4212 return true;
4213 break;
4214 }
4215 case Builtin::BI__builtin_hlsl_asdouble: {
4216 if (SemaRef.checkArgCount(TheCall, 2))
4217 return true;
4219 &SemaRef, TheCall,
4220 /*only check for uint*/ SemaRef.Context.UnsignedIntTy,
4221 /* arg index */ 0))
4222 return true;
4224 &SemaRef, TheCall,
4225 /*only check for uint*/ SemaRef.Context.UnsignedIntTy,
4226 /* arg index */ 1))
4227 return true;
4228 if (CheckAllArgsHaveSameType(&SemaRef, TheCall))
4229 return true;
4230
4231 SetElementTypeAsReturnType(&SemaRef, TheCall, getASTContext().DoubleTy);
4232 break;
4233 }
4234 case Builtin::BI__builtin_hlsl_elementwise_clamp: {
4235 if (SemaRef.BuiltinElementwiseTernaryMath(
4236 TheCall, /*ArgTyRestr=*/
4238 return true;
4239 break;
4240 }
4241 case Builtin::BI__builtin_hlsl_dot: {
4242 // arg count is checked by BuiltinVectorToScalarMath
4243 if (SemaRef.BuiltinVectorToScalarMath(TheCall))
4244 return true;
4246 return true;
4247 break;
4248 }
4249 case Builtin::BI__builtin_hlsl_elementwise_firstbithigh:
4250 case Builtin::BI__builtin_hlsl_elementwise_firstbitlow: {
4251 if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall))
4252 return true;
4253
4254 const Expr *Arg = TheCall->getArg(0);
4255 QualType ArgTy = Arg->getType();
4256 QualType EltTy = ArgTy;
4257
4258 QualType ResTy = SemaRef.Context.UnsignedIntTy;
4259
4260 if (auto *VecTy = EltTy->getAs<VectorType>()) {
4261 EltTy = VecTy->getElementType();
4262 ResTy = SemaRef.Context.getExtVectorType(ResTy, VecTy->getNumElements());
4263 }
4264
4265 if (!EltTy->isIntegerType()) {
4266 Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
4267 << 1 << /* scalar or vector of */ 5 << /* integer ty */ 1
4268 << /* no fp */ 0 << ArgTy;
4269 return true;
4270 }
4271
4272 TheCall->setType(ResTy);
4273 break;
4274 }
4275 case Builtin::BI__builtin_hlsl_select: {
4276 if (SemaRef.checkArgCount(TheCall, 3))
4277 return true;
4278 if (CheckScalarOrVector(&SemaRef, TheCall, getASTContext().BoolTy, 0))
4279 return true;
4280 QualType ArgTy = TheCall->getArg(0)->getType();
4281 if (ArgTy->isBooleanType() && CheckBoolSelect(&SemaRef, TheCall))
4282 return true;
4283 auto *VTy = ArgTy->getAs<VectorType>();
4284 if (VTy && VTy->getElementType()->isBooleanType() &&
4285 CheckVectorSelect(&SemaRef, TheCall))
4286 return true;
4287 break;
4288 }
4289 case Builtin::BI__builtin_hlsl_elementwise_saturate:
4290 case Builtin::BI__builtin_hlsl_elementwise_rcp: {
4291 if (SemaRef.checkArgCount(TheCall, 1))
4292 return true;
4293 if (!TheCall->getArg(0)
4294 ->getType()
4295 ->hasFloatingRepresentation()) // half or float or double
4296 return SemaRef.Diag(TheCall->getArg(0)->getBeginLoc(),
4297 diag::err_builtin_invalid_arg_type)
4298 << /* ordinal */ 1 << /* scalar or vector */ 5 << /* no int */ 0
4299 << /* fp */ 1 << TheCall->getArg(0)->getType();
4300 if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall))
4301 return true;
4302 break;
4303 }
4304 case Builtin::BI__builtin_hlsl_elementwise_degrees:
4305 case Builtin::BI__builtin_hlsl_elementwise_radians:
4306 case Builtin::BI__builtin_hlsl_elementwise_rsqrt:
4307 case Builtin::BI__builtin_hlsl_elementwise_frac:
4308 case Builtin::BI__builtin_hlsl_elementwise_ddx_coarse:
4309 case Builtin::BI__builtin_hlsl_elementwise_ddy_coarse:
4310 case Builtin::BI__builtin_hlsl_elementwise_ddx_fine:
4311 case Builtin::BI__builtin_hlsl_elementwise_ddy_fine: {
4312 if (SemaRef.checkArgCount(TheCall, 1))
4313 return true;
4314 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
4316 return true;
4317 if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall))
4318 return true;
4319 break;
4320 }
4321 case Builtin::BI__builtin_hlsl_elementwise_isinf:
4322 case Builtin::BI__builtin_hlsl_elementwise_isnan: {
4323 if (SemaRef.checkArgCount(TheCall, 1))
4324 return true;
4325 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
4327 return true;
4328 if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall))
4329 return true;
4331 break;
4332 }
4333 case Builtin::BI__builtin_hlsl_lerp: {
4334 if (SemaRef.checkArgCount(TheCall, 3))
4335 return true;
4336 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
4338 return true;
4339 if (CheckAllArgsHaveSameType(&SemaRef, TheCall))
4340 return true;
4341 if (SemaRef.BuiltinElementwiseTernaryMath(TheCall))
4342 return true;
4343 break;
4344 }
4345 case Builtin::BI__builtin_hlsl_mad: {
4346 if (SemaRef.BuiltinElementwiseTernaryMath(
4347 TheCall, /*ArgTyRestr=*/
4349 return true;
4350 break;
4351 }
4352 case Builtin::BI__builtin_hlsl_mul: {
4353 if (SemaRef.checkArgCount(TheCall, 2))
4354 return true;
4355
4356 Expr *Arg0 = TheCall->getArg(0);
4357 Expr *Arg1 = TheCall->getArg(1);
4358 QualType Ty0 = Arg0->getType();
4359 QualType Ty1 = Arg1->getType();
4360
4361 auto getElemType = [](QualType T) -> QualType {
4362 if (const auto *VTy = T->getAs<VectorType>())
4363 return VTy->getElementType();
4364 if (const auto *MTy = T->getAs<ConstantMatrixType>())
4365 return MTy->getElementType();
4366 return T;
4367 };
4368
4369 QualType EltTy0 = getElemType(Ty0);
4370
4371 bool IsVec0 = Ty0->isVectorType();
4372 bool IsMat0 = Ty0->isConstantMatrixType();
4373 bool IsVec1 = Ty1->isVectorType();
4374 bool IsMat1 = Ty1->isConstantMatrixType();
4375
4376 QualType RetTy;
4377
4378 if (IsVec0 && IsMat1) {
4379 auto *MatTy = Ty1->castAs<ConstantMatrixType>();
4380 RetTy = getASTContext().getExtVectorType(EltTy0, MatTy->getNumColumns());
4381 } else if (IsMat0 && IsVec1) {
4382 auto *MatTy = Ty0->castAs<ConstantMatrixType>();
4383 RetTy = getASTContext().getExtVectorType(EltTy0, MatTy->getNumRows());
4384 } else {
4385 assert(IsMat0 && IsMat1);
4386 auto *MatTy0 = Ty0->castAs<ConstantMatrixType>();
4387 auto *MatTy1 = Ty1->castAs<ConstantMatrixType>();
4389 EltTy0, MatTy0->getNumRows(), MatTy1->getNumColumns());
4390 }
4391
4392 TheCall->setType(RetTy);
4393 break;
4394 }
4395 case Builtin::BI__builtin_hlsl_normalize: {
4396 if (SemaRef.checkArgCount(TheCall, 1))
4397 return true;
4398 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
4400 return true;
4401 ExprResult A = TheCall->getArg(0);
4402 QualType ArgTyA = A.get()->getType();
4403 // return type is the same as the input type
4404 TheCall->setType(ArgTyA);
4405 break;
4406 }
4407 case Builtin::BI__builtin_elementwise_fma: {
4408 if (SemaRef.checkArgCount(TheCall, 3) ||
4409 CheckAllArgsHaveSameType(&SemaRef, TheCall)) {
4410 return true;
4411 }
4412
4413 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
4415 return true;
4416
4417 ExprResult A = TheCall->getArg(0);
4418 QualType ArgTyA = A.get()->getType();
4419 // return type is the same as input type
4420 TheCall->setType(ArgTyA);
4421 break;
4422 }
4423 case Builtin::BI__builtin_hlsl_transpose: {
4424 if (SemaRef.checkArgCount(TheCall, 1))
4425 return true;
4426
4427 Expr *Arg = TheCall->getArg(0);
4428 QualType ArgTy = Arg->getType();
4429
4430 const auto *MatTy = ArgTy->getAs<ConstantMatrixType>();
4431 if (!MatTy) {
4432 SemaRef.Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
4433 << 1 << /* matrix */ 3 << /* no int */ 0 << /* no fp */ 0 << ArgTy;
4434 return true;
4435 }
4436
4438 MatTy->getElementType(), MatTy->getNumColumns(), MatTy->getNumRows());
4439 TheCall->setType(RetTy);
4440 break;
4441 }
4442 case Builtin::BI__builtin_hlsl_elementwise_sign: {
4443 if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall))
4444 return true;
4445 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
4447 return true;
4449 break;
4450 }
4451 case Builtin::BI__builtin_hlsl_step: {
4452 if (SemaRef.checkArgCount(TheCall, 2))
4453 return true;
4454 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
4456 return true;
4457
4458 ExprResult A = TheCall->getArg(0);
4459 QualType ArgTyA = A.get()->getType();
4460 // return type is the same as the input type
4461 TheCall->setType(ArgTyA);
4462 break;
4463 }
4464 case Builtin::BI__builtin_hlsl_wave_active_all_equal: {
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 QualType InputTy = TheCall->getArg(0)->getType();
4473 ASTContext &Ctx = getASTContext();
4474
4475 QualType RetTy;
4476
4477 // If vector, construct bool vector of same size
4478 if (const auto *VecTy = InputTy->getAs<ExtVectorType>()) {
4479 unsigned NumElts = VecTy->getNumElements();
4480 RetTy = Ctx.getExtVectorType(Ctx.BoolTy, NumElts);
4481 } else {
4482 // Scalar case
4483 RetTy = Ctx.BoolTy;
4484 }
4485
4486 TheCall->setType(RetTy);
4487 break;
4488 }
4489 case Builtin::BI__builtin_hlsl_wave_active_max:
4490 case Builtin::BI__builtin_hlsl_wave_active_min:
4491 case Builtin::BI__builtin_hlsl_wave_active_sum:
4492 case Builtin::BI__builtin_hlsl_wave_active_product: {
4493 if (SemaRef.checkArgCount(TheCall, 1))
4494 return true;
4495
4496 // Ensure input expr type is a scalar/vector and the same as the return type
4497 if (CheckAnyScalarOrVector(&SemaRef, TheCall, 0))
4498 return true;
4499 if (CheckWaveActive(&SemaRef, TheCall))
4500 return true;
4501 ExprResult Expr = TheCall->getArg(0);
4502 QualType ArgTyExpr = Expr.get()->getType();
4503 TheCall->setType(ArgTyExpr);
4504 break;
4505 }
4506 case Builtin::BI__builtin_hlsl_wave_active_bit_or:
4507 case Builtin::BI__builtin_hlsl_wave_active_bit_xor:
4508 case Builtin::BI__builtin_hlsl_wave_active_bit_and: {
4509 if (SemaRef.checkArgCount(TheCall, 1))
4510 return true;
4511
4512 // Ensure input expr type is a scalar/vector
4513 if (CheckAnyScalarOrVector(&SemaRef, TheCall, 0))
4514 return true;
4515
4516 if (CheckWaveActive(&SemaRef, TheCall))
4517 return true;
4518
4519 // Ensure the expr type is interpretable as a uint or vector<uint>
4520 ExprResult Expr = TheCall->getArg(0);
4521 QualType ArgTyExpr = Expr.get()->getType();
4522 auto *VTy = ArgTyExpr->getAs<VectorType>();
4523 if (!(ArgTyExpr->isIntegerType() ||
4524 (VTy && VTy->getElementType()->isIntegerType()))) {
4525 SemaRef.Diag(TheCall->getArg(0)->getBeginLoc(),
4526 diag::err_builtin_invalid_arg_type)
4527 << ArgTyExpr << SemaRef.Context.UnsignedIntTy << 1 << 0 << 0;
4528 return true;
4529 }
4530
4531 // Ensure input expr type is the same as the return type
4532 TheCall->setType(ArgTyExpr);
4533 break;
4534 }
4535 case Builtin::BI__builtin_hlsl_interlocked_add: {
4536 // The builtin's prototype in Builtins.td is `void (...)`, so direct calls
4537 // to `__builtin_hlsl_interlocked_add` bypass argument checking entirely.
4538 // When reached via the synthesized `InterlockedAdd` overload set in
4539 // HLSLExternalSemaSource, overload resolution has already enforced the
4540 // argument count, integer-type matching, and the address-space requirement
4541 // on `dest`. The checks below are a safety net for callers that invoke the
4542 // builtin by its mangled name and would otherwise reach CodeGen unchecked.
4543 if (TheCall->getNumArgs() < 2) {
4544 SemaRef.Diag(TheCall->getEndLoc(),
4545 diag::err_typecheck_call_too_few_args_at_least)
4546 << /*callee_type=*/0 << /*min_arg_count=*/2 << TheCall->getNumArgs()
4547 << /*is_non_object=*/0 << TheCall->getSourceRange();
4548 return true;
4549 }
4550 if (SemaRef.checkArgCountAtMost(TheCall, 3))
4551 return true;
4552
4553 QualType DestTy = TheCall->getArg(0)->getType().getUnqualifiedType();
4554 if (!DestTy->isIntegerType()) {
4555 SemaRef.Diag(TheCall->getArg(0)->getBeginLoc(),
4556 diag::err_builtin_invalid_arg_type)
4557 << /*ordinal=*/1 << /*scalar*/ 1 << /*integer*/ 1 << /*no float*/ 0
4558 << DestTy;
4559 return true;
4560 }
4561
4562 if (CheckModifiableLValue(&SemaRef, TheCall, 0))
4563 return true;
4564
4565 if (CheckArgAddrSpaceOneOf(&SemaRef, TheCall, 0,
4567 return true;
4568
4569 if (CheckArgTypeMatches(&SemaRef, TheCall->getArg(1), DestTy))
4570 return true;
4571
4572 if (TheCall->getNumArgs() == 3) {
4573 if (CheckArgTypeMatches(&SemaRef, TheCall->getArg(2), DestTy))
4574 return true;
4575 if (CheckModifiableLValue(&SemaRef, TheCall, 2))
4576 return true;
4577 }
4578
4579 TheCall->setType(SemaRef.Context.VoidTy);
4580 break;
4581 }
4582 // Note these are llvm builtins that we want to catch invalid intrinsic
4583 // generation. Normal handling of these builtins will occur elsewhere.
4584 case Builtin::BI__builtin_elementwise_bitreverse: {
4585 // does not include a check for number of arguments
4586 // because that is done previously
4587 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
4589 return true;
4590 break;
4591 }
4592 case Builtin::BI__builtin_hlsl_wave_prefix_count_bits: {
4593 if (SemaRef.checkArgCount(TheCall, 1))
4594 return true;
4595
4596 QualType ArgType = TheCall->getArg(0)->getType();
4597
4598 if (!(ArgType->isScalarType())) {
4599 SemaRef.Diag(TheCall->getArg(0)->getBeginLoc(),
4600 diag::err_typecheck_expect_any_scalar_or_vector)
4601 << ArgType << 0;
4602 return true;
4603 }
4604
4605 if (!(ArgType->isBooleanType())) {
4606 SemaRef.Diag(TheCall->getArg(0)->getBeginLoc(),
4607 diag::err_typecheck_expect_any_scalar_or_vector)
4608 << ArgType << 0;
4609 return true;
4610 }
4611
4612 break;
4613 }
4614 case Builtin::BI__builtin_hlsl_wave_read_lane_at: {
4615 if (SemaRef.checkArgCount(TheCall, 2))
4616 return true;
4617
4618 // Ensure index parameter type can be interpreted as a uint
4619 ExprResult Index = TheCall->getArg(1);
4620 QualType ArgTyIndex = Index.get()->getType();
4621 if (!ArgTyIndex->isIntegerType()) {
4622 SemaRef.Diag(TheCall->getArg(1)->getBeginLoc(),
4623 diag::err_typecheck_convert_incompatible)
4624 << ArgTyIndex << SemaRef.Context.UnsignedIntTy << 1 << 0 << 0;
4625 return true;
4626 }
4627
4628 // Ensure input expr type is a scalar/vector and the same as the return type
4629 if (CheckAnyScalarOrVector(&SemaRef, TheCall, 0))
4630 return true;
4631
4632 ExprResult Expr = TheCall->getArg(0);
4633 QualType ArgTyExpr = Expr.get()->getType();
4634 TheCall->setType(ArgTyExpr);
4635 break;
4636 }
4637 case Builtin::BI__builtin_hlsl_wave_get_lane_index: {
4638 if (SemaRef.checkArgCount(TheCall, 0))
4639 return true;
4640 break;
4641 }
4642 case Builtin::BI__builtin_hlsl_wave_prefix_sum:
4643 case Builtin::BI__builtin_hlsl_wave_prefix_product: {
4644 if (SemaRef.checkArgCount(TheCall, 1))
4645 return true;
4646
4647 // Ensure input expr type is a scalar/vector and the same as the return type
4648 if (CheckAnyScalarOrVector(&SemaRef, TheCall, 0))
4649 return true;
4650 if (CheckWavePrefix(&SemaRef, TheCall))
4651 return true;
4652 ExprResult Expr = TheCall->getArg(0);
4653 QualType ArgTyExpr = Expr.get()->getType();
4654 TheCall->setType(ArgTyExpr);
4655 break;
4656 }
4657 case Builtin::BI__builtin_hlsl_quad_read_across_x:
4658 case Builtin::BI__builtin_hlsl_quad_read_across_y:
4659 case Builtin::BI__builtin_hlsl_quad_read_across_diagonal: {
4660 if (SemaRef.checkArgCount(TheCall, 1))
4661 return true;
4662
4663 if (CheckAnyScalarOrVector(&SemaRef, TheCall, 0))
4664 return true;
4665 if (CheckNotBoolScalarOrVector(&SemaRef, TheCall, 0))
4666 return true;
4667 ExprResult Expr = TheCall->getArg(0);
4668 QualType ArgTyExpr = Expr.get()->getType();
4669 TheCall->setType(ArgTyExpr);
4670 break;
4671 }
4672 case Builtin::BI__builtin_hlsl_elementwise_splitdouble: {
4673 if (SemaRef.checkArgCount(TheCall, 3))
4674 return true;
4675
4676 if (CheckScalarOrVectorOrMatrix(&SemaRef, TheCall, SemaRef.Context.DoubleTy,
4677 0) ||
4679 SemaRef.Context.UnsignedIntTy, 1) ||
4681 SemaRef.Context.UnsignedIntTy, 2))
4682 return true;
4683
4684 if (CheckModifiableLValue(&SemaRef, TheCall, 1) ||
4685 CheckModifiableLValue(&SemaRef, TheCall, 2))
4686 return true;
4687 break;
4688 }
4689 case Builtin::BI__builtin_hlsl_elementwise_clip: {
4690 if (SemaRef.checkArgCount(TheCall, 1))
4691 return true;
4692
4693 if (CheckScalarOrVector(&SemaRef, TheCall, SemaRef.Context.FloatTy, 0))
4694 return true;
4695 break;
4696 }
4697 case Builtin::BI__builtin_elementwise_acos:
4698 case Builtin::BI__builtin_elementwise_asin:
4699 case Builtin::BI__builtin_elementwise_atan:
4700 case Builtin::BI__builtin_elementwise_atan2:
4701 case Builtin::BI__builtin_elementwise_ceil:
4702 case Builtin::BI__builtin_elementwise_cos:
4703 case Builtin::BI__builtin_elementwise_cosh:
4704 case Builtin::BI__builtin_elementwise_exp:
4705 case Builtin::BI__builtin_elementwise_exp2:
4706 case Builtin::BI__builtin_elementwise_exp10:
4707 case Builtin::BI__builtin_elementwise_floor:
4708 case Builtin::BI__builtin_elementwise_fmod:
4709 case Builtin::BI__builtin_elementwise_log:
4710 case Builtin::BI__builtin_elementwise_log2:
4711 case Builtin::BI__builtin_elementwise_log10:
4712 case Builtin::BI__builtin_elementwise_pow:
4713 case Builtin::BI__builtin_elementwise_roundeven:
4714 case Builtin::BI__builtin_elementwise_sin:
4715 case Builtin::BI__builtin_elementwise_sinh:
4716 case Builtin::BI__builtin_elementwise_sqrt:
4717 case Builtin::BI__builtin_elementwise_tan:
4718 case Builtin::BI__builtin_elementwise_tanh:
4719 case Builtin::BI__builtin_elementwise_trunc: {
4720 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
4722 return true;
4723 break;
4724 }
4725 case Builtin::BI__builtin_hlsl_buffer_update_counter: {
4726 assert(TheCall->getNumArgs() == 2 && "expected 2 args");
4727 auto checkResTy = [](const HLSLAttributedResourceType *ResTy) -> bool {
4728 return !(ResTy->getAttrs().ResourceClass == ResourceClass::UAV &&
4729 ResTy->getAttrs().RawBuffer && ResTy->hasContainedType());
4730 };
4731 if (CheckResourceHandle(&SemaRef, TheCall, 0, checkResTy))
4732 return true;
4733 Expr *OffsetExpr = TheCall->getArg(1);
4734 std::optional<llvm::APSInt> Offset =
4735 OffsetExpr->getIntegerConstantExpr(SemaRef.getASTContext());
4736 if (!Offset.has_value() || std::abs(Offset->getExtValue()) != 1) {
4737 SemaRef.Diag(TheCall->getArg(1)->getBeginLoc(),
4738 diag::err_hlsl_expect_arg_const_int_one_or_neg_one)
4739 << 1;
4740 return true;
4741 }
4742 break;
4743 }
4744 case Builtin::BI__builtin_hlsl_elementwise_f16tof32: {
4745 if (SemaRef.checkArgCount(TheCall, 1))
4746 return true;
4747 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
4749 return true;
4750 // ensure arg integers are 32 bits
4751 if (CheckExpectedBitWidth(&SemaRef, TheCall, 0, 32))
4752 return true;
4753 // check it wasn't a bool type
4754 QualType ArgTy = TheCall->getArg(0)->getType();
4755 if (auto *VTy = ArgTy->getAs<VectorType>())
4756 ArgTy = VTy->getElementType();
4757 if (ArgTy->isBooleanType()) {
4758 SemaRef.Diag(TheCall->getArg(0)->getBeginLoc(),
4759 diag::err_builtin_invalid_arg_type)
4760 << 1 << /* scalar or vector of */ 5 << /* unsigned int */ 3
4761 << /* no fp */ 0 << TheCall->getArg(0)->getType();
4762 return true;
4763 }
4764
4765 SetElementTypeAsReturnType(&SemaRef, TheCall, getASTContext().FloatTy);
4766 break;
4767 }
4768 case Builtin::BI__builtin_hlsl_elementwise_f32tof16: {
4769 if (SemaRef.checkArgCount(TheCall, 1))
4770 return true;
4772 return true;
4774 getASTContext().UnsignedIntTy);
4775 break;
4776 }
4777 }
4778 return false;
4779}
4780
4784 WorkList.push_back(BaseTy);
4785 while (!WorkList.empty()) {
4786 QualType T = WorkList.pop_back_val();
4787 T = T.getCanonicalType().getUnqualifiedType();
4788 if (const auto *AT = dyn_cast<ConstantArrayType>(T)) {
4789 llvm::SmallVector<QualType, 16> ElementFields;
4790 // Generally I've avoided recursion in this algorithm, but arrays of
4791 // structs could be time-consuming to flatten and churn through on the
4792 // work list. Hopefully nesting arrays of structs containing arrays
4793 // of structs too many levels deep is unlikely.
4794 BuildFlattenedTypeList(AT->getElementType(), ElementFields);
4795 // Repeat the element's field list n times.
4796 for (uint64_t Ct = 0; Ct < AT->getZExtSize(); ++Ct)
4797 llvm::append_range(List, ElementFields);
4798 continue;
4799 }
4800 // Vectors can only have element types that are builtin types, so this can
4801 // add directly to the list instead of to the WorkList.
4802 if (const auto *VT = dyn_cast<VectorType>(T)) {
4803 List.insert(List.end(), VT->getNumElements(), VT->getElementType());
4804 continue;
4805 }
4806 if (const auto *MT = dyn_cast<ConstantMatrixType>(T)) {
4807 List.insert(List.end(), MT->getNumElementsFlattened(),
4808 MT->getElementType());
4809 continue;
4810 }
4811 if (const auto *RD = T->getAsCXXRecordDecl()) {
4812 if (RD->isStandardLayout())
4813 RD = RD->getStandardLayoutBaseWithFields();
4814
4815 // For types that we shouldn't decompose (unions and non-aggregates), just
4816 // add the type itself to the list.
4817 if (RD->isUnion() || !RD->isAggregate()) {
4818 List.push_back(T);
4819 continue;
4820 }
4821
4823 for (const auto *FD : RD->fields())
4824 if (!FD->isUnnamedBitField())
4825 FieldTypes.push_back(FD->getType());
4826 // Reverse the newly added sub-range.
4827 std::reverse(FieldTypes.begin(), FieldTypes.end());
4828 llvm::append_range(WorkList, FieldTypes);
4829
4830 // If this wasn't a standard layout type we may also have some base
4831 // classes to deal with.
4832 if (!RD->isStandardLayout()) {
4833 FieldTypes.clear();
4834 for (const auto &Base : RD->bases())
4835 FieldTypes.push_back(Base.getType());
4836 std::reverse(FieldTypes.begin(), FieldTypes.end());
4837 llvm::append_range(WorkList, FieldTypes);
4838 }
4839 continue;
4840 }
4841 List.push_back(T);
4842 }
4843}
4844
4846 if (QT.isNull())
4847 return false;
4848
4849 // Must be a class/struct.
4850 const auto *RD = QT->getAsCXXRecordDecl();
4851 if (!RD || RD->isUnion())
4852 return false;
4853
4854 // Cannot be a resource type or contain one.
4855 return !QT->isHLSLIntangibleType();
4856}
4857
4859 // null and array types are not allowed.
4860 if (QT.isNull() || QT->isArrayType())
4861 return false;
4862
4863 // UDT types are not allowed
4864 if (QT->isRecordType())
4865 return false;
4866
4867 if (QT->isBooleanType() || QT->isEnumeralType())
4868 return false;
4869
4870 // the only other valid builtin types are scalars or vectors
4871 if (QT->isArithmeticType()) {
4872 if (SemaRef.Context.getTypeSize(QT) / 8 > 16)
4873 return false;
4874 return true;
4875 }
4876
4877 if (const VectorType *VT = QT->getAs<VectorType>()) {
4878 int ArraySize = VT->getNumElements();
4879
4880 if (ArraySize > 4)
4881 return false;
4882
4883 QualType ElTy = VT->getElementType();
4884 if (ElTy->isBooleanType())
4885 return false;
4886
4887 if (SemaRef.Context.getTypeSize(QT) / 8 > 16)
4888 return false;
4889 return true;
4890 }
4891
4892 return false;
4893}
4894
4896 if (T1.isNull() || T2.isNull())
4897 return false;
4898
4901
4902 // If both types are the same canonical type, they're obviously compatible.
4903 if (SemaRef.getASTContext().hasSameType(T1, T2))
4904 return true;
4905
4907 BuildFlattenedTypeList(T1, T1Types);
4909 BuildFlattenedTypeList(T2, T2Types);
4910
4911 // Check the flattened type list
4912 return llvm::equal(T1Types, T2Types,
4913 [this](QualType LHS, QualType RHS) -> bool {
4914 return SemaRef.IsLayoutCompatible(LHS, RHS);
4915 });
4916}
4917
4919 FunctionDecl *Old) {
4920 if (New->getNumParams() != Old->getNumParams())
4921 return true;
4922
4923 bool HadError = false;
4924
4925 for (unsigned i = 0, e = New->getNumParams(); i != e; ++i) {
4926 ParmVarDecl *NewParam = New->getParamDecl(i);
4927 ParmVarDecl *OldParam = Old->getParamDecl(i);
4928
4929 // HLSL parameter declarations for inout and out must match between
4930 // declarations. In HLSL inout and out are ambiguous at the call site,
4931 // but have different calling behavior, so you cannot overload a
4932 // method based on a difference between inout and out annotations.
4933 const auto *NDAttr = NewParam->getAttr<HLSLParamModifierAttr>();
4934 unsigned NSpellingIdx = (NDAttr ? NDAttr->getSpellingListIndex() : 0);
4935 const auto *ODAttr = OldParam->getAttr<HLSLParamModifierAttr>();
4936 unsigned OSpellingIdx = (ODAttr ? ODAttr->getSpellingListIndex() : 0);
4937
4938 if (NSpellingIdx != OSpellingIdx) {
4939 SemaRef.Diag(NewParam->getLocation(),
4940 diag::err_hlsl_param_qualifier_mismatch)
4941 << NDAttr << NewParam;
4942 SemaRef.Diag(OldParam->getLocation(), diag::note_previous_declaration_as)
4943 << ODAttr;
4944 HadError = true;
4945 }
4946 }
4947 return HadError;
4948}
4949
4950// Generally follows PerformScalarCast, with cases reordered for
4951// clarity of what types are supported
4953
4954 if (!SrcTy->isScalarType() || !DestTy->isScalarType())
4955 return false;
4956
4957 if (SemaRef.getASTContext().hasSameUnqualifiedType(SrcTy, DestTy))
4958 return true;
4959
4960 switch (SrcTy->getScalarTypeKind()) {
4961 case Type::STK_Bool: // casting from bool is like casting from an integer
4962 case Type::STK_Integral:
4963 switch (DestTy->getScalarTypeKind()) {
4964 case Type::STK_Bool:
4965 case Type::STK_Integral:
4966 case Type::STK_Floating:
4967 return true;
4968 case Type::STK_CPointer:
4972 llvm_unreachable("HLSL doesn't support pointers.");
4975 llvm_unreachable("HLSL doesn't support complex types.");
4977 llvm_unreachable("HLSL doesn't support fixed point types.");
4978 }
4979 llvm_unreachable("Should have returned before this");
4980
4981 case Type::STK_Floating:
4982 switch (DestTy->getScalarTypeKind()) {
4983 case Type::STK_Floating:
4984 case Type::STK_Bool:
4985 case Type::STK_Integral:
4986 return true;
4989 llvm_unreachable("HLSL doesn't support complex types.");
4991 llvm_unreachable("HLSL doesn't support fixed point types.");
4992 case Type::STK_CPointer:
4996 llvm_unreachable("HLSL doesn't support pointers.");
4997 }
4998 llvm_unreachable("Should have returned before this");
4999
5001 case Type::STK_CPointer:
5004 llvm_unreachable("HLSL doesn't support pointers.");
5005
5007 llvm_unreachable("HLSL doesn't support fixed point types.");
5008
5011 llvm_unreachable("HLSL doesn't support complex types.");
5012 }
5013
5014 llvm_unreachable("Unhandled scalar cast");
5015}
5016
5017// Can perform an HLSL Aggregate splat cast if the Dest is an aggregate and the
5018// Src is a scalar, a vector of length 1, or a 1x1 matrix
5019// Or if Dest is a vector and Src is a vector of length 1 or a 1x1 matrix
5021
5022 QualType SrcTy = Src->getType();
5023 // Not a valid HLSL Aggregate Splat cast if Dest is a scalar or if this is
5024 // going to be a vector splat from a scalar.
5025 if ((SrcTy->isScalarType() && DestTy->isVectorType()) ||
5026 DestTy->isScalarType())
5027 return false;
5028
5029 const VectorType *SrcVecTy = SrcTy->getAs<VectorType>();
5030 const ConstantMatrixType *SrcMatTy = SrcTy->getAs<ConstantMatrixType>();
5031
5032 // Src isn't a scalar, a vector of length 1, or a 1x1 matrix
5033 if (!SrcTy->isScalarType() &&
5034 !(SrcVecTy && SrcVecTy->getNumElements() == 1) &&
5035 !(SrcMatTy && SrcMatTy->getNumElementsFlattened() == 1))
5036 return false;
5037
5038 if (SrcVecTy)
5039 SrcTy = SrcVecTy->getElementType();
5040 else if (SrcMatTy)
5041 SrcTy = SrcMatTy->getElementType();
5042
5044 BuildFlattenedTypeList(DestTy, DestTypes);
5045
5046 for (unsigned I = 0, Size = DestTypes.size(); I < Size; ++I) {
5047 if (DestTypes[I]->isUnionType())
5048 return false;
5049 if (!CanPerformScalarCast(SrcTy, DestTypes[I]))
5050 return false;
5051 }
5052 return true;
5053}
5054
5055// Can we perform an HLSL Elementwise cast?
5057
5058 // Don't handle casts where LHS and RHS are any combination of scalar/vector
5059 // There must be an aggregate somewhere
5060 QualType SrcTy = Src->getType();
5061 if (SrcTy->isScalarType()) // always a splat and this cast doesn't handle that
5062 return false;
5063
5064 if (SrcTy->isVectorType() &&
5065 (DestTy->isScalarType() || DestTy->isVectorType()))
5066 return false;
5067
5068 if (SrcTy->isConstantMatrixType() &&
5069 (DestTy->isScalarType() || DestTy->isConstantMatrixType()))
5070 return false;
5071
5073 BuildFlattenedTypeList(DestTy, DestTypes);
5075 BuildFlattenedTypeList(SrcTy, SrcTypes);
5076
5077 // Usually the size of SrcTypes must be greater than or equal to the size of
5078 // DestTypes.
5079 if (SrcTypes.size() < DestTypes.size())
5080 return false;
5081
5082 unsigned SrcSize = SrcTypes.size();
5083 unsigned DstSize = DestTypes.size();
5084 unsigned I;
5085 for (I = 0; I < DstSize && I < SrcSize; I++) {
5086 if (SrcTypes[I]->isUnionType() || DestTypes[I]->isUnionType())
5087 return false;
5088 if (!CanPerformScalarCast(SrcTypes[I], DestTypes[I])) {
5089 return false;
5090 }
5091 }
5092
5093 // check the rest of the source type for unions.
5094 for (; I < SrcSize; I++) {
5095 if (SrcTypes[I]->isUnionType())
5096 return false;
5097 }
5098 return true;
5099}
5100
5102 assert(Param->hasAttr<HLSLParamModifierAttr>() &&
5103 "We should not get here without a parameter modifier expression");
5104 const auto *Attr = Param->getAttr<HLSLParamModifierAttr>();
5105 if (Attr->getABI() == ParameterABI::Ordinary)
5106 return ExprResult(Arg);
5107
5108 bool IsInOut = Attr->getABI() == ParameterABI::HLSLInOut;
5109 if (!Arg->isLValue()) {
5110 SemaRef.Diag(Arg->getBeginLoc(), diag::error_hlsl_inout_lvalue)
5111 << Arg << (IsInOut ? 1 : 0);
5112 return ExprError();
5113 }
5114
5115 ASTContext &Ctx = SemaRef.getASTContext();
5116
5117 QualType Ty = Param->getType().getNonLValueExprType(Ctx);
5118
5119 // HLSL allows implicit conversions from scalars to vectors, but not the
5120 // inverse, so we need to disallow `inout` with scalar->vector or
5121 // scalar->matrix conversions.
5122 if (Arg->getType()->isScalarType() != Ty->isScalarType()) {
5123 SemaRef.Diag(Arg->getBeginLoc(), diag::error_hlsl_inout_scalar_extension)
5124 << Arg << (IsInOut ? 1 : 0);
5125 return ExprError();
5126 }
5127
5128 auto *ArgOpV = new (Ctx) OpaqueValueExpr(Param->getBeginLoc(), Arg->getType(),
5129 VK_LValue, OK_Ordinary, Arg);
5130
5131 // Parameters are initialized via copy initialization. This allows for
5132 // overload resolution of argument constructors.
5133 InitializedEntity Entity =
5135 ExprResult Res =
5136 SemaRef.PerformCopyInitialization(Entity, Param->getBeginLoc(), ArgOpV);
5137 if (Res.isInvalid())
5138 return ExprError();
5139 Expr *Base = Res.get();
5140 // After the cast, drop the reference type when creating the exprs.
5141 Ty = Ty.getNonLValueExprType(Ctx);
5142 auto *OpV = new (Ctx)
5143 OpaqueValueExpr(Param->getBeginLoc(), Ty, VK_LValue, OK_Ordinary, Base);
5144
5145 // Writebacks are performed with `=` binary operator, which allows for
5146 // overload resolution on writeback result expressions.
5147 Res = SemaRef.ActOnBinOp(SemaRef.getCurScope(), Param->getBeginLoc(),
5148 tok::equal, ArgOpV, OpV);
5149
5150 if (Res.isInvalid())
5151 return ExprError();
5152 Expr *Writeback = Res.get();
5153 auto *OutExpr =
5154 HLSLOutArgExpr::Create(Ctx, Ty, ArgOpV, OpV, Writeback, IsInOut);
5155
5156 return ExprResult(OutExpr);
5157}
5158
5160 // If HLSL gains support for references, all the cites that use this will need
5161 // to be updated with semantic checking to produce errors for
5162 // pointers/references.
5163 assert(!Ty->isReferenceType() &&
5164 "Pointer and reference types cannot be inout or out parameters");
5165 Ty = SemaRef.getASTContext().getLValueReferenceType(Ty);
5166 Ty.addRestrict();
5167 return Ty;
5168}
5169
5170// Returns true if the type has a non-empty constant buffer layout (if it is
5171// scalar, vector or matrix, or if it contains any of these.
5173 const Type *Ty = QT->getUnqualifiedDesugaredType();
5174 if (Ty->isScalarType() || Ty->isVectorType() || Ty->isMatrixType())
5175 return true;
5176
5178 return false;
5179
5180 if (const auto *RD = Ty->getAsCXXRecordDecl()) {
5181 for (const auto *FD : RD->fields()) {
5183 return true;
5184 }
5185 assert(RD->getNumBases() <= 1 &&
5186 "HLSL doesn't support multiple inheritance");
5187 return RD->getNumBases()
5188 ? hasConstantBufferLayout(RD->bases_begin()->getType())
5189 : false;
5190 }
5191
5192 if (const auto *AT = dyn_cast<ArrayType>(Ty)) {
5193 if (const auto *CAT = dyn_cast<ConstantArrayType>(AT))
5194 if (isZeroSizedArray(CAT))
5195 return false;
5197 }
5198
5199 return false;
5200}
5201
5202static bool IsDefaultBufferConstantDecl(const ASTContext &Ctx, VarDecl *VD) {
5203 bool IsVulkan =
5204 Ctx.getTargetInfo().getTriple().getOS() == llvm::Triple::Vulkan;
5205 bool IsVKPushConstant = IsVulkan && VD->hasAttr<HLSLVkPushConstantAttr>();
5206 QualType QT = VD->getType();
5207 return VD->getDeclContext()->isTranslationUnit() &&
5208 QT.getAddressSpace() == LangAS::Default &&
5209 VD->getStorageClass() != SC_Static &&
5210 !VD->hasAttr<HLSLVkConstantIdAttr>() && !IsVKPushConstant &&
5212}
5213
5215 // The variable already has an address space (groupshared for ex).
5216 if (Decl->getType().hasAddressSpace())
5217 return;
5218
5219 if (Decl->getType()->isDependentType())
5220 return;
5221
5222 QualType Type = Decl->getType();
5223
5224 if (Decl->hasAttr<HLSLVkExtBuiltinInputAttr>()) {
5225 LangAS ImplAS = LangAS::hlsl_input;
5226 Type = SemaRef.getASTContext().getAddrSpaceQualType(Type, ImplAS);
5227 Decl->setType(Type);
5228 return;
5229 }
5230
5231 if (Decl->hasAttr<HLSLVkExtBuiltinOutputAttr>()) {
5232 LangAS ImplAS = LangAS::hlsl_output;
5233 Type = SemaRef.getASTContext().getAddrSpaceQualType(Type, ImplAS);
5234 Decl->setType(Type);
5235
5236 // HLSL uses `static` differently than C++. For BuiltIn output, the static
5237 // does not imply private to the module scope.
5238 // Marking it as external to reflect the semantic this attribute brings.
5239 // See https://github.com/microsoft/hlsl-specs/issues/350
5240 Decl->setStorageClass(SC_Extern);
5241 return;
5242 }
5243
5244 bool IsVulkan = getASTContext().getTargetInfo().getTriple().getOS() ==
5245 llvm::Triple::Vulkan;
5246 if (IsVulkan && Decl->hasAttr<HLSLVkPushConstantAttr>()) {
5247 if (HasDeclaredAPushConstant)
5248 SemaRef.Diag(Decl->getLocation(), diag::err_hlsl_push_constant_unique);
5249
5251 Type = SemaRef.getASTContext().getAddrSpaceQualType(Type, ImplAS);
5252 Decl->setType(Type);
5253 HasDeclaredAPushConstant = true;
5254 return;
5255 }
5256
5257 if (Type->isSamplerT() || Type->isVoidType())
5258 return;
5259
5260 // Resource handles.
5262 return;
5263
5264 // Only static globals belong to the Private address space.
5265 // Non-static globals belongs to the cbuffer.
5266 if (Decl->getStorageClass() != SC_Static && !Decl->isStaticDataMember())
5267 return;
5268
5270 Type = SemaRef.getASTContext().getAddrSpaceQualType(Type, ImplAS);
5271 Decl->setType(Type);
5272}
5273
5274namespace {
5275
5276// Helper class for assigning bindings to resources declared within a struct.
5277// It keeps track of all binding attributes declared on a struct instance, and
5278// the offsets for each register type that have been assigned so far.
5279// Handles both explicit and implicit bindings.
5280class StructBindingContext {
5281 // Bindings and offsets per register type. We only need to support four
5282 // register types - SRV (u), UAV (t), CBuffer (c), and Sampler (s).
5283 HLSLResourceBindingAttr *RegBindingsAttrs[4];
5284 unsigned RegBindingOffset[4];
5285
5286 // Make sure the RegisterType values are what we expect
5287 static_assert(static_cast<unsigned>(RegisterType::SRV) == 0 &&
5288 static_cast<unsigned>(RegisterType::UAV) == 1 &&
5289 static_cast<unsigned>(RegisterType::CBuffer) == 2 &&
5290 static_cast<unsigned>(RegisterType::Sampler) == 3,
5291 "unexpected register type values");
5292
5293 // Vulkan binding attribute does not vary by register type.
5294 HLSLVkBindingAttr *VkBindingAttr;
5295 unsigned VkBindingOffset;
5296
5297public:
5298 // Constructor: gather all binding attributes on a struct instance and
5299 // initialize offsets.
5300 StructBindingContext(VarDecl *VD) {
5301 for (unsigned i = 0; i < 4; ++i) {
5302 RegBindingsAttrs[i] = nullptr;
5303 RegBindingOffset[i] = 0;
5304 }
5305 VkBindingAttr = nullptr;
5306 VkBindingOffset = 0;
5307
5308 ASTContext &AST = VD->getASTContext();
5309 bool IsSpirv = AST.getTargetInfo().getTriple().isSPIRV();
5310
5311 for (Attr *A : VD->attrs()) {
5312 if (auto *RBA = dyn_cast<HLSLResourceBindingAttr>(A)) {
5313 RegisterType RegType = RBA->getRegisterType();
5314 unsigned RegTypeIdx = static_cast<unsigned>(RegType);
5315 // Ignore unsupported register annotations, such as 'c' or 'i'.
5316 if (RegTypeIdx < 4)
5317 RegBindingsAttrs[RegTypeIdx] = RBA;
5318 continue;
5319 }
5320 // Gather the Vulkan binding attributes only if the target is SPIR-V.
5321 if (IsSpirv) {
5322 if (auto *VBA = dyn_cast<HLSLVkBindingAttr>(A))
5323 VkBindingAttr = VBA;
5324 }
5325 }
5326 }
5327
5328 // Creates a binding attribute for a resource based on the gathered attributes
5329 // and the required register type and range.
5330 Attr *createBindingAttr(SemaHLSL &S, ASTContext &AST, RegisterType RegType,
5331 unsigned Range, bool HasCounter) {
5332 assert(static_cast<unsigned>(RegType) < 4 && "unexpected register type");
5333
5334 if (VkBindingAttr) {
5335 unsigned Offset = VkBindingOffset;
5336 VkBindingOffset += Range;
5337 return HLSLVkBindingAttr::CreateImplicit(
5338 AST, VkBindingAttr->getBinding() + Offset, VkBindingAttr->getSet(),
5339 VkBindingAttr->getRange());
5340 }
5341
5342 HLSLResourceBindingAttr *RBA =
5343 RegBindingsAttrs[static_cast<unsigned>(RegType)];
5344 HLSLResourceBindingAttr *NewAttr = nullptr;
5345
5346 if (RBA && RBA->hasRegisterSlot()) {
5347 // Explicit binding - create a new attribute with offseted slot number
5348 // based on the required register type.
5349 unsigned Offset = RegBindingOffset[static_cast<unsigned>(RegType)];
5350 RegBindingOffset[static_cast<unsigned>(RegType)] += Range;
5351
5352 unsigned NewSlotNumber = RBA->getSlotNumber() + Offset;
5353 StringRef NewSlotNumberStr =
5354 createRegisterString(AST, RBA->getRegisterType(), NewSlotNumber);
5355 NewAttr = HLSLResourceBindingAttr::CreateImplicit(
5356 AST, NewSlotNumberStr, RBA->getSpace(), RBA->getRange());
5357 NewAttr->setBinding(RegType, NewSlotNumber, RBA->getSpaceNumber());
5358 } else {
5359 // No binding attribute or space-only binding - create a binding
5360 // attribute for implicit binding.
5361 NewAttr = HLSLResourceBindingAttr::CreateImplicit(AST, "", "0", {});
5362 NewAttr->setBinding(RegType, std::nullopt,
5363 RBA ? RBA->getSpaceNumber() : 0);
5364 NewAttr->setImplicitBindingOrderID(S.getNextImplicitBindingOrderID());
5365 }
5366 if (HasCounter)
5367 NewAttr->setImplicitCounterBindingOrderID(
5369 return NewAttr;
5370 }
5371};
5372
5373// Creates a global variable declaration for a resource field embedded in a
5374// struct, assigns it a binding, initializes it, and associates it with the
5375// struct declaration via an HLSLAssociatedResourceDeclAttr.
5376static void createGlobalResourceDeclForStruct(
5377 Sema &S, VarDecl *ParentVD, SourceLocation Loc, IdentifierInfo *Id,
5378 QualType ResTy, StructBindingContext &BindingCtx) {
5379 assert(isResourceRecordTypeOrArrayOf(ResTy) &&
5380 "expected resource type or array of resources");
5381
5382 DeclContext *DC = ParentVD->getNonTransparentDeclContext();
5383 assert(DC->isTranslationUnit() && "expected translation unit decl context");
5384
5385 ASTContext &AST = S.getASTContext();
5386 VarDecl *ResDecl =
5387 VarDecl::Create(AST, DC, Loc, Loc, Id, ResTy, nullptr, SC_None);
5388
5389 unsigned Range = 1;
5390 const Type *SingleResTy = ResTy.getTypePtr()->getUnqualifiedDesugaredType();
5391 while (const auto *AT = dyn_cast<ArrayType>(SingleResTy)) {
5392 const auto *CAT = dyn_cast<ConstantArrayType>(AT);
5393 Range = CAT ? (Range * CAT->getSize().getZExtValue()) : 0;
5394 SingleResTy =
5396 }
5397 const HLSLAttributedResourceType *ResHandleTy =
5398 HLSLAttributedResourceType::findHandleTypeOnResource(SingleResTy);
5399
5400 // Add a binding attribute to the global resource declaration.
5401 bool HasCounter = hasCounterHandle(SingleResTy->getAsCXXRecordDecl());
5402 Attr *BindingAttr = BindingCtx.createBindingAttr(
5403 S.HLSL(), AST, getRegisterType(ResHandleTy), Range, HasCounter);
5404 ResDecl->addAttr(BindingAttr);
5405 ResDecl->addAttr(InternalLinkageAttr::CreateImplicit(AST));
5406 ResDecl->setImplicit();
5407
5408 if (Range == 1)
5409 S.HLSL().initGlobalResourceDecl(ResDecl);
5410 else
5411 S.HLSL().initGlobalResourceArrayDecl(ResDecl);
5412
5413 ParentVD->addAttr(
5414 HLSLAssociatedResourceDeclAttr::CreateImplicit(AST, ResDecl));
5415 DC->addDecl(ResDecl);
5416
5417 DeclGroupRef DG(ResDecl);
5419}
5420
5421static void handleArrayOfStructWithResources(
5422 Sema &S, VarDecl *ParentVD, const ConstantArrayType *CAT,
5423 EmbeddedResourceNameBuilder &NameBuilder, StructBindingContext &BindingCtx);
5424
5425// Scans base and all fields of a struct/class type to find all embedded
5426// resources or resource arrays. Creates a global variable for each resource
5427// found.
5428static void handleStructWithResources(Sema &S, VarDecl *ParentVD,
5429 const CXXRecordDecl *RD,
5430 EmbeddedResourceNameBuilder &NameBuilder,
5431 StructBindingContext &BindingCtx) {
5432
5433 // Scan the base classes.
5434 assert(RD->getNumBases() <= 1 && "HLSL doesn't support multiple inheritance");
5435 const auto *BasesIt = RD->bases_begin();
5436 if (BasesIt != RD->bases_end()) {
5437 QualType QT = BasesIt->getType();
5438 if (QT->isHLSLIntangibleType()) {
5439 CXXRecordDecl *BaseRD = QT->getAsCXXRecordDecl();
5440 NameBuilder.pushBaseName(BaseRD->getName());
5441 handleStructWithResources(S, ParentVD, BaseRD, NameBuilder, BindingCtx);
5442 NameBuilder.pop();
5443 }
5444 }
5445 // Process this class fields.
5446 for (const FieldDecl *FD : RD->fields()) {
5447 QualType FDTy = FD->getType().getCanonicalType();
5448 if (!FDTy->isHLSLIntangibleType())
5449 continue;
5450
5451 NameBuilder.pushName(FD->getName());
5452
5454 IdentifierInfo *II = NameBuilder.getNameAsIdentifier(S.getASTContext());
5455 createGlobalResourceDeclForStruct(S, ParentVD, FD->getLocation(), II,
5456 FDTy, BindingCtx);
5457 } else if (const auto *RD = FDTy->getAsCXXRecordDecl()) {
5458 handleStructWithResources(S, ParentVD, RD, NameBuilder, BindingCtx);
5459
5460 } else if (const auto *ArrayTy = dyn_cast<ConstantArrayType>(FDTy)) {
5461 assert(!FDTy->isHLSLResourceRecordArray() &&
5462 "resource arrays should have been already handled");
5463 handleArrayOfStructWithResources(S, ParentVD, ArrayTy, NameBuilder,
5464 BindingCtx);
5465 }
5466 NameBuilder.pop();
5467 }
5468}
5469
5470// Processes array of structs with resources.
5471static void
5472handleArrayOfStructWithResources(Sema &S, VarDecl *ParentVD,
5473 const ConstantArrayType *CAT,
5474 EmbeddedResourceNameBuilder &NameBuilder,
5475 StructBindingContext &BindingCtx) {
5476
5477 QualType ElementTy = CAT->getElementType().getCanonicalType();
5478 assert(ElementTy->isHLSLIntangibleType() && "Expected HLSL intangible type");
5479
5480 const ConstantArrayType *SubCAT = dyn_cast<ConstantArrayType>(ElementTy);
5481 const CXXRecordDecl *ElementRD = ElementTy->getAsCXXRecordDecl();
5482
5483 if (!SubCAT && !ElementRD)
5484 return;
5485
5486 for (unsigned I = 0, E = CAT->getSize().getZExtValue(); I < E; ++I) {
5487 NameBuilder.pushArrayIndex(I);
5488 if (ElementRD)
5489 handleStructWithResources(S, ParentVD, ElementRD, NameBuilder,
5490 BindingCtx);
5491 else
5492 handleArrayOfStructWithResources(S, ParentVD, SubCAT, NameBuilder,
5493 BindingCtx);
5494 NameBuilder.pop();
5495 }
5496}
5497
5498} // namespace
5499
5500// Scans all fields of a user-defined struct (or array of structs)
5501// to find all embedded resources or resource arrays. For each resource
5502// a global variable of the resource type is created and associated
5503// with the parent declaration (VD) through a HLSLAssociatedResourceDeclAttr
5504// attribute.
5505void SemaHLSL::handleGlobalStructOrArrayOfWithResources(VarDecl *VD) {
5506 EmbeddedResourceNameBuilder NameBuilder(VD->getName());
5507 StructBindingContext BindingCtx(VD);
5508
5509 const Type *VDTy = VD->getType().getTypePtr();
5510 assert(VDTy->isHLSLIntangibleType() && !isResourceRecordTypeOrArrayOf(VD) &&
5511 "Expected non-resource struct or array type");
5512
5513 if (const CXXRecordDecl *RD = VDTy->getAsCXXRecordDecl()) {
5514 handleStructWithResources(SemaRef, VD, RD, NameBuilder, BindingCtx);
5515 return;
5516 }
5517
5518 if (const auto *CAT = dyn_cast<ConstantArrayType>(VDTy)) {
5519 handleArrayOfStructWithResources(SemaRef, VD, CAT, NameBuilder, BindingCtx);
5520 return;
5521 }
5522}
5523
5525 if (VD->hasGlobalStorage()) {
5526 // make sure the declaration has a complete type
5527 if (SemaRef.RequireCompleteType(
5528 VD->getLocation(),
5529 SemaRef.getASTContext().getBaseElementType(VD->getType()),
5530 diag::err_typecheck_decl_incomplete_type)) {
5531 VD->setInvalidDecl();
5533 return;
5534 }
5535
5536 // Global variables outside a cbuffer block that are not a resource, static,
5537 // groupshared, or an empty array or struct belong to the default constant
5538 // buffer $Globals (to be created at the end of the translation unit).
5540 // update address space to hlsl_constant
5543 VD->setType(NewTy);
5544 DefaultCBufferDecls.push_back(VD);
5545 }
5546
5547 // find all resources bindings on decl
5548 if (VD->getType()->isHLSLIntangibleType())
5549 collectResourceBindingsOnVarDecl(VD);
5550
5551 if (VD->hasAttr<HLSLVkConstantIdAttr>())
5553
5555 VD->getStorageClass() != SC_Static) {
5556 // Add internal linkage attribute to non-static resource variables. The
5557 // global externally visible storage is accessed through the handle, which
5558 // is a member. The variable itself is not externally visible.
5559 VD->addAttr(InternalLinkageAttr::CreateImplicit(getASTContext()));
5560 }
5561
5562 // process explicit bindings
5563 processExplicitBindingsOnDecl(VD);
5564
5565 // Add implicit binding attribute to non-static resource arrays.
5566 if (VD->getType()->isHLSLResourceRecordArray() &&
5567 VD->getStorageClass() != SC_Static) {
5568 // If the resource array does not have an explicit binding attribute,
5569 // create an implicit one. It will be used to transfer implicit binding
5570 // order_ID to codegen.
5571 ResourceBindingAttrs Binding(VD);
5572 if (!Binding.isExplicit()) {
5573 uint32_t OrderID = getNextImplicitBindingOrderID();
5574 if (Binding.hasBinding())
5575 Binding.setImplicitOrderID(OrderID);
5576 else {
5579 OrderID);
5580 // Re-create the binding object to pick up the new attribute.
5581 Binding = ResourceBindingAttrs(VD);
5582 }
5583 }
5584
5585 // Get to the base type of a potentially multi-dimensional array.
5587
5588 const CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
5589 if (hasCounterHandle(RD)) {
5590 if (!Binding.hasCounterImplicitOrderID()) {
5591 uint32_t OrderID = getNextImplicitBindingOrderID();
5592 Binding.setCounterImplicitOrderID(OrderID);
5593 }
5594 }
5595 }
5596
5597 // Process resources in user-defined structs, or arrays of such structs.
5598 const Type *VDTy = VD->getType().getTypePtr();
5599 if (VD->getStorageClass() != SC_Static && VDTy->isHLSLIntangibleType() &&
5601 handleGlobalStructOrArrayOfWithResources(VD);
5602
5603 // Mark groupshared variables as extern so they will have
5604 // external storage and won't be default initialized
5605 if (VD->hasAttr<HLSLGroupSharedAddressSpaceAttr>())
5607 }
5608
5610}
5611
5613 assert(VD->getType()->isHLSLResourceRecord() &&
5614 "expected resource record type");
5615
5616 ASTContext &AST = SemaRef.getASTContext();
5617 uint64_t UIntTySize = AST.getTypeSize(AST.UnsignedIntTy);
5618 uint64_t IntTySize = AST.getTypeSize(AST.IntTy);
5619
5620 // Gather resource binding attributes.
5621 ResourceBindingAttrs Binding(VD);
5622
5623 // Find correct initialization method and create its arguments.
5624 QualType ResourceTy = VD->getType();
5625 CXXRecordDecl *ResourceDecl = ResourceTy->getAsCXXRecordDecl();
5626 CXXMethodDecl *CreateMethod = nullptr;
5628
5629 bool HasCounter = hasCounterHandle(ResourceDecl);
5630 const char *CreateMethodName;
5631 if (Binding.isExplicit())
5632 CreateMethodName = HasCounter ? "__createFromBindingWithImplicitCounter"
5633 : "__createFromBinding";
5634 else
5635 CreateMethodName = HasCounter
5636 ? "__createFromImplicitBindingWithImplicitCounter"
5637 : "__createFromImplicitBinding";
5638
5639 CreateMethod =
5640 lookupMethod(SemaRef, ResourceDecl, CreateMethodName, VD->getLocation());
5641
5642 if (!CreateMethod) {
5643 // This can happen if someone creates a struct that looks like an HLSL
5644 // resource record but does not have the required static create method.
5645 // No binding will be generated for it.
5646 assert(!ResourceDecl->isImplicit() &&
5647 "create method lookup should always succeed for built-in resource "
5648 "records");
5649 return false;
5650 }
5651
5652 if (Binding.isExplicit()) {
5653 IntegerLiteral *RegSlot =
5654 IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, Binding.getSlot()),
5656 Args.push_back(RegSlot);
5657 } else {
5658 uint32_t OrderID = (Binding.hasImplicitOrderID())
5659 ? Binding.getImplicitOrderID()
5661 IntegerLiteral *OrderId =
5662 IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, OrderID),
5664 Args.push_back(OrderId);
5665 }
5666
5667 IntegerLiteral *Space =
5668 IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, Binding.getSpace()),
5670 Args.push_back(Space);
5671
5673 AST, llvm::APInt(IntTySize, 1), AST.IntTy, SourceLocation());
5674 Args.push_back(RangeSize);
5675
5677 AST, llvm::APInt(UIntTySize, 0), AST.UnsignedIntTy, SourceLocation());
5678 Args.push_back(Index);
5679
5680 StringRef VarName = VD->getName();
5682 AST, VarName, StringLiteralKind::Ordinary, false,
5683 AST.getStringLiteralArrayType(AST.CharTy.withConst(), VarName.size()),
5684 SourceLocation());
5686 AST, AST.getPointerType(AST.CharTy.withConst()), CK_ArrayToPointerDecay,
5687 Name, nullptr, VK_PRValue, FPOptionsOverride());
5688 Args.push_back(NameCast);
5689
5690 if (HasCounter) {
5691 // Will this be in the correct order?
5692 uint32_t CounterOrderID = getNextImplicitBindingOrderID();
5693 IntegerLiteral *CounterId =
5694 IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, CounterOrderID),
5696 Args.push_back(CounterId);
5697 }
5698
5699 // Make sure the create method template is instantiated and emitted.
5700 if (!CreateMethod->isDefined() && CreateMethod->isTemplateInstantiation())
5701 SemaRef.InstantiateFunctionDefinition(VD->getLocation(), CreateMethod,
5702 true);
5703
5704 // Create CallExpr with a call to the static method and set it as the decl
5705 // initialization.
5707 AST, NestedNameSpecifierLoc(), SourceLocation(), CreateMethod, false,
5708 CreateMethod->getNameInfo(), CreateMethod->getType(), VK_PRValue);
5709
5710 auto *ImpCast = ImplicitCastExpr::Create(
5711 AST, AST.getPointerType(CreateMethod->getType()),
5712 CK_FunctionToPointerDecay, DRE, nullptr, VK_PRValue, FPOptionsOverride());
5713
5714 CallExpr *InitExpr =
5715 CallExpr::Create(AST, ImpCast, Args, ResourceTy, VK_PRValue,
5717 VD->setInit(InitExpr);
5719 SemaRef.CheckCompleteVariableDeclaration(VD);
5720 return true;
5721}
5722
5724 assert(VD->getType()->isHLSLResourceRecordArray() &&
5725 "expected array of resource records");
5726
5727 // Individual resources in a resource array are not initialized here. They
5728 // are initialized later on during codegen when the individual resources are
5729 // accessed. Codegen will emit a call to the resource initialization method
5730 // with the specified array index. We need to make sure though that the method
5731 // for the specific resource type is instantiated, so codegen can emit a call
5732 // to it when the array element is accessed.
5733
5734 // Find correct initialization method based on the resource binding
5735 // information.
5736 ASTContext &AST = SemaRef.getASTContext();
5737 QualType ResElementTy = AST.getBaseElementType(VD->getType());
5738 CXXRecordDecl *ResourceDecl = ResElementTy->getAsCXXRecordDecl();
5739 CXXMethodDecl *CreateMethod = nullptr;
5740
5741 bool HasCounter = hasCounterHandle(ResourceDecl);
5742 ResourceBindingAttrs ResourceAttrs(VD);
5743 if (ResourceAttrs.isExplicit())
5744 // Resource has explicit binding.
5745 CreateMethod =
5746 lookupMethod(SemaRef, ResourceDecl,
5747 HasCounter ? "__createFromBindingWithImplicitCounter"
5748 : "__createFromBinding",
5749 VD->getLocation());
5750 else
5751 // Resource has implicit binding.
5752 CreateMethod = lookupMethod(
5753 SemaRef, ResourceDecl,
5754 HasCounter ? "__createFromImplicitBindingWithImplicitCounter"
5755 : "__createFromImplicitBinding",
5756 VD->getLocation());
5757
5758 if (!CreateMethod)
5759 return false;
5760
5761 // Make sure the create method template is instantiated and emitted.
5762 if (!CreateMethod->isDefined() && CreateMethod->isTemplateInstantiation())
5763 SemaRef.InstantiateFunctionDefinition(VD->getLocation(), CreateMethod,
5764 true);
5765 return true;
5766}
5767
5768// Returns true if the initialization has been handled.
5769// Returns false to use default initialization.
5771 // Objects in the hlsl_constant address space are initialized
5772 // externally, so don't synthesize an implicit initializer.
5774 return true;
5775
5776 if (VD->hasGlobalStorage() && VD->getStorageClass() != SC_Static) {
5777 const Type *Ty = VD->getType().getTypePtr();
5779 return true;
5781 return true;
5782 }
5783
5784 // User-defined structs/classes do not have constructors.
5785 // When declared at a global scope, they are part of the constant buffer
5786 // and should not be initialized by the compiler.
5787 // When declared at a local scope, they are not initialized.
5788 // Also applies to arrays of user-defined structs/classes.
5789 const Type *Ty = VD->getType()->getUnqualifiedDesugaredType();
5790 while (Ty->isArrayType())
5792 if (CXXRecordDecl *RD = Ty->getAsCXXRecordDecl())
5793 return !RD->isHLSLBuiltinRecord();
5794
5795 return false;
5796}
5797
5798std::optional<const DeclBindingInfo *> SemaHLSL::inferGlobalBinding(Expr *E) {
5799 if (auto *Ternary = dyn_cast<ConditionalOperator>(E)) {
5800 auto TrueInfo = inferGlobalBinding(Ternary->getTrueExpr());
5801 auto FalseInfo = inferGlobalBinding(Ternary->getFalseExpr());
5802 if (!TrueInfo || !FalseInfo)
5803 return std::nullopt;
5804 if (*TrueInfo != *FalseInfo)
5805 return std::nullopt;
5806 return TrueInfo;
5807 }
5808
5809 if (auto *ASE = dyn_cast<ArraySubscriptExpr>(E))
5810 E = ASE->getBase()->IgnoreParenImpCasts();
5811
5812 if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParens()))
5813 if (VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
5814 const Type *Ty = VD->getType()->getUnqualifiedDesugaredType();
5815 if (Ty->isArrayType())
5817
5818 if (const auto *AttrResType =
5819 HLSLAttributedResourceType::findHandleTypeOnResource(Ty)) {
5820 ResourceClass RC = AttrResType->getAttrs().ResourceClass;
5821 return Bindings.getDeclBindingInfo(VD, RC);
5822 }
5823 }
5824
5825 return nullptr;
5826}
5827
5828void SemaHLSL::trackLocalResource(VarDecl *VD, Expr *E) {
5829 std::optional<const DeclBindingInfo *> ExprBinding = inferGlobalBinding(E);
5830 if (!ExprBinding) {
5831 SemaRef.Diag(E->getBeginLoc(),
5832 diag::warn_hlsl_assigning_local_resource_is_not_unique)
5833 << E << VD;
5834 return; // Expr use multiple resources
5835 }
5836
5837 if (*ExprBinding == nullptr)
5838 return; // No binding could be inferred to track, return without error
5839
5840 auto PrevBinding = Assigns.find(VD);
5841 if (PrevBinding == Assigns.end()) {
5842 // No previous binding recorded, simply record the new assignment
5843 Assigns.insert({VD, *ExprBinding});
5844 return;
5845 }
5846
5847 // Otherwise, warn if the assignment implies different resource bindings
5848 if (*ExprBinding != PrevBinding->second) {
5849 SemaRef.Diag(E->getBeginLoc(),
5850 diag::warn_hlsl_assigning_local_resource_is_not_unique)
5851 << E << VD;
5852 SemaRef.Diag(VD->getLocation(), diag::note_var_declared_here) << VD;
5853 return;
5854 }
5855
5856 return;
5857}
5858
5860 Expr *RHSExpr, SourceLocation Loc) {
5861 assert((LHSExpr->getType()->isHLSLResourceRecord() ||
5862 LHSExpr->getType()->isHLSLResourceRecordArray()) &&
5863 "expected LHS to be a resource record or array of resource records");
5864 if (Opc != BO_Assign)
5865 return true;
5866
5867 // If LHS is an array subscript, get the underlying declaration.
5868 Expr *E = LHSExpr;
5869 while (auto *ASE = dyn_cast<ArraySubscriptExpr>(E))
5870 E = ASE->getBase()->IgnoreParenImpCasts();
5871
5872 // Report error if LHS is a non-static resource declared at a global scope.
5873 if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParens())) {
5874 if (VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
5875 if (VD->hasGlobalStorage() && VD->getStorageClass() != SC_Static) {
5876 // assignment to global resource is not allowed
5877 SemaRef.Diag(Loc, diag::err_hlsl_assign_to_global_resource) << VD;
5878 SemaRef.Diag(VD->getLocation(), diag::note_var_declared_here) << VD;
5879 return false;
5880 }
5881
5882 trackLocalResource(VD, RHSExpr);
5883 }
5884 }
5885 return true;
5886}
5887
5888// Returns true if the given type can have an overload of the given
5889// binary operator.
5891 CXXRecordDecl *RD = LHSTy->getAsCXXRecordDecl();
5892 if (!RD)
5893 return true;
5894 return RD->isHLSLBuiltinRecord() || Opc != BO_Assign;
5895}
5896
5897// Walks though the global variable declaration, collects all resource binding
5898// requirements and adds them to Bindings
5899void SemaHLSL::collectResourceBindingsOnVarDecl(VarDecl *VD) {
5900 assert(VD->hasGlobalStorage() && VD->getType()->isHLSLIntangibleType() &&
5901 "expected global variable that contains HLSL resource");
5902
5903 // Cbuffers and Tbuffers are HLSLBufferDecl types
5904 if (const HLSLBufferDecl *CBufferOrTBuffer = dyn_cast<HLSLBufferDecl>(VD)) {
5905 Bindings.addDeclBindingInfo(VD, CBufferOrTBuffer->isCBuffer()
5906 ? ResourceClass::CBuffer
5907 : ResourceClass::SRV);
5908 return;
5909 }
5910
5911 // Unwrap arrays
5912 // FIXME: Calculate array size while unwrapping
5913 const Type *Ty = VD->getType()->getUnqualifiedDesugaredType();
5914 while (Ty->isArrayType()) {
5915 const ArrayType *AT = cast<ArrayType>(Ty);
5917 }
5918
5919 // Resource (or array of resources)
5920 if (const HLSLAttributedResourceType *AttrResType =
5921 HLSLAttributedResourceType::findHandleTypeOnResource(Ty)) {
5922 Bindings.addDeclBindingInfo(VD, AttrResType->getAttrs().ResourceClass);
5923 return;
5924 }
5925
5926 // User defined record type
5927 if (const RecordType *RT = dyn_cast<RecordType>(Ty))
5928 collectResourceBindingsOnUserRecordDecl(VD, RT);
5929}
5930
5931// Walks though the explicit resource binding attributes on the declaration,
5932// and makes sure there is a resource that matched the binding and updates
5933// DeclBindingInfoLists
5934void SemaHLSL::processExplicitBindingsOnDecl(VarDecl *VD) {
5935 assert(VD->hasGlobalStorage() && "expected global variable");
5936
5937 bool HasBinding = false;
5938 for (Attr *A : VD->attrs()) {
5939 if (isa<HLSLVkBindingAttr>(A)) {
5940 HasBinding = true;
5941 if (auto PA = VD->getAttr<HLSLVkPushConstantAttr>())
5942 Diag(PA->getLoc(), diag::err_hlsl_attr_incompatible) << A << PA;
5943 }
5944
5945 HLSLResourceBindingAttr *RBA = dyn_cast<HLSLResourceBindingAttr>(A);
5946 if (!RBA || !RBA->hasRegisterSlot())
5947 continue;
5948 HasBinding = true;
5949
5950 RegisterType RT = RBA->getRegisterType();
5951 assert(RT != RegisterType::I && "invalid or obsolete register type should "
5952 "never have an attribute created");
5953
5954 if (RT == RegisterType::C) {
5955 if (Bindings.hasBindingInfoForDecl(VD))
5956 SemaRef.Diag(VD->getLocation(),
5957 diag::warn_hlsl_user_defined_type_missing_member)
5958 << static_cast<int>(RT);
5959 continue;
5960 }
5961
5962 // Find DeclBindingInfo for this binding and update it, or report error
5963 // if it does not exist (user type does to contain resources with the
5964 // expected resource class).
5966 if (DeclBindingInfo *BI = Bindings.getDeclBindingInfo(VD, RC)) {
5967 // update binding info
5968 BI->setBindingAttribute(RBA, BindingType::Explicit);
5969 } else {
5970 SemaRef.Diag(VD->getLocation(),
5971 diag::warn_hlsl_user_defined_type_missing_member)
5972 << static_cast<int>(RT);
5973 }
5974 }
5975
5976 if (!HasBinding && isResourceRecordTypeOrArrayOf(VD))
5977 SemaRef.Diag(VD->getLocation(), diag::warn_hlsl_implicit_binding);
5978}
5979namespace {
5980class InitListTransformer {
5981 Sema &S;
5982 ASTContext &Ctx;
5983 QualType InitTy;
5984 QualType *DstIt = nullptr;
5985 Expr **ArgIt = nullptr;
5986 // Is wrapping the destination type iterator required? This is only used for
5987 // incomplete array types where we loop over the destination type since we
5988 // don't know the full number of elements from the declaration.
5989 bool Wrap;
5990
5991 bool castInitializer(Expr *E) {
5992 assert(DstIt && "This should always be something!");
5993 if (DstIt == DestTypes.end()) {
5994 if (!Wrap) {
5995 ArgExprs.push_back(E);
5996 // This is odd, but it isn't technically a failure due to conversion, we
5997 // handle mismatched counts of arguments differently.
5998 return true;
5999 }
6000 DstIt = DestTypes.begin();
6001 }
6002 InitializedEntity Entity = InitializedEntity::InitializeParameter(
6003 Ctx, *DstIt, /* Consumed (ObjC) */ false);
6004 ExprResult Res = S.PerformCopyInitialization(Entity, E->getBeginLoc(), E);
6005 if (Res.isInvalid())
6006 return false;
6007 Expr *Init = Res.get();
6008 ArgExprs.push_back(Init);
6009 DstIt++;
6010 return true;
6011 }
6012
6013 bool buildInitializerListImpl(Expr *E) {
6014 // If this is an initialization list, traverse the sub initializers.
6015 if (auto *Init = dyn_cast<InitListExpr>(E)) {
6016 for (auto *SubInit : Init->inits())
6017 if (!buildInitializerListImpl(SubInit))
6018 return false;
6019 return true;
6020 }
6021
6022 // If this is a scalar type, just enqueue the expression.
6023 QualType Ty = E->getType().getDesugaredType(Ctx);
6024
6025 if (Ty->isScalarType() || (Ty->isRecordType() && !Ty->isAggregateType()) ||
6027 return castInitializer(E);
6028
6029 // If this is an aggregate type and a prvalue, create an xvalue temporary
6030 // so the member accesses will be xvalues. Wrap it in OpaqueExpr to make
6031 // sure codegen will not generate duplicate copies.
6032 if (E->isPRValue() && Ty->isAggregateType()) {
6034 if (TmpExpr.isInvalid())
6035 return false;
6036 E = TmpExpr.get();
6037 E = new (Ctx) OpaqueValueExpr(E->getBeginLoc(), E->getType(),
6038 E->getValueKind(), E->getObjectKind(), E);
6039 }
6040
6041 if (auto *VecTy = Ty->getAs<VectorType>()) {
6042 uint64_t Size = VecTy->getNumElements();
6043
6044 QualType SizeTy = Ctx.getSizeType();
6045 uint64_t SizeTySize = Ctx.getTypeSize(SizeTy);
6046 for (uint64_t I = 0; I < Size; ++I) {
6047 auto *Idx = IntegerLiteral::Create(Ctx, llvm::APInt(SizeTySize, I),
6048 SizeTy, SourceLocation());
6049
6051 E, E->getBeginLoc(), Idx, E->getEndLoc());
6052 if (ElExpr.isInvalid())
6053 return false;
6054 if (!castInitializer(ElExpr.get()))
6055 return false;
6056 }
6057 return true;
6058 }
6059 if (auto *MTy = Ty->getAs<ConstantMatrixType>()) {
6060 unsigned Rows = MTy->getNumRows();
6061 unsigned Cols = MTy->getNumColumns();
6062 QualType ElemTy = MTy->getElementType();
6063
6064 for (unsigned R = 0; R < Rows; ++R) {
6065 for (unsigned C = 0; C < Cols; ++C) {
6066 // row index literal
6067 Expr *RowIdx = IntegerLiteral::Create(
6068 Ctx, llvm::APInt(Ctx.getIntWidth(Ctx.IntTy), R), Ctx.IntTy,
6069 E->getBeginLoc());
6070 // column index literal
6071 Expr *ColIdx = IntegerLiteral::Create(
6072 Ctx, llvm::APInt(Ctx.getIntWidth(Ctx.IntTy), C), Ctx.IntTy,
6073 E->getBeginLoc());
6075 E, RowIdx, ColIdx, E->getEndLoc());
6076 if (ElExpr.isInvalid())
6077 return false;
6078 if (!castInitializer(ElExpr.get()))
6079 return false;
6080 ElExpr.get()->setType(ElemTy);
6081 }
6082 }
6083 return true;
6084 }
6085
6086 if (auto *ArrTy = dyn_cast<ConstantArrayType>(Ty.getTypePtr())) {
6087 uint64_t Size = ArrTy->getZExtSize();
6088 QualType SizeTy = Ctx.getSizeType();
6089 uint64_t SizeTySize = Ctx.getTypeSize(SizeTy);
6090 for (uint64_t I = 0; I < Size; ++I) {
6091 auto *Idx = IntegerLiteral::Create(Ctx, llvm::APInt(SizeTySize, I),
6092 SizeTy, SourceLocation());
6094 E, E->getBeginLoc(), Idx, E->getEndLoc());
6095 if (ElExpr.isInvalid())
6096 return false;
6097 if (!buildInitializerListImpl(ElExpr.get()))
6098 return false;
6099 }
6100 return true;
6101 }
6102
6103 if (auto *RD = Ty->getAsCXXRecordDecl()) {
6104 llvm::SmallVector<CXXRecordDecl *> RecordDecls;
6105 RecordDecls.push_back(RD);
6106 while (RecordDecls.back()->getNumBases()) {
6107 CXXRecordDecl *D = RecordDecls.back();
6108 assert(D->getNumBases() == 1 &&
6109 "HLSL doesn't support multiple inheritance");
6110 RecordDecls.push_back(
6112 }
6113 while (!RecordDecls.empty()) {
6114 CXXRecordDecl *RD = RecordDecls.pop_back_val();
6115 for (auto *FD : RD->fields()) {
6116 if (FD->isUnnamedBitField())
6117 continue;
6118 DeclAccessPair Found = DeclAccessPair::make(FD, FD->getAccess());
6119 DeclarationNameInfo NameInfo(FD->getDeclName(), E->getBeginLoc());
6121 E, false, E->getBeginLoc(), CXXScopeSpec(), FD, Found, NameInfo);
6122 if (Res.isInvalid())
6123 return false;
6124 if (!buildInitializerListImpl(Res.get()))
6125 return false;
6126 }
6127 }
6128 }
6129 return true;
6130 }
6131
6132 Expr *generateInitListsImpl(QualType Ty) {
6133 Ty = Ty.getDesugaredType(Ctx);
6134 assert(ArgIt != ArgExprs.end() && "Something is off in iteration!");
6135 if (Ty->isScalarType() || (Ty->isRecordType() && !Ty->isAggregateType()) ||
6137 return *(ArgIt++);
6138
6139 llvm::SmallVector<Expr *> Inits;
6140 if (Ty->isVectorType() || Ty->isConstantArrayType() ||
6141 Ty->isConstantMatrixType()) {
6142 QualType ElTy;
6143 uint64_t Size = 0;
6144 if (auto *ATy = Ty->getAs<VectorType>()) {
6145 ElTy = ATy->getElementType();
6146 Size = ATy->getNumElements();
6147 } else if (auto *CMTy = Ty->getAs<ConstantMatrixType>()) {
6148 ElTy = CMTy->getElementType();
6149 Size = CMTy->getNumElementsFlattened();
6150 } else {
6151 auto *VTy = cast<ConstantArrayType>(Ty.getTypePtr());
6152 ElTy = VTy->getElementType();
6153 Size = VTy->getZExtSize();
6154 }
6155 for (uint64_t I = 0; I < Size; ++I)
6156 Inits.push_back(generateInitListsImpl(ElTy));
6157 }
6158 if (auto *RD = Ty->getAsCXXRecordDecl()) {
6159 llvm::SmallVector<CXXRecordDecl *> RecordDecls;
6160 RecordDecls.push_back(RD);
6161 while (RecordDecls.back()->getNumBases()) {
6162 CXXRecordDecl *D = RecordDecls.back();
6163 assert(D->getNumBases() == 1 &&
6164 "HLSL doesn't support multiple inheritance");
6165 RecordDecls.push_back(
6167 }
6168 while (!RecordDecls.empty()) {
6169 CXXRecordDecl *RD = RecordDecls.pop_back_val();
6170 for (auto *FD : RD->fields())
6171 if (!FD->isUnnamedBitField())
6172 Inits.push_back(generateInitListsImpl(FD->getType()));
6173 }
6174 }
6175 auto *NewInit =
6176 new (Ctx) InitListExpr(Ctx, Inits.front()->getBeginLoc(), Inits,
6177 Inits.back()->getEndLoc(), /*isExplicit=*/false);
6178 NewInit->setType(Ty);
6179 return NewInit;
6180 }
6181
6182public:
6183 llvm::SmallVector<QualType, 16> DestTypes;
6184 llvm::SmallVector<Expr *, 16> ArgExprs;
6185 InitListTransformer(Sema &SemaRef, const InitializedEntity &Entity)
6186 : S(SemaRef), Ctx(SemaRef.getASTContext()),
6187 Wrap(Entity.getType()->isIncompleteArrayType()) {
6188 InitTy = Entity.getType().getNonReferenceType();
6189 // When we're generating initializer lists for incomplete array types we
6190 // need to wrap around both when building the initializers and when
6191 // generating the final initializer lists.
6192 if (Wrap) {
6193 assert(InitTy->isIncompleteArrayType());
6194 const IncompleteArrayType *IAT = Ctx.getAsIncompleteArrayType(InitTy);
6195 InitTy = IAT->getElementType();
6196 }
6197 BuildFlattenedTypeList(InitTy, DestTypes);
6198 DstIt = DestTypes.begin();
6199 }
6200
6201 bool buildInitializerList(Expr *E) { return buildInitializerListImpl(E); }
6202
6203 Expr *generateInitLists() {
6204 assert(!ArgExprs.empty() &&
6205 "Call buildInitializerList to generate argument expressions.");
6206 ArgIt = ArgExprs.begin();
6207 if (!Wrap)
6208 return generateInitListsImpl(InitTy);
6209 llvm::SmallVector<Expr *> Inits;
6210 while (ArgIt != ArgExprs.end())
6211 Inits.push_back(generateInitListsImpl(InitTy));
6212
6213 auto *NewInit =
6214 new (Ctx) InitListExpr(Ctx, Inits.front()->getBeginLoc(), Inits,
6215 Inits.back()->getEndLoc(), /*isExplicit=*/false);
6216 llvm::APInt ArySize(64, Inits.size());
6217 NewInit->setType(Ctx.getConstantArrayType(InitTy, ArySize, nullptr,
6218 ArraySizeModifier::Normal, 0));
6219 return NewInit;
6220 }
6221};
6222} // namespace
6223
6224// Recursively detect any incomplete array anywhere in the type graph,
6225// including arrays, struct fields, and base classes.
6227 Ty = Ty.getCanonicalType();
6228
6229 // Array types
6230 if (const ArrayType *AT = dyn_cast<ArrayType>(Ty)) {
6232 return true;
6234 }
6235
6236 // Record (struct/class) types
6237 if (const auto *RT = Ty->getAs<RecordType>()) {
6238 const RecordDecl *RD = RT->getDecl();
6239
6240 // Walk base classes (for C++ / HLSL structs with inheritance)
6241 if (const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
6242 for (const CXXBaseSpecifier &Base : CXXRD->bases()) {
6243 if (containsIncompleteArrayType(Base.getType()))
6244 return true;
6245 }
6246 }
6247
6248 // Walk fields
6249 for (const FieldDecl *F : RD->fields()) {
6250 if (containsIncompleteArrayType(F->getType()))
6251 return true;
6252 }
6253 }
6254
6255 return false;
6256}
6257
6259 InitListExpr *Init) {
6260 // If the initializer is a scalar, just return it.
6261 if (Init->getType()->isScalarType())
6262 return true;
6263 ASTContext &Ctx = SemaRef.getASTContext();
6264 InitListTransformer ILT(SemaRef, Entity);
6265
6266 for (unsigned I = 0; I < Init->getNumInits(); ++I) {
6267 Expr *E = Init->getInit(I);
6268 if (E->HasSideEffects(Ctx)) {
6269 QualType Ty = E->getType();
6270 if (Ty->isRecordType())
6271 E = new (Ctx) MaterializeTemporaryExpr(Ty, E, E->isLValue());
6272 E = new (Ctx) OpaqueValueExpr(E->getBeginLoc(), Ty, E->getValueKind(),
6273 E->getObjectKind(), E);
6274 Init->setInit(I, E);
6275 }
6276 if (!ILT.buildInitializerList(E))
6277 return false;
6278 }
6279 size_t ExpectedSize = ILT.DestTypes.size();
6280 size_t ActualSize = ILT.ArgExprs.size();
6281 if (ExpectedSize == 0 && ActualSize == 0)
6282 return true;
6283
6284 // Reject empty initializer if *any* incomplete array exists structurally
6285 if (ActualSize == 0 && containsIncompleteArrayType(Entity.getType())) {
6286 QualType InitTy = Entity.getType().getNonReferenceType();
6287 if (InitTy.hasAddressSpace())
6288 InitTy = SemaRef.getASTContext().removeAddrSpaceQualType(InitTy);
6289
6290 SemaRef.Diag(Init->getBeginLoc(), diag::err_hlsl_incorrect_num_initializers)
6291 << /*TooManyOrFew=*/(int)(ExpectedSize < ActualSize) << InitTy
6292 << /*ExpectedSize=*/ExpectedSize << /*ActualSize=*/ActualSize;
6293 return false;
6294 }
6295
6296 // We infer size after validating legality.
6297 // For incomplete arrays it is completely arbitrary to choose whether we think
6298 // the user intended fewer or more elements. This implementation assumes that
6299 // the user intended more, and errors that there are too few initializers to
6300 // complete the final element.
6301 if (Entity.getType()->isIncompleteArrayType()) {
6302 assert(ExpectedSize > 0 &&
6303 "The expected size of an incomplete array type must be at least 1.");
6304 ExpectedSize =
6305 ((ActualSize + ExpectedSize - 1) / ExpectedSize) * ExpectedSize;
6306 }
6307
6308 // An initializer list might be attempting to initialize a reference or
6309 // rvalue-reference. When checking the initializer we should look through
6310 // the reference.
6311 QualType InitTy = Entity.getType().getNonReferenceType();
6312 if (InitTy.hasAddressSpace())
6313 InitTy = SemaRef.getASTContext().removeAddrSpaceQualType(InitTy);
6314 if (ExpectedSize != ActualSize) {
6315 int TooManyOrFew = ActualSize > ExpectedSize ? 1 : 0;
6316 SemaRef.Diag(Init->getBeginLoc(), diag::err_hlsl_incorrect_num_initializers)
6317 << TooManyOrFew << InitTy << ExpectedSize << ActualSize;
6318 return false;
6319 }
6320
6321 // generateInitListsImpl will always return an InitListExpr here, because the
6322 // scalar case is handled above.
6323 auto *NewInit = cast<InitListExpr>(ILT.generateInitLists());
6324 Init->resizeInits(Ctx, NewInit->getNumInits());
6325 for (unsigned I = 0; I < NewInit->getNumInits(); ++I)
6326 Init->updateInit(Ctx, I, NewInit->getInit(I));
6327 return true;
6328}
6329
6330static QualType ReportMatrixInvalidMember(Sema &S, StringRef Name,
6331 StringRef Expected,
6332 SourceLocation OpLoc,
6333 SourceLocation CompLoc) {
6334 S.Diag(OpLoc, diag::err_builtin_matrix_invalid_member)
6335 << Name << Expected << SourceRange(CompLoc);
6336 return QualType();
6337}
6338
6341 const IdentifierInfo *CompName,
6342 SourceLocation CompLoc) {
6343 const auto *MT = baseType->castAs<ConstantMatrixType>();
6344 StringRef AccessorName = CompName->getName();
6345 assert(!AccessorName.empty() && "Matrix Accessor must have a name");
6346
6347 unsigned Rows = MT->getNumRows();
6348 unsigned Cols = MT->getNumColumns();
6349 bool IsZeroBasedAccessor = false;
6350 unsigned ChunkLen = 0;
6351 if (AccessorName.size() < 2)
6352 return ReportMatrixInvalidMember(S, AccessorName,
6353 "length 4 for zero based: \'_mRC\' or "
6354 "length 3 for one-based: \'_RC\' accessor",
6355 OpLoc, CompLoc);
6356
6357 if (AccessorName[0] == '_') {
6358 if (AccessorName[1] == 'm') {
6359 IsZeroBasedAccessor = true;
6360 ChunkLen = 4; // zero-based: "_mRC"
6361 } else {
6362 ChunkLen = 3; // one-based: "_RC"
6363 }
6364 } else
6366 S, AccessorName, "zero based: \'_mRC\' or one-based: \'_RC\' accessor",
6367 OpLoc, CompLoc);
6368
6369 if (AccessorName.size() % ChunkLen != 0) {
6370 const llvm::StringRef Expected = IsZeroBasedAccessor
6371 ? "zero based: '_mRC' accessor"
6372 : "one-based: '_RC' accessor";
6373
6374 return ReportMatrixInvalidMember(S, AccessorName, Expected, OpLoc, CompLoc);
6375 }
6376
6377 auto isDigit = [](char c) { return c >= '0' && c <= '9'; };
6378 auto isZeroBasedIndex = [](unsigned i) { return i <= 3; };
6379 auto isOneBasedIndex = [](unsigned i) { return i >= 1 && i <= 4; };
6380
6381 bool HasRepeated = false;
6382 SmallVector<bool, 16> Seen(Rows * Cols, false);
6383 unsigned NumComponents = 0;
6384 const char *Begin = AccessorName.data();
6385
6386 for (unsigned I = 0, E = AccessorName.size(); I < E; I += ChunkLen) {
6387 const char *Chunk = Begin + I;
6388 char RowChar = 0, ColChar = 0;
6389 if (IsZeroBasedAccessor) {
6390 // Zero-based: "_mRC"
6391 if (Chunk[0] != '_' || Chunk[1] != 'm') {
6392 char Bad = (Chunk[0] != '_') ? Chunk[0] : Chunk[1];
6394 S, StringRef(&Bad, 1), "\'_m\' prefix",
6395 OpLoc.getLocWithOffset(I + (Bad == Chunk[0] ? 1 : 2)), CompLoc);
6396 }
6397 RowChar = Chunk[2];
6398 ColChar = Chunk[3];
6399 } else {
6400 // One-based: "_RC"
6401 if (Chunk[0] != '_')
6403 S, StringRef(&Chunk[0], 1), "\'_\' prefix",
6404 OpLoc.getLocWithOffset(I + 1), CompLoc);
6405 RowChar = Chunk[1];
6406 ColChar = Chunk[2];
6407 }
6408
6409 // Must be digits.
6410 bool IsDigitsError = false;
6411 if (!isDigit(RowChar)) {
6412 unsigned BadPos = IsZeroBasedAccessor ? 2 : 1;
6413 ReportMatrixInvalidMember(S, StringRef(&RowChar, 1), "row as integer",
6414 OpLoc.getLocWithOffset(I + BadPos + 1),
6415 CompLoc);
6416 IsDigitsError = true;
6417 }
6418
6419 if (!isDigit(ColChar)) {
6420 unsigned BadPos = IsZeroBasedAccessor ? 3 : 2;
6421 ReportMatrixInvalidMember(S, StringRef(&ColChar, 1), "column as integer",
6422 OpLoc.getLocWithOffset(I + BadPos + 1),
6423 CompLoc);
6424 IsDigitsError = true;
6425 }
6426 if (IsDigitsError)
6427 return QualType();
6428
6429 unsigned Row = RowChar - '0';
6430 unsigned Col = ColChar - '0';
6431
6432 bool HasIndexingError = false;
6433 if (IsZeroBasedAccessor) {
6434 // 0-based [0..3]
6435 if (!isZeroBasedIndex(Row)) {
6436 S.Diag(OpLoc, diag::err_hlsl_matrix_element_not_in_bounds)
6437 << /*row*/ 0 << /*zero-based*/ 0 << SourceRange(CompLoc);
6438 HasIndexingError = true;
6439 }
6440 if (!isZeroBasedIndex(Col)) {
6441 S.Diag(OpLoc, diag::err_hlsl_matrix_element_not_in_bounds)
6442 << /*col*/ 1 << /*zero-based*/ 0 << SourceRange(CompLoc);
6443 HasIndexingError = true;
6444 }
6445 } else {
6446 // 1-based [1..4]
6447 if (!isOneBasedIndex(Row)) {
6448 S.Diag(OpLoc, diag::err_hlsl_matrix_element_not_in_bounds)
6449 << /*row*/ 0 << /*one-based*/ 1 << SourceRange(CompLoc);
6450 HasIndexingError = true;
6451 }
6452 if (!isOneBasedIndex(Col)) {
6453 S.Diag(OpLoc, diag::err_hlsl_matrix_element_not_in_bounds)
6454 << /*col*/ 1 << /*one-based*/ 1 << SourceRange(CompLoc);
6455 HasIndexingError = true;
6456 }
6457 // Convert to 0-based after range checking.
6458 --Row;
6459 --Col;
6460 }
6461
6462 if (HasIndexingError)
6463 return QualType();
6464
6465 // Note: matrix swizzle index is hard coded. That means Row and Col can
6466 // potentially be larger than Rows and Cols if matrix size is less than
6467 // the max index size.
6468 bool HasBoundsError = false;
6469 if (Row >= Rows) {
6470 Diag(OpLoc, diag::err_hlsl_matrix_index_out_of_bounds)
6471 << /*Row*/ 0 << Row << Rows << SourceRange(CompLoc);
6472 HasBoundsError = true;
6473 }
6474 if (Col >= Cols) {
6475 Diag(OpLoc, diag::err_hlsl_matrix_index_out_of_bounds)
6476 << /*Col*/ 1 << Col << Cols << SourceRange(CompLoc);
6477 HasBoundsError = true;
6478 }
6479 if (HasBoundsError)
6480 return QualType();
6481
6482 unsigned FlatIndex = Row * Cols + Col;
6483 if (Seen[FlatIndex])
6484 HasRepeated = true;
6485 Seen[FlatIndex] = true;
6486 ++NumComponents;
6487 }
6488 if (NumComponents == 0 || NumComponents > 4) {
6489 S.Diag(OpLoc, diag::err_hlsl_matrix_swizzle_invalid_length)
6490 << NumComponents << SourceRange(CompLoc);
6491 return QualType();
6492 }
6493
6494 QualType ElemTy = MT->getElementType();
6495 if (NumComponents == 1)
6496 return ElemTy;
6497 QualType VT = S.Context.getExtVectorType(ElemTy, NumComponents);
6498 if (HasRepeated)
6499 VK = VK_PRValue;
6500
6501 for (Sema::ExtVectorDeclsType::iterator
6503 E = S.ExtVectorDecls.end();
6504 I != E; ++I) {
6505 if ((*I)->getUnderlyingType() == VT)
6507 /*Qualifier=*/std::nullopt, *I);
6508 }
6509
6510 return VT;
6511}
6512
6514 // If initializing a local resource, track the resource binding it is using
6515 if (VDecl->getType()->isHLSLResourceRecord() && !VDecl->hasGlobalStorage())
6516 trackLocalResource(VDecl, Init);
6517
6518 const HLSLVkConstantIdAttr *ConstIdAttr =
6519 VDecl->getAttr<HLSLVkConstantIdAttr>();
6520 if (!ConstIdAttr)
6521 return true;
6522
6523 ASTContext &Context = SemaRef.getASTContext();
6524
6525 APValue InitValue;
6526 if (!Init->isCXX11ConstantExpr(Context, &InitValue)) {
6527 Diag(VDecl->getLocation(), diag::err_specialization_const);
6528 VDecl->setInvalidDecl();
6529 return false;
6530 }
6531
6532 Builtin::ID BID =
6534
6535 // Argument 1: The ID from the attribute
6536 int ConstantID = ConstIdAttr->getId();
6537 llvm::APInt IDVal(Context.getIntWidth(Context.IntTy), ConstantID);
6538 Expr *IdExpr = IntegerLiteral::Create(Context, IDVal, Context.IntTy,
6539 ConstIdAttr->getLocation());
6540
6541 SmallVector<Expr *, 2> Args = {IdExpr, Init};
6542 Expr *C = SemaRef.BuildBuiltinCallExpr(Init->getExprLoc(), BID, Args);
6543 if (C->getType()->getCanonicalTypeUnqualified() !=
6545 C = SemaRef
6546 .BuildCStyleCastExpr(SourceLocation(),
6547 Context.getTrivialTypeSourceInfo(
6548 Init->getType(), Init->getExprLoc()),
6549 SourceLocation(), C)
6550 .get();
6551 }
6552 Init = C;
6553 return true;
6554}
6555
6557 SourceLocation NameLoc) {
6558 if (!Template)
6559 return QualType();
6560
6561 DeclContext *DC = Template->getDeclContext();
6562 if (!DC->isNamespace() || !cast<NamespaceDecl>(DC)->getIdentifier() ||
6563 cast<NamespaceDecl>(DC)->getName() != "hlsl")
6564 return QualType();
6565
6566 TemplateParameterList *Params = Template->getTemplateParameters();
6567 if (!Params || Params->size() != 1)
6568 return QualType();
6569
6570 if (!Template->isImplicit())
6571 return QualType();
6572
6573 // We manually extract default arguments here instead of letting
6574 // CheckTemplateIdType handle it. This ensures that for resource types that
6575 // lack a default argument (like Buffer), we return a null QualType, which
6576 // triggers the "requires template arguments" error rather than a less
6577 // descriptive "too few template arguments" error.
6578 TemplateArgumentListInfo TemplateArgs(NameLoc, NameLoc);
6579 for (NamedDecl *P : *Params) {
6580 if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(P)) {
6581 if (TTP->hasDefaultArgument()) {
6582 TemplateArgs.addArgument(TTP->getDefaultArgument());
6583 continue;
6584 }
6585 } else if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P)) {
6586 if (NTTP->hasDefaultArgument()) {
6587 TemplateArgs.addArgument(NTTP->getDefaultArgument());
6588 continue;
6589 }
6590 } else if (auto *TTPD = dyn_cast<TemplateTemplateParmDecl>(P)) {
6591 if (TTPD->hasDefaultArgument()) {
6592 TemplateArgs.addArgument(TTPD->getDefaultArgument());
6593 continue;
6594 }
6595 }
6596 return QualType();
6597 }
6598
6599 return SemaRef.CheckTemplateIdType(
6601 TemplateArgs, nullptr, /*ForNestedNameSpecifier=*/false);
6602}
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 isLayoutAdaptingMatrixBuiltin(unsigned BuiltinID)
static bool CheckSamplingBuiltin(Sema &S, CallExpr *TheCall, SampleKind Kind)
static bool CheckScalarOrVectorOrMatrix(Sema *S, CallExpr *TheCall, QualType Scalar, unsigned ArgIndex)
static bool CheckFloatRepresentation(Sema *S, SourceLocation Loc, int ArgOrdinal, clang::QualType PassedType)
static bool CheckAnyDoubleRepresentation(Sema *S, SourceLocation Loc, int ArgOrdinal, clang::QualType PassedType)
static bool requiresImplicitBufferLayoutStructure(const CXXRecordDecl *RD)
Definition SemaHLSL.cpp: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:3786
QualType getElementType() const
Definition TypeBase.h:3798
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:2145
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:1561
static CXXRecordDecl * Create(const ASTContext &C, TagKind TK, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, CXXRecordDecl *PrevDecl=nullptr)
Definition DeclCXX.cpp:133
void setBases(CXXBaseSpecifier const *const *Bases, unsigned NumBases)
Sets the base classes of this struct or class.
Definition DeclCXX.cpp:185
base_class_iterator bases_end()
Definition DeclCXX.h:617
void completeDefinition() override
Indicates that the definition of this class is now complete.
Definition DeclCXX.cpp:2245
base_class_range bases()
Definition DeclCXX.h:608
unsigned getNumBases() const
Retrieves the number of base classes of this class.
Definition DeclCXX.h:602
bool isHLSLBuiltinRecord() const
Returns true if the class is a built-in HLSL record.
Definition DeclCXX.h:1564
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:1191
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:3824
bool isZeroSize() const
Return true if the size is zero.
Definition TypeBase.h:3894
llvm::APInt getSize() const
Return the constant array size as an APInt.
Definition TypeBase.h:3880
uint64_t getZExtSize() const
Return the size zero-extended as a uint64_t.
Definition TypeBase.h:3900
Represents a concrete matrix type with constant number of rows and columns.
Definition TypeBase.h:4451
unsigned getNumColumns() const
Returns the number of columns in the matrix.
Definition TypeBase.h:4470
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:3099
Expr * IgnoreParens() LLVM_READONLY
Skip past any parentheses which might surround this expression until reaching a fixed point.
Definition Expr.cpp:3095
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:3083
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:3697
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:4331
Represents difference between two FPOptions values.
Represents a member of a struct/union/class.
Definition Decl.h:3182
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:4694
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:2815
Stmt * getBody(const FunctionDecl *&Definition) const
Retrieve the body (definition) of the function.
Definition Decl.cpp:3253
bool isThisDeclarationADefinition() const
Returns whether this specific declaration of the function is also a definition that does not contain ...
Definition Decl.h:2332
QualType getReturnType() const
Definition Decl.h:2863
ArrayRef< ParmVarDecl * > parameters() const
Definition Decl.h:2792
bool isTemplateInstantiation() const
Determines if the given function was instantiated from a function template.
Definition Decl.cpp:4231
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:3800
DeclarationNameInfo getNameInfo() const
Definition Decl.h:2229
bool hasBody(const FunctionDecl *&Definition) const
Returns true if the function has a body.
Definition Decl.cpp:3173
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:3220
HLSLBufferDecl - Represent a cbuffer or tbuffer declaration.
Definition Decl.h:5216
static HLSLBufferDecl * Create(ASTContext &C, DeclContext *LexicalParent, bool CBuffer, SourceLocation KwLoc, IdentifierInfo *ID, SourceLocation IDLoc, SourceLocation LBrace)
Definition Decl.cpp:5904
void addLayoutStruct(CXXRecordDecl *LS)
Definition Decl.cpp:5944
void setHasValidPackoffset(bool PO)
Definition Decl.h:5261
static HLSLBufferDecl * CreateDefaultCBuffer(ASTContext &C, DeclContext *LexicalParent, ArrayRef< Decl * > DefaultCBufferDecls)
Definition Decl.cpp:5927
buffer_decl_range buffer_decls() const
Definition Decl.h:5291
static HLSLOutArgExpr * Create(const ASTContext &C, QualType Ty, OpaqueValueExpr *Base, OpaqueValueExpr *OpV, Expr *WB, bool IsInOut)
Definition Expr.cpp:5655
static HLSLRootSignatureDecl * Create(ASTContext &C, DeclContext *DC, SourceLocation Loc, IdentifierInfo *ID, llvm::dxbc::RootSignatureVersion Version, ArrayRef< llvm::hlsl::rootsig::RootElement > RootElements)
Definition Decl.cpp:5990
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:4401
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:3682
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:8447
LangAS getAddressSpace() const
Return the address space of this type.
Definition TypeBase.h:8573
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:8632
QualType getCanonicalType() const
Definition TypeBase.h:8499
QualType getUnqualifiedType() const
Retrieve the unqualified variant of the given type, removing as little sugar as possible.
Definition TypeBase.h:8541
bool hasAddressSpace() const
Check if this type has any address space qualifier.
Definition TypeBase.h:8568
Represents a struct/union/class.
Definition Decl.h:4347
field_range fields() const
Definition Decl.h:4550
RecordDecl * getDefinitionOrSelf() const
Definition Decl.h:4535
bool field_empty() const
Definition Decl.h:4558
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:250
void CheckEntryPoint(FunctionDecl *FD)
Definition SemaHLSL.cpp:984
void handleVkExtBuiltinOutputAttr(Decl *D, const ParsedAttr &AL)
void emitLogicalOperatorFixIt(Expr *LHS, Expr *RHS, BinaryOperatorKind Opc)
void propagateContextualMatrixLayout(Expr *E, QualType DestType)
T * createSemanticAttr(const AttributeCommonInfo &ACI, std::optional< unsigned > Location)
Definition SemaHLSL.h:201
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)
bool canHaveOverloadedBinOp(QualType Ty, BinaryOperatorKind Opc)
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:4900
bool isUnion() const
Definition Decl.h:3950
bool isClass() const
Definition Decl.h:3949
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:8418
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:9050
bool isBooleanType() const
Definition TypeBase.h:9187
bool isIncompleteArrayType() const
Definition TypeBase.h:8791
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:8787
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:2119
bool isArrayType() const
Definition TypeBase.h:8783
CXXRecordDecl * castAsCXXRecordDecl() const
Definition Type.h:36
bool isArithmeticType() const
Definition Type.cpp:2422
bool isConstantMatrixType() const
Definition TypeBase.h:8851
bool isHLSLBuiltinIntangibleType() const
Definition TypeBase.h:8995
bool isPointerType() const
Definition TypeBase.h:8684
CanQualType getCanonicalTypeUnqualified() const
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
Definition TypeBase.h:9094
const T * castAs() const
Member-template castAs<specific type>.
Definition TypeBase.h:9344
bool isReferenceType() const
Definition TypeBase.h:8708
bool isHLSLIntangibleType() const
Definition Type.cpp:5523
bool isEnumeralType() const
Definition TypeBase.h:8815
bool isScalarType() const
Definition TypeBase.h:9156
bool isIntegralType(const ASTContext &Ctx) const
Determine whether this type is an integral type.
Definition Type.cpp:2156
const Type * getArrayElementTypeNoTypeQual() const
If this is an array type, return the element type of the array, potentially with type qualifiers miss...
Definition Type.cpp:508
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:789
bool hasUnsignedIntegerRepresentation() const
Determine whether this type has an unsigned integer representation of some sort, e....
Definition Type.cpp:2376
bool isDependentType() const
Whether this type is a dependent type, meaning that its definition somehow depends on a template para...
Definition TypeBase.h:2846
bool isAggregateType() const
Determines whether the type is a C++ aggregate type or C aggregate or union type.
Definition Type.cpp:2503
ScalarTypeKind getScalarTypeKind() const
Given that this is a scalar type, classify it.
Definition Type.cpp:2454
bool hasSignedIntegerRepresentation() const
Determine whether this type has an signed integer representation of some sort, e.g....
Definition Type.cpp:2310
bool isMatrixType() const
Definition TypeBase.h:8847
bool isHLSLResourceRecord() const
Definition Type.cpp:5510
bool hasFloatingRepresentation() const
Determine whether this type has a floating-point representation of some sort, e.g....
Definition Type.cpp:2397
bool isVectorType() const
Definition TypeBase.h:8823
bool isRealFloatingType() const
Floating point categories.
Definition Type.cpp:2405
bool isHLSLAttributedResourceType() const
Definition TypeBase.h:9007
@ STK_FloatingComplex
Definition TypeBase.h:2828
@ STK_ObjCObjectPointer
Definition TypeBase.h:2822
@ STK_IntegralComplex
Definition TypeBase.h:2827
@ STK_MemberPointer
Definition TypeBase.h:2823
bool isFloatingType() const
Definition Type.cpp:2389
bool isSamplerT() const
Definition TypeBase.h:8928
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9277
const Type * getUnqualifiedDesugaredType() const
Return the specified type with any "sugar" removed from the type, removing any typedefs,...
Definition Type.cpp:690
bool isRecordType() const
Definition TypeBase.h:8811
bool isHLSLResourceRecordArray() const
Definition Type.cpp:5514
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:2130
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:2142
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:2456
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:4239
unsigned getNumElements() const
Definition TypeBase.h:4254
QualType getElementType() const
Definition TypeBase.h:4253
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)
llvm::ImmutableSet< T > join(llvm::ImmutableSet< T > A, llvm::ImmutableSet< T > B, typename llvm::ImmutableSet< T >::Factory &F)
Computes the union of two ImmutableSets.
Definition Utils.h:39
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:273
@ TemplateName
The identifier is a template name. FIXME: Add an annotation for that.
Definition Parser.h:61
@ OK_Ordinary
An ordinary object is located at an address in memory.
Definition Specifiers.h:152
static bool CheckAllArgTypesAreCorrect(Sema *S, CallExpr *TheCall, llvm::ArrayRef< llvm::function_ref< bool(Sema *, SourceLocation, int, QualType)> > Checks)
Definition SemaSPIRV.cpp:49
@ AS_public
Definition Specifiers.h:125
@ AS_none
Definition Specifiers.h:128
@ SC_Extern
Definition Specifiers.h:252
@ SC_Static
Definition Specifiers.h:253
@ SC_None
Definition Specifiers.h:251
@ AANT_ArgumentIdentifier
@ Result
The result type of a method or function.
Definition TypeBase.h:905
@ Ordinary
This parameter uses ordinary ABI rules for its type.
Definition Specifiers.h:383
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:5991
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