clang 24.0.0git
SemaHLSL.cpp
Go to the documentation of this file.
1//===- SemaHLSL.cpp - Semantic Analysis for HLSL constructs ---------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8// This implements Semantic Analysis for HLSL constructs.
9//===----------------------------------------------------------------------===//
10
11#include "clang/Sema/SemaHLSL.h"
14#include "clang/AST/Attr.h"
15#include "clang/AST/Decl.h"
16#include "clang/AST/DeclBase.h"
17#include "clang/AST/DeclCXX.h"
20#include "clang/AST/Expr.h"
22#include "clang/AST/Type.h"
23#include "clang/AST/TypeBase.h"
24#include "clang/AST/TypeLoc.h"
28#include "clang/Basic/LLVM.h"
33#include "clang/Sema/Lookup.h"
35#include "clang/Sema/Sema.h"
36#include "clang/Sema/Template.h"
37#include "llvm/ADT/ArrayRef.h"
38#include "llvm/ADT/STLExtras.h"
39#include "llvm/ADT/SmallVector.h"
40#include "llvm/ADT/StringExtras.h"
41#include "llvm/ADT/StringRef.h"
42#include "llvm/ADT/Twine.h"
43#include "llvm/Frontend/HLSL/HLSLBinding.h"
44#include "llvm/Frontend/HLSL/RootSignatureValidations.h"
45#include "llvm/Support/Casting.h"
46#include "llvm/Support/DXILABI.h"
47#include "llvm/Support/ErrorHandling.h"
48#include "llvm/Support/FormatVariadic.h"
49#include "llvm/TargetParser/Triple.h"
50#include <cmath>
51#include <cstddef>
52#include <iterator>
53#include <utility>
54
55using namespace clang;
56using namespace clang::hlsl;
57using 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 (TargetInfo.getTriple().isSPIRV()) {
1028 Diag(WS->getLocation(), diag::warn_hlsl_wavesize_unsupported_spirv);
1029 } else if (Ver < VersionTuple(6, 6)) {
1030 Diag(WS->getLocation(), diag::err_hlsl_attribute_in_wrong_shader_model)
1031 << WS << "6.6";
1032 FD->setInvalidDecl();
1033 } else if (WS->getSpelledArgsCount() > 1 && Ver < VersionTuple(6, 8)) {
1034 Diag(
1035 WS->getLocation(),
1036 diag::err_hlsl_attribute_number_arguments_insufficient_shader_model)
1037 << WS << WS->getSpelledArgsCount() << "6.8";
1038 FD->setInvalidDecl();
1039 }
1040 }
1041 break;
1042 case llvm::Triple::RootSignature:
1043 llvm_unreachable("rootsig environment has no function entry point");
1044 default:
1045 llvm_unreachable("Unhandled environment in triple");
1046 }
1047
1048 SemaHLSL::SemanticContext InputSC = {};
1049 InputSC.CurrentIOType = IOType::In;
1050
1051 for (ParmVarDecl *Param : FD->parameters()) {
1052 SemanticInfo ActiveSemantic;
1053 ActiveSemantic.Semantic = Param->getAttr<HLSLParsedSemanticAttr>();
1054 if (ActiveSemantic.Semantic)
1055 ActiveSemantic.Index = ActiveSemantic.Semantic->getSemanticIndex();
1056
1057 // FIXME: Verify output semantics in parameters.
1058 if (!determineActiveSemantic(FD, Param, Param, ActiveSemantic, InputSC)) {
1059 Diag(Param->getLocation(), diag::note_previous_decl) << Param;
1060 FD->setInvalidDecl();
1061 }
1062 }
1063
1064 SemanticInfo ActiveSemantic;
1065 SemaHLSL::SemanticContext OutputSC = {};
1066 OutputSC.CurrentIOType = IOType::Out;
1067 ActiveSemantic.Semantic = FD->getAttr<HLSLParsedSemanticAttr>();
1068 if (ActiveSemantic.Semantic)
1069 ActiveSemantic.Index = ActiveSemantic.Semantic->getSemanticIndex();
1070 if (!FD->getReturnType()->isVoidType())
1071 determineActiveSemantic(FD, FD, FD, ActiveSemantic, OutputSC);
1072}
1073
1074void SemaHLSL::checkSemanticAnnotation(
1075 FunctionDecl *EntryPoint, const Decl *Param,
1076 const HLSLAppliedSemanticAttr *SemanticAttr, const SemanticContext &SC) {
1077 auto *ShaderAttr = EntryPoint->getAttr<HLSLShaderAttr>();
1078 assert(ShaderAttr && "Entry point has no shader attribute");
1079 llvm::Triple::EnvironmentType ST = ShaderAttr->getType();
1080
1081 auto SemanticName = SemanticAttr->getSemanticName().upper();
1082 if (SemanticName == "SV_DISPATCHTHREADID" ||
1083 SemanticName == "SV_GROUPINDEX" || SemanticName == "SV_GROUPTHREADID" ||
1084 SemanticName == "SV_GROUPID") {
1085
1086 if (ST != llvm::Triple::Compute)
1087 diagnoseSemanticStageMismatch(SemanticAttr, ST, SC.CurrentIOType,
1088 {{llvm::Triple::Compute, IOType::In}});
1089
1090 if (SemanticAttr->getSemanticIndex() != 0) {
1091 std::string PrettyName =
1092 "'" + SemanticAttr->getSemanticName().str() + "'";
1093 Diag(SemanticAttr->getLoc(),
1094 diag::err_hlsl_semantic_indexing_not_supported)
1095 << PrettyName;
1096 }
1097 return;
1098 }
1099
1100 if (SemanticName == "SV_POSITION") {
1101 // SV_Position can be an input or output in vertex shaders,
1102 // but only an input in pixel shaders.
1103 diagnoseSemanticStageMismatch(SemanticAttr, ST, SC.CurrentIOType,
1104 {{llvm::Triple::Vertex, IOType::InOut},
1105 {llvm::Triple::Pixel, IOType::In}});
1106 return;
1107 }
1108 if (SemanticName == "SV_VERTEXID") {
1109 diagnoseSemanticStageMismatch(SemanticAttr, ST, SC.CurrentIOType,
1110 {{llvm::Triple::Vertex, IOType::In}});
1111 return;
1112 }
1113
1114 if (SemanticName == "SV_TARGET") {
1115 diagnoseSemanticStageMismatch(SemanticAttr, ST, SC.CurrentIOType,
1116 {{llvm::Triple::Pixel, IOType::Out}});
1117 return;
1118 }
1119
1120 // FIXME: catch-all for non-implemented system semantics reaching this
1121 // location.
1122 if (SemanticAttr->getAttrName()->getName().starts_with_insensitive("SV_"))
1123 llvm_unreachable("Unknown SemanticAttr");
1124}
1125
1126void SemaHLSL::diagnoseAttrStageMismatch(
1127 const Attr *A, llvm::Triple::EnvironmentType Stage,
1128 std::initializer_list<llvm::Triple::EnvironmentType> AllowedStages) {
1129 SmallVector<StringRef, 8> StageStrings;
1130 llvm::transform(AllowedStages, std::back_inserter(StageStrings),
1131 [](llvm::Triple::EnvironmentType ST) {
1132 return StringRef(
1133 HLSLShaderAttr::ConvertEnvironmentTypeToStr(ST));
1134 });
1135 Diag(A->getLoc(), diag::err_hlsl_attr_unsupported_in_stage)
1136 << A->getAttrName() << llvm::Triple::getEnvironmentTypeName(Stage)
1137 << (AllowedStages.size() != 1) << join(StageStrings, ", ");
1138}
1139
1140void SemaHLSL::diagnoseSemanticStageMismatch(
1141 const Attr *A, llvm::Triple::EnvironmentType Stage, IOType CurrentIOType,
1142 std::initializer_list<SemanticStageInfo> Allowed) {
1143
1144 for (auto &Case : Allowed) {
1145 if (Case.Stage != Stage)
1146 continue;
1147
1148 if (CurrentIOType & Case.AllowedIOTypesMask)
1149 return;
1150
1151 SmallVector<std::string, 8> ValidCases;
1152 llvm::transform(
1153 Allowed, std::back_inserter(ValidCases), [](SemanticStageInfo Case) {
1154 SmallVector<std::string, 2> ValidType;
1155 if (Case.AllowedIOTypesMask & IOType::In)
1156 ValidType.push_back("input");
1157 if (Case.AllowedIOTypesMask & IOType::Out)
1158 ValidType.push_back("output");
1159 return std::string(
1160 HLSLShaderAttr::ConvertEnvironmentTypeToStr(Case.Stage)) +
1161 " " + join(ValidType, "/");
1162 });
1163 Diag(A->getLoc(), diag::err_hlsl_semantic_unsupported_iotype_for_stage)
1164 << A->getAttrName() << (CurrentIOType & IOType::In ? "input" : "output")
1165 << llvm::Triple::getEnvironmentTypeName(Case.Stage)
1166 << join(ValidCases, ", ");
1167 return;
1168 }
1169
1170 SmallVector<StringRef, 8> StageStrings;
1171 llvm::transform(
1172 Allowed, std::back_inserter(StageStrings), [](SemanticStageInfo Case) {
1173 return StringRef(
1174 HLSLShaderAttr::ConvertEnvironmentTypeToStr(Case.Stage));
1175 });
1176
1177 Diag(A->getLoc(), diag::err_hlsl_attr_unsupported_in_stage)
1178 << A->getAttrName() << llvm::Triple::getEnvironmentTypeName(Stage)
1179 << (Allowed.size() != 1) << join(StageStrings, ", ");
1180}
1181
1182template <CastKind Kind>
1183static void castVector(Sema &S, ExprResult &E, QualType &Ty, unsigned Sz) {
1184 if (const auto *VTy = Ty->getAs<VectorType>())
1185 Ty = VTy->getElementType();
1186 Ty = S.getASTContext().getExtVectorType(Ty, Sz);
1187 E = S.ImpCastExprToType(E.get(), Ty, Kind);
1188}
1189
1190template <CastKind Kind>
1192 E = S.ImpCastExprToType(E.get(), Ty, Kind);
1193 return Ty;
1194}
1195
1197 Sema &SemaRef, ExprResult &LHS, ExprResult &RHS, QualType LHSType,
1198 QualType RHSType, QualType LElTy, QualType RElTy, bool IsCompAssign) {
1199 bool LHSFloat = LElTy->isRealFloatingType();
1200 bool RHSFloat = RElTy->isRealFloatingType();
1201
1202 if (LHSFloat && RHSFloat) {
1203 if (IsCompAssign ||
1204 SemaRef.getASTContext().getFloatingTypeOrder(LElTy, RElTy) > 0)
1205 return castElement<CK_FloatingCast>(SemaRef, RHS, LHSType);
1206
1207 return castElement<CK_FloatingCast>(SemaRef, LHS, RHSType);
1208 }
1209
1210 if (LHSFloat)
1211 return castElement<CK_IntegralToFloating>(SemaRef, RHS, LHSType);
1212
1213 assert(RHSFloat);
1214 if (IsCompAssign)
1215 return castElement<clang::CK_FloatingToIntegral>(SemaRef, RHS, LHSType);
1216
1217 return castElement<CK_IntegralToFloating>(SemaRef, LHS, RHSType);
1218}
1219
1221 Sema &SemaRef, ExprResult &LHS, ExprResult &RHS, QualType LHSType,
1222 QualType RHSType, QualType LElTy, QualType RElTy, bool IsCompAssign) {
1223
1224 int IntOrder = SemaRef.Context.getIntegerTypeOrder(LElTy, RElTy);
1225 bool LHSSigned = LElTy->hasSignedIntegerRepresentation();
1226 bool RHSSigned = RElTy->hasSignedIntegerRepresentation();
1227 auto &Ctx = SemaRef.getASTContext();
1228
1229 // If both types have the same signedness, use the higher ranked type.
1230 if (LHSSigned == RHSSigned) {
1231 if (IsCompAssign || IntOrder >= 0)
1232 return castElement<CK_IntegralCast>(SemaRef, RHS, LHSType);
1233
1234 return castElement<CK_IntegralCast>(SemaRef, LHS, RHSType);
1235 }
1236
1237 // If the unsigned type has greater than or equal rank of the signed type, use
1238 // the unsigned type.
1239 if (IntOrder != (LHSSigned ? 1 : -1)) {
1240 if (IsCompAssign || RHSSigned)
1241 return castElement<CK_IntegralCast>(SemaRef, RHS, LHSType);
1242 return castElement<CK_IntegralCast>(SemaRef, LHS, RHSType);
1243 }
1244
1245 // At this point the signed type has higher rank than the unsigned type, which
1246 // means it will be the same size or bigger. If the signed type is bigger, it
1247 // can represent all the values of the unsigned type, so select it.
1248 if (Ctx.getIntWidth(LElTy) != Ctx.getIntWidth(RElTy)) {
1249 if (IsCompAssign || LHSSigned)
1250 return castElement<CK_IntegralCast>(SemaRef, RHS, LHSType);
1251 return castElement<CK_IntegralCast>(SemaRef, LHS, RHSType);
1252 }
1253
1254 // This is a bit of an odd duck case in HLSL. It shouldn't happen, but can due
1255 // to C/C++ leaking through. The place this happens today is long vs long
1256 // long. When arguments are vector<unsigned long, N> and vector<long long, N>,
1257 // the long long has higher rank than long even though they are the same size.
1258
1259 // If this is a compound assignment cast the right hand side to the left hand
1260 // side's type.
1261 if (IsCompAssign)
1262 return castElement<CK_IntegralCast>(SemaRef, RHS, LHSType);
1263
1264 // If this isn't a compound assignment we convert to unsigned long long.
1265 QualType ElTy = Ctx.getCorrespondingUnsignedType(LHSSigned ? LElTy : RElTy);
1266 QualType NewTy = Ctx.getExtVectorType(
1267 ElTy, RHSType->castAs<VectorType>()->getNumElements());
1268 (void)castElement<CK_IntegralCast>(SemaRef, RHS, NewTy);
1269
1270 return castElement<CK_IntegralCast>(SemaRef, LHS, NewTy);
1271}
1272
1274 QualType SrcTy) {
1275 if (DestTy->isRealFloatingType() && SrcTy->isRealFloatingType())
1276 return CK_FloatingCast;
1277 if (DestTy->isIntegralType(Ctx) && SrcTy->isIntegralType(Ctx))
1278 return CK_IntegralCast;
1279 if (DestTy->isRealFloatingType())
1280 return CK_IntegralToFloating;
1281 assert(SrcTy->isRealFloatingType() && DestTy->isIntegralType(Ctx));
1282 return CK_FloatingToIntegral;
1283}
1284
1286 QualType LHSType,
1287 QualType RHSType,
1288 bool IsCompAssign) {
1289 const auto *LVecTy = LHSType->getAs<VectorType>();
1290 const auto *RVecTy = RHSType->getAs<VectorType>();
1291 auto &Ctx = getASTContext();
1292
1293 // If the LHS is not a vector and this is a compound assignment, we truncate
1294 // the argument to a scalar then convert it to the LHS's type.
1295 if (!LVecTy && IsCompAssign) {
1296 QualType RElTy = RHSType->castAs<VectorType>()->getElementType();
1297 RHS = SemaRef.ImpCastExprToType(RHS.get(), RElTy, CK_HLSLVectorTruncation);
1298 RHSType = RHS.get()->getType();
1299 if (Ctx.hasSameUnqualifiedType(LHSType, RHSType))
1300 return LHSType;
1301 RHS = SemaRef.ImpCastExprToType(RHS.get(), LHSType,
1302 getScalarCastKind(Ctx, LHSType, RHSType));
1303 return LHSType;
1304 }
1305
1306 unsigned EndSz = std::numeric_limits<unsigned>::max();
1307 unsigned LSz = 0;
1308 if (LVecTy)
1309 LSz = EndSz = LVecTy->getNumElements();
1310 if (RVecTy)
1311 EndSz = std::min(RVecTy->getNumElements(), EndSz);
1312 assert(EndSz != std::numeric_limits<unsigned>::max() &&
1313 "one of the above should have had a value");
1314
1315 // In a compound assignment, the left operand does not change type, the right
1316 // operand is converted to the type of the left operand.
1317 if (IsCompAssign && LSz != EndSz) {
1318 Diag(LHS.get()->getBeginLoc(),
1319 diag::err_hlsl_vector_compound_assignment_truncation)
1320 << LHSType << RHSType;
1321 return QualType();
1322 }
1323
1324 if (RVecTy && RVecTy->getNumElements() > EndSz)
1325 castVector<CK_HLSLVectorTruncation>(SemaRef, RHS, RHSType, EndSz);
1326 if (!IsCompAssign && LVecTy && LVecTy->getNumElements() > EndSz)
1327 castVector<CK_HLSLVectorTruncation>(SemaRef, LHS, LHSType, EndSz);
1328
1329 if (!RVecTy)
1330 castVector<CK_VectorSplat>(SemaRef, RHS, RHSType, EndSz);
1331 if (!IsCompAssign && !LVecTy)
1332 castVector<CK_VectorSplat>(SemaRef, LHS, LHSType, EndSz);
1333
1334 // If we're at the same type after resizing we can stop here.
1335 if (Ctx.hasSameUnqualifiedType(LHSType, RHSType))
1336 return Ctx.getCommonSugaredType(LHSType, RHSType);
1337
1338 QualType LElTy = LHSType->castAs<VectorType>()->getElementType();
1339 QualType RElTy = RHSType->castAs<VectorType>()->getElementType();
1340
1341 // Handle conversion for floating point vectors.
1342 if (LElTy->isRealFloatingType() || RElTy->isRealFloatingType())
1343 return handleFloatVectorBinOpConversion(SemaRef, LHS, RHS, LHSType, RHSType,
1344 LElTy, RElTy, IsCompAssign);
1345
1346 assert(LElTy->isIntegralType(Ctx) && RElTy->isIntegralType(Ctx) &&
1347 "HLSL Vectors can only contain integer or floating point types");
1348 return handleIntegerVectorBinOpConversion(SemaRef, LHS, RHS, LHSType, RHSType,
1349 LElTy, RElTy, IsCompAssign);
1350}
1351
1353 BinaryOperatorKind Opc) {
1354 assert((Opc == BO_LOr || Opc == BO_LAnd) &&
1355 "Called with non-logical operator");
1357 llvm::raw_svector_ostream OS(Buff);
1358 PrintingPolicy PP(SemaRef.getLangOpts());
1359 StringRef NewFnName = Opc == BO_LOr ? "or" : "and";
1360 OS << NewFnName << "(";
1361 LHS->printPretty(OS, nullptr, PP);
1362 OS << ", ";
1363 RHS->printPretty(OS, nullptr, PP);
1364 OS << ")";
1365 SourceRange FullRange = SourceRange(LHS->getBeginLoc(), RHS->getEndLoc());
1366 SemaRef.Diag(LHS->getBeginLoc(), diag::note_function_suggestion)
1367 << NewFnName << FixItHint::CreateReplacement(FullRange, OS.str());
1368}
1369
1370std::pair<IdentifierInfo *, bool>
1372 llvm::hash_code Hash = llvm::hash_value(Signature);
1373 std::string IdStr = "__hlsl_rootsig_decl_" + std::to_string(Hash);
1374 IdentifierInfo *DeclIdent = &(getASTContext().Idents.get(IdStr));
1375
1376 // Check if we have already found a decl of the same name.
1377 LookupResult R(SemaRef, DeclIdent, SourceLocation(),
1379 bool Found = SemaRef.LookupQualifiedName(R, SemaRef.CurContext);
1380 return {DeclIdent, Found};
1381}
1382
1384 SourceLocation Loc, IdentifierInfo *DeclIdent,
1386
1387 if (handleRootSignatureElements(RootElements))
1388 return;
1389
1391 for (auto &RootSigElement : RootElements)
1392 Elements.push_back(RootSigElement.getElement());
1393
1394 auto *SignatureDecl = HLSLRootSignatureDecl::Create(
1395 SemaRef.getASTContext(), /*DeclContext=*/SemaRef.CurContext, Loc,
1396 DeclIdent, SemaRef.getLangOpts().HLSLRootSigVer, Elements);
1397
1398 SignatureDecl->setImplicit();
1399 SemaRef.PushOnScopeChains(SignatureDecl, SemaRef.getCurScope());
1400}
1401
1404 if (RootSigOverrideIdent) {
1405 LookupResult R(SemaRef, RootSigOverrideIdent, SourceLocation(),
1407 if (SemaRef.LookupQualifiedName(R, DC))
1408 return dyn_cast<HLSLRootSignatureDecl>(R.getFoundDecl());
1409 }
1410
1411 return nullptr;
1412}
1413
1414namespace {
1415
1416struct PerVisibilityBindingChecker {
1417 SemaHLSL *S;
1418 // We need one builder per `llvm::dxbc::ShaderVisibility` value.
1419 std::array<llvm::hlsl::BindingInfoBuilder, 8> Builders;
1420
1421 struct ElemInfo {
1422 const hlsl::RootSignatureElement *Elem;
1423 llvm::dxbc::ShaderVisibility Vis;
1424 bool Diagnosed;
1425 };
1426 llvm::SmallVector<ElemInfo> ElemInfoMap;
1427
1428 PerVisibilityBindingChecker(SemaHLSL *S) : S(S) {}
1429
1430 void trackBinding(llvm::dxbc::ShaderVisibility Visibility,
1431 llvm::dxil::ResourceClass RC, uint32_t Space,
1432 uint32_t LowerBound, uint32_t UpperBound,
1433 const hlsl::RootSignatureElement *Elem) {
1434 uint32_t BuilderIndex = llvm::to_underlying(Visibility);
1435 assert(BuilderIndex < Builders.size() &&
1436 "Not enough builders for visibility type");
1437 Builders[BuilderIndex].trackBinding(RC, Space, LowerBound, UpperBound,
1438 static_cast<const void *>(Elem));
1439
1440 static_assert(llvm::to_underlying(llvm::dxbc::ShaderVisibility::All) == 0,
1441 "'All' visibility must come first");
1442 if (Visibility == llvm::dxbc::ShaderVisibility::All)
1443 for (size_t I = 1, E = Builders.size(); I < E; ++I)
1444 Builders[I].trackBinding(RC, Space, LowerBound, UpperBound,
1445 static_cast<const void *>(Elem));
1446
1447 ElemInfoMap.push_back({Elem, Visibility, false});
1448 }
1449
1450 ElemInfo &getInfo(const hlsl::RootSignatureElement *Elem) {
1451 auto It = llvm::lower_bound(
1452 ElemInfoMap, Elem,
1453 [](const auto &LHS, const auto &RHS) { return LHS.Elem < RHS; });
1454 assert(It->Elem == Elem && "Element not in map");
1455 return *It;
1456 }
1457
1458 bool checkOverlap() {
1459 llvm::sort(ElemInfoMap, [](const auto &LHS, const auto &RHS) {
1460 return LHS.Elem < RHS.Elem;
1461 });
1462
1463 bool HadOverlap = false;
1464
1465 using llvm::hlsl::BindingInfoBuilder;
1466 auto ReportOverlap = [this,
1467 &HadOverlap](const BindingInfoBuilder &Builder,
1468 const llvm::hlsl::Binding &Reported) {
1469 HadOverlap = true;
1470
1471 const auto *Elem =
1472 static_cast<const hlsl::RootSignatureElement *>(Reported.Cookie);
1473 const llvm::hlsl::Binding &Previous = Builder.findOverlapping(Reported);
1474 const auto *PrevElem =
1475 static_cast<const hlsl::RootSignatureElement *>(Previous.Cookie);
1476
1477 ElemInfo &Info = getInfo(Elem);
1478 // We will have already diagnosed this binding if there's overlap in the
1479 // "All" visibility as well as any particular visibility.
1480 if (Info.Diagnosed)
1481 return;
1482 Info.Diagnosed = true;
1483
1484 ElemInfo &PrevInfo = getInfo(PrevElem);
1485 llvm::dxbc::ShaderVisibility CommonVis =
1486 Info.Vis == llvm::dxbc::ShaderVisibility::All ? PrevInfo.Vis
1487 : Info.Vis;
1488
1489 this->S->Diag(Elem->getLocation(), diag::err_hlsl_resource_range_overlap)
1490 << llvm::to_underlying(Reported.RC) << Reported.LowerBound
1491 << Reported.isUnbounded() << Reported.UpperBound
1492 << llvm::to_underlying(Previous.RC) << Previous.LowerBound
1493 << Previous.isUnbounded() << Previous.UpperBound << Reported.Space
1494 << CommonVis;
1495
1496 this->S->Diag(PrevElem->getLocation(),
1497 diag::note_hlsl_resource_range_here);
1498 };
1499
1500 for (BindingInfoBuilder &Builder : Builders)
1501 Builder.calculateBindingInfo(ReportOverlap);
1502
1503 return HadOverlap;
1504 }
1505};
1506
1507static CXXMethodDecl *lookupMethod(Sema &S, CXXRecordDecl *RecordDecl,
1508 StringRef Name, SourceLocation Loc) {
1509 DeclarationName DeclName(&S.getASTContext().Idents.get(Name));
1510 LookupResult Result(S, DeclName, Loc, Sema::LookupMemberName);
1511 if (!S.LookupQualifiedName(Result, static_cast<DeclContext *>(RecordDecl)))
1512 return nullptr;
1513 return cast<CXXMethodDecl>(Result.getFoundDecl());
1514}
1515
1516} // end anonymous namespace
1517
1520 // Define some common error handling functions
1521 bool HadError = false;
1522 auto ReportError = [this, &HadError](SourceLocation Loc, uint32_t LowerBound,
1523 uint32_t UpperBound) {
1524 HadError = true;
1525 this->Diag(Loc, diag::err_hlsl_invalid_rootsig_value)
1526 << LowerBound << UpperBound;
1527 };
1528
1529 auto ReportFloatError = [this, &HadError](SourceLocation Loc,
1530 float LowerBound,
1531 float UpperBound) {
1532 HadError = true;
1533 this->Diag(Loc, diag::err_hlsl_invalid_rootsig_value)
1534 << llvm::formatv("{0:f}", LowerBound).sstr<6>()
1535 << llvm::formatv("{0:f}", UpperBound).sstr<6>();
1536 };
1537
1538 auto VerifyRegister = [ReportError](SourceLocation Loc, uint32_t Register) {
1539 if (!llvm::hlsl::rootsig::verifyRegisterValue(Register))
1540 ReportError(Loc, 0, 0xfffffffe);
1541 };
1542
1543 auto VerifySpace = [ReportError](SourceLocation Loc, uint32_t Space) {
1544 if (!llvm::hlsl::rootsig::verifyRegisterSpace(Space))
1545 ReportError(Loc, 0, 0xffffffef);
1546 };
1547
1548 const uint32_t Version =
1549 llvm::to_underlying(SemaRef.getLangOpts().HLSLRootSigVer);
1550 const uint32_t VersionEnum = Version - 1;
1551 auto ReportFlagError = [this, &HadError, VersionEnum](SourceLocation Loc) {
1552 HadError = true;
1553 this->Diag(Loc, diag::err_hlsl_invalid_rootsig_flag)
1554 << /*version minor*/ VersionEnum;
1555 };
1556
1557 // Iterate through the elements and do basic validations
1558 for (const hlsl::RootSignatureElement &RootSigElem : Elements) {
1559 SourceLocation Loc = RootSigElem.getLocation();
1560 const llvm::hlsl::rootsig::RootElement &Elem = RootSigElem.getElement();
1561 if (const auto *Descriptor =
1562 std::get_if<llvm::hlsl::rootsig::RootDescriptor>(&Elem)) {
1563 VerifyRegister(Loc, Descriptor->Reg.Number);
1564 VerifySpace(Loc, Descriptor->Space);
1565
1566 if (!llvm::hlsl::rootsig::verifyRootDescriptorFlag(Version,
1567 Descriptor->Flags))
1568 ReportFlagError(Loc);
1569 } else if (const auto *Constants =
1570 std::get_if<llvm::hlsl::rootsig::RootConstants>(&Elem)) {
1571 VerifyRegister(Loc, Constants->Reg.Number);
1572 VerifySpace(Loc, Constants->Space);
1573 } else if (const auto *Sampler =
1574 std::get_if<llvm::hlsl::rootsig::StaticSampler>(&Elem)) {
1575 VerifyRegister(Loc, Sampler->Reg.Number);
1576 VerifySpace(Loc, Sampler->Space);
1577
1578 assert(!std::isnan(Sampler->MaxLOD) && !std::isnan(Sampler->MinLOD) &&
1579 "By construction, parseFloatParam can't produce a NaN from a "
1580 "float_literal token");
1581
1582 if (!llvm::hlsl::rootsig::verifyMaxAnisotropy(Sampler->MaxAnisotropy))
1583 ReportError(Loc, 0, 16);
1584 if (!llvm::hlsl::rootsig::verifyMipLODBias(Sampler->MipLODBias))
1585 ReportFloatError(Loc, -16.f, 15.99f);
1586 } else if (const auto *Clause =
1587 std::get_if<llvm::hlsl::rootsig::DescriptorTableClause>(
1588 &Elem)) {
1589 VerifyRegister(Loc, Clause->Reg.Number);
1590 VerifySpace(Loc, Clause->Space);
1591
1592 if (!llvm::hlsl::rootsig::verifyNumDescriptors(Clause->NumDescriptors)) {
1593 // NumDescriptor could techincally be ~0u but that is reserved for
1594 // unbounded, so the diagnostic will not report that as a valid int
1595 // value
1596 ReportError(Loc, 1, 0xfffffffe);
1597 }
1598
1599 if (!llvm::hlsl::rootsig::verifyDescriptorRangeFlag(Version, Clause->Type,
1600 Clause->Flags))
1601 ReportFlagError(Loc);
1602 }
1603 }
1604
1605 PerVisibilityBindingChecker BindingChecker(this);
1606 SmallVector<std::pair<const llvm::hlsl::rootsig::DescriptorTableClause *,
1608 UnboundClauses;
1609
1610 for (const hlsl::RootSignatureElement &RootSigElem : Elements) {
1611 const llvm::hlsl::rootsig::RootElement &Elem = RootSigElem.getElement();
1612 if (const auto *Descriptor =
1613 std::get_if<llvm::hlsl::rootsig::RootDescriptor>(&Elem)) {
1614 uint32_t LowerBound(Descriptor->Reg.Number);
1615 uint32_t UpperBound(LowerBound); // inclusive range
1616
1617 BindingChecker.trackBinding(
1618 Descriptor->Visibility,
1619 static_cast<llvm::dxil::ResourceClass>(Descriptor->Type),
1620 Descriptor->Space, LowerBound, UpperBound, &RootSigElem);
1621 } else if (const auto *Constants =
1622 std::get_if<llvm::hlsl::rootsig::RootConstants>(&Elem)) {
1623 uint32_t LowerBound(Constants->Reg.Number);
1624 uint32_t UpperBound(LowerBound); // inclusive range
1625
1626 BindingChecker.trackBinding(
1627 Constants->Visibility, llvm::dxil::ResourceClass::CBuffer,
1628 Constants->Space, LowerBound, UpperBound, &RootSigElem);
1629 } else if (const auto *Sampler =
1630 std::get_if<llvm::hlsl::rootsig::StaticSampler>(&Elem)) {
1631 uint32_t LowerBound(Sampler->Reg.Number);
1632 uint32_t UpperBound(LowerBound); // inclusive range
1633
1634 BindingChecker.trackBinding(
1635 Sampler->Visibility, llvm::dxil::ResourceClass::Sampler,
1636 Sampler->Space, LowerBound, UpperBound, &RootSigElem);
1637 } else if (const auto *Clause =
1638 std::get_if<llvm::hlsl::rootsig::DescriptorTableClause>(
1639 &Elem)) {
1640 // We'll process these once we see the table element.
1641 UnboundClauses.emplace_back(Clause, &RootSigElem);
1642 } else if (const auto *Table =
1643 std::get_if<llvm::hlsl::rootsig::DescriptorTable>(&Elem)) {
1644 assert(UnboundClauses.size() == Table->NumClauses &&
1645 "Number of unbound elements must match the number of clauses");
1646 bool HasAnySampler = false;
1647 bool HasAnyNonSampler = false;
1648 uint64_t Offset = 0;
1649 bool IsPrevUnbound = false;
1650 for (const auto &[Clause, ClauseElem] : UnboundClauses) {
1651 SourceLocation Loc = ClauseElem->getLocation();
1652 if (Clause->Type == llvm::dxil::ResourceClass::Sampler)
1653 HasAnySampler = true;
1654 else
1655 HasAnyNonSampler = true;
1656
1657 if (HasAnySampler && HasAnyNonSampler)
1658 Diag(Loc, diag::err_hlsl_invalid_mixed_resources);
1659
1660 // Relevant error will have already been reported above and needs to be
1661 // fixed before we can conduct further analysis, so shortcut error
1662 // return
1663 if (Clause->NumDescriptors == 0)
1664 return true;
1665
1666 bool IsAppending =
1667 Clause->Offset == llvm::hlsl::rootsig::DescriptorTableOffsetAppend;
1668 if (!IsAppending)
1669 Offset = Clause->Offset;
1670
1671 uint64_t RangeBound = llvm::hlsl::rootsig::computeRangeBound(
1672 Offset, Clause->NumDescriptors);
1673
1674 if (IsPrevUnbound && IsAppending)
1675 Diag(Loc, diag::err_hlsl_appending_onto_unbound);
1676 else if (!llvm::hlsl::rootsig::verifyNoOverflowedOffset(RangeBound))
1677 Diag(Loc, diag::err_hlsl_offset_overflow) << Offset << RangeBound;
1678
1679 // Update offset to be 1 past this range's bound
1680 Offset = RangeBound + 1;
1681 IsPrevUnbound = Clause->NumDescriptors ==
1682 llvm::hlsl::rootsig::NumDescriptorsUnbounded;
1683
1684 // Compute the register bounds and track resource binding
1685 uint32_t LowerBound(Clause->Reg.Number);
1686 uint32_t UpperBound = llvm::hlsl::rootsig::computeRangeBound(
1687 LowerBound, Clause->NumDescriptors);
1688
1689 BindingChecker.trackBinding(
1690 Table->Visibility,
1691 static_cast<llvm::dxil::ResourceClass>(Clause->Type), Clause->Space,
1692 LowerBound, UpperBound, ClauseElem);
1693 }
1694 UnboundClauses.clear();
1695 }
1696 }
1697
1698 return BindingChecker.checkOverlap();
1699}
1700
1702 if (AL.getNumArgs() != 1) {
1703 Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1;
1704 return;
1705 }
1706
1708 if (auto *RS = D->getAttr<RootSignatureAttr>()) {
1709 if (RS->getSignatureIdent() != Ident) {
1710 Diag(AL.getLoc(), diag::err_disallowed_duplicate_attribute) << RS;
1711 return;
1712 }
1713
1714 Diag(AL.getLoc(), diag::warn_duplicate_attribute_exact) << RS;
1715 return;
1716 }
1717
1719 if (SemaRef.LookupQualifiedName(R, D->getDeclContext()))
1720 if (auto *SignatureDecl =
1721 dyn_cast<HLSLRootSignatureDecl>(R.getFoundDecl())) {
1722 D->addAttr(::new (getASTContext()) RootSignatureAttr(
1723 getASTContext(), AL, Ident, SignatureDecl));
1724 }
1725}
1726
1728 llvm::VersionTuple SMVersion =
1729 getASTContext().getTargetInfo().getTriple().getOSVersion();
1730 bool IsDXIL = getASTContext().getTargetInfo().getTriple().getArch() ==
1731 llvm::Triple::dxil;
1732
1733 uint32_t ZMax = 1024;
1734 uint32_t ThreadMax = 1024;
1735 if (IsDXIL && SMVersion.getMajor() <= 4) {
1736 ZMax = 1;
1737 ThreadMax = 768;
1738 } else if (IsDXIL && SMVersion.getMajor() == 5) {
1739 ZMax = 64;
1740 ThreadMax = 1024;
1741 }
1742
1743 uint32_t X;
1744 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), X))
1745 return;
1746 if (X > 1024) {
1747 Diag(AL.getArgAsExpr(0)->getExprLoc(),
1748 diag::err_hlsl_numthreads_argument_oor)
1749 << 0 << 1024;
1750 return;
1751 }
1752 uint32_t Y;
1753 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(1), Y))
1754 return;
1755 if (Y > 1024) {
1756 Diag(AL.getArgAsExpr(1)->getExprLoc(),
1757 diag::err_hlsl_numthreads_argument_oor)
1758 << 1 << 1024;
1759 return;
1760 }
1761 uint32_t Z;
1762 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(2), Z))
1763 return;
1764 if (Z > ZMax) {
1765 SemaRef.Diag(AL.getArgAsExpr(2)->getExprLoc(),
1766 diag::err_hlsl_numthreads_argument_oor)
1767 << 2 << ZMax;
1768 return;
1769 }
1770
1771 if (X * Y * Z > ThreadMax) {
1772 Diag(AL.getLoc(), diag::err_hlsl_numthreads_invalid) << ThreadMax;
1773 return;
1774 }
1775
1776 HLSLNumThreadsAttr *NewAttr = mergeNumThreadsAttr(D, AL, X, Y, Z);
1777 if (NewAttr)
1778 D->addAttr(NewAttr);
1779}
1780
1781static bool isValidWaveSizeValue(unsigned Value) {
1782 return llvm::isPowerOf2_32(Value) && Value >= 4 && Value <= 128;
1783}
1784
1786 // validate that the wavesize argument is a power of 2 between 4 and 128
1787 // inclusive
1788 unsigned SpelledArgsCount = AL.getNumArgs();
1789 if (SpelledArgsCount == 0 || SpelledArgsCount > 3)
1790 return;
1791
1792 uint32_t Min;
1793 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), Min))
1794 return;
1795
1796 uint32_t Max = 0;
1797 if (SpelledArgsCount > 1 &&
1798 !SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(1), Max))
1799 return;
1800
1801 uint32_t Preferred = 0;
1802 if (SpelledArgsCount > 2 &&
1803 !SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(2), Preferred))
1804 return;
1805
1806 if (SpelledArgsCount > 2) {
1807 if (!isValidWaveSizeValue(Preferred)) {
1808 Diag(AL.getArgAsExpr(2)->getExprLoc(),
1809 diag::err_attribute_power_of_two_in_range)
1810 << AL << llvm::dxil::MinWaveSize << llvm::dxil::MaxWaveSize
1811 << Preferred;
1812 return;
1813 }
1814 // Preferred not in range.
1815 if (Preferred < Min || Preferred > Max) {
1816 Diag(AL.getArgAsExpr(2)->getExprLoc(),
1817 diag::err_attribute_power_of_two_in_range)
1818 << AL << Min << Max << Preferred;
1819 return;
1820 }
1821 } else if (SpelledArgsCount > 1) {
1822 if (!isValidWaveSizeValue(Max)) {
1823 Diag(AL.getArgAsExpr(1)->getExprLoc(),
1824 diag::err_attribute_power_of_two_in_range)
1825 << AL << llvm::dxil::MinWaveSize << llvm::dxil::MaxWaveSize << Max;
1826 return;
1827 }
1828 if (Max < Min) {
1829 Diag(AL.getLoc(), diag::err_attribute_argument_invalid) << AL << 1;
1830 return;
1831 } else if (Max == Min) {
1832 Diag(AL.getLoc(), diag::warn_attr_min_eq_max) << AL;
1833 }
1834 } else {
1835 if (!isValidWaveSizeValue(Min)) {
1836 Diag(AL.getArgAsExpr(0)->getExprLoc(),
1837 diag::err_attribute_power_of_two_in_range)
1838 << AL << llvm::dxil::MinWaveSize << llvm::dxil::MaxWaveSize << Min;
1839 return;
1840 }
1841 }
1842
1843 HLSLWaveSizeAttr *NewAttr =
1844 mergeWaveSizeAttr(D, AL, Min, Max, Preferred, SpelledArgsCount);
1845 if (NewAttr)
1846 D->addAttr(NewAttr);
1847}
1848
1850 uint32_t ID;
1851 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), ID))
1852 return;
1853 D->addAttr(::new (getASTContext())
1854 HLSLVkExtBuiltinInputAttr(getASTContext(), AL, ID));
1855}
1856
1858 uint32_t ID;
1859 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), ID))
1860 return;
1861 D->addAttr(::new (getASTContext())
1862 HLSLVkExtBuiltinOutputAttr(getASTContext(), AL, ID));
1863}
1864
1866 D->addAttr(::new (getASTContext())
1867 HLSLVkPushConstantAttr(getASTContext(), AL));
1868}
1869
1871 uint32_t Id;
1872 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), Id))
1873 return;
1874 HLSLVkConstantIdAttr *NewAttr = mergeVkConstantIdAttr(D, AL, Id);
1875 if (NewAttr)
1876 D->addAttr(NewAttr);
1877}
1878
1880 uint32_t Binding = 0;
1881 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), Binding))
1882 return;
1883 uint32_t Set = 0;
1884 if (AL.getNumArgs() > 1 &&
1885 !SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(1), Set))
1886 return;
1887
1888 D->addAttr(::new (getASTContext())
1889 HLSLVkBindingAttr(getASTContext(), AL, Binding, Set));
1890}
1891
1893 uint32_t Location;
1894 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), Location))
1895 return;
1896
1897 D->addAttr(::new (getASTContext())
1898 HLSLVkLocationAttr(getASTContext(), AL, Location));
1899}
1900
1902 const auto *VT = T->getAs<VectorType>();
1903
1904 if (!T->hasUnsignedIntegerRepresentation() ||
1905 (VT && VT->getNumElements() > 3)) {
1906 Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type)
1907 << AL << "uint/uint2/uint3";
1908 return false;
1909 }
1910
1911 return true;
1912}
1913
1915 const auto *VT = T->getAs<VectorType>();
1916 if (!T->hasFloatingRepresentation() || (VT && VT->getNumElements() > 4)) {
1917 Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type)
1918 << AL << "float/float1/float2/float3/float4";
1919 return false;
1920 }
1921
1922 return true;
1923}
1924
1926 std::optional<unsigned> Index) {
1927 std::string SemanticName = AL.getAttrName()->getName().upper();
1928
1929 auto *VD = cast<ValueDecl>(D);
1930 QualType ValueType = VD->getType();
1931 if (auto *FD = dyn_cast<FunctionDecl>(D))
1932 ValueType = FD->getReturnType();
1933
1934 bool IsOutput = false;
1935 if (HLSLParamModifierAttr *MA = D->getAttr<HLSLParamModifierAttr>()) {
1936 if (MA->isOut()) {
1937 IsOutput = true;
1938 ValueType = cast<ReferenceType>(ValueType)->getPointeeType();
1939 }
1940 }
1941
1942 if (SemanticName == "SV_DISPATCHTHREADID") {
1943 diagnoseInputIDType(ValueType, AL);
1944 if (IsOutput)
1945 Diag(AL.getLoc(), diag::err_hlsl_semantic_output_not_supported) << AL;
1946 if (Index.has_value())
1947 Diag(AL.getLoc(), diag::err_hlsl_semantic_indexing_not_supported) << AL;
1949 return;
1950 }
1951
1952 if (SemanticName == "SV_GROUPINDEX") {
1953 if (IsOutput)
1954 Diag(AL.getLoc(), diag::err_hlsl_semantic_output_not_supported) << AL;
1955 if (Index.has_value())
1956 Diag(AL.getLoc(), diag::err_hlsl_semantic_indexing_not_supported) << AL;
1958 return;
1959 }
1960
1961 if (SemanticName == "SV_GROUPTHREADID") {
1962 diagnoseInputIDType(ValueType, AL);
1963 if (IsOutput)
1964 Diag(AL.getLoc(), diag::err_hlsl_semantic_output_not_supported) << AL;
1965 if (Index.has_value())
1966 Diag(AL.getLoc(), diag::err_hlsl_semantic_indexing_not_supported) << AL;
1968 return;
1969 }
1970
1971 if (SemanticName == "SV_GROUPID") {
1972 diagnoseInputIDType(ValueType, AL);
1973 if (IsOutput)
1974 Diag(AL.getLoc(), diag::err_hlsl_semantic_output_not_supported) << AL;
1975 if (Index.has_value())
1976 Diag(AL.getLoc(), diag::err_hlsl_semantic_indexing_not_supported) << AL;
1978 return;
1979 }
1980
1981 if (SemanticName == "SV_POSITION") {
1982 const auto *VT = ValueType->getAs<VectorType>();
1983 if (!ValueType->hasFloatingRepresentation() ||
1984 (VT && VT->getNumElements() > 4))
1985 Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type)
1986 << AL << "float/float1/float2/float3/float4";
1988 return;
1989 }
1990
1991 if (SemanticName == "SV_VERTEXID") {
1992 uint64_t SizeInBits = SemaRef.Context.getTypeSize(ValueType);
1993 if (!ValueType->isUnsignedIntegerType() || SizeInBits != 32)
1994 Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type) << AL << "uint";
1996 return;
1997 }
1998
1999 if (SemanticName == "SV_TARGET") {
2000 const auto *VT = ValueType->getAs<VectorType>();
2001 if (!ValueType->hasFloatingRepresentation() ||
2002 (VT && VT->getNumElements() > 4))
2003 Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type)
2004 << AL << "float/float1/float2/float3/float4";
2006 return;
2007 }
2008
2009 Diag(AL.getLoc(), diag::err_hlsl_unknown_semantic) << AL;
2010}
2011
2013 uint32_t IndexValue(0), ExplicitIndex(0);
2014 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), IndexValue) ||
2015 !SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(1), ExplicitIndex)) {
2016 assert(0 && "HLSLUnparsedSemantic is expected to have 2 int arguments.");
2017 }
2018 assert(IndexValue > 0 ? ExplicitIndex : true);
2019 std::optional<unsigned> Index =
2020 ExplicitIndex ? std::optional<unsigned>(IndexValue) : std::nullopt;
2021
2022 if (AL.getAttrName()->getName().starts_with_insensitive("SV_"))
2023 diagnoseSystemSemanticAttr(D, AL, Index);
2024 else
2026}
2027
2030 Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_ast_node)
2031 << AL << "shader constant in a constant buffer";
2032 return;
2033 }
2034
2035 uint32_t SubComponent;
2036 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), SubComponent))
2037 return;
2038 uint32_t Component;
2039 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(1), Component))
2040 return;
2041
2042 QualType T = cast<VarDecl>(D)->getType().getCanonicalType();
2043 // Check if T is an array or struct type.
2044 // TODO: mark matrix type as aggregate type.
2045 bool IsAggregateTy = (T->isArrayType() || T->isStructureType());
2046
2047 // Check Component is valid for T.
2048 if (Component) {
2049 unsigned Size = getASTContext().getTypeSize(T);
2050 if (IsAggregateTy) {
2051 Diag(AL.getLoc(), diag::err_hlsl_invalid_register_or_packoffset);
2052 return;
2053 } else {
2054 // Make sure Component + sizeof(T) <= 4.
2055 if ((Component * 32 + Size) > 128) {
2056 Diag(AL.getLoc(), diag::err_hlsl_packoffset_cross_reg_boundary);
2057 return;
2058 }
2059 QualType EltTy = T;
2060 if (const auto *VT = T->getAs<VectorType>())
2061 EltTy = VT->getElementType();
2062 unsigned Align = getASTContext().getTypeAlign(EltTy);
2063 if (Align > 32 && Component == 1) {
2064 // NOTE: Component 3 will hit err_hlsl_packoffset_cross_reg_boundary.
2065 // So we only need to check Component 1 here.
2066 Diag(AL.getLoc(), diag::err_hlsl_packoffset_alignment_mismatch)
2067 << Align << EltTy;
2068 return;
2069 }
2070 }
2071 }
2072
2073 D->addAttr(::new (getASTContext()) HLSLPackOffsetAttr(
2074 getASTContext(), AL, SubComponent, Component));
2075}
2076
2078 StringRef Str;
2079 SourceLocation ArgLoc;
2080 if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
2081 return;
2082
2083 llvm::Triple::EnvironmentType ShaderType;
2084 if (!HLSLShaderAttr::ConvertStrToEnvironmentType(Str, ShaderType)) {
2085 Diag(AL.getLoc(), diag::warn_attribute_type_not_supported)
2086 << AL << Str << ArgLoc;
2087 return;
2088 }
2089
2090 // FIXME: check function match the shader stage.
2091
2092 HLSLShaderAttr *NewAttr = mergeShaderAttr(D, AL, ShaderType);
2093 if (NewAttr)
2094 D->addAttr(NewAttr);
2095}
2096
2098 Sema &S, QualType Wrapped, ArrayRef<const Attr *> AttrList,
2099 QualType &ResType, HLSLAttributedResourceLocInfo *LocInfo) {
2100 assert(AttrList.size() && "expected list of resource attributes");
2101
2102 QualType ContainedTy = QualType();
2103 TypeSourceInfo *ContainedTyInfo = nullptr;
2104 SourceLocation LocBegin = AttrList[0]->getRange().getBegin();
2105 SourceLocation LocEnd = AttrList[0]->getRange().getEnd();
2106
2107 HLSLAttributedResourceType::Attributes ResAttrs;
2108
2109 bool HasResourceClass = false;
2110 bool HasResourceDimension = false;
2111 for (const Attr *A : AttrList) {
2112 if (!A)
2113 continue;
2114 LocEnd = A->getRange().getEnd();
2115 switch (A->getKind()) {
2116 case attr::HLSLResourceClass: {
2117 ResourceClass RC = cast<HLSLResourceClassAttr>(A)->getResourceClass();
2118 if (HasResourceClass) {
2119 S.Diag(A->getLocation(), ResAttrs.ResourceClass == RC
2120 ? diag::warn_duplicate_attribute_exact
2121 : diag::warn_duplicate_attribute)
2122 << A;
2123 return false;
2124 }
2125 ResAttrs.ResourceClass = RC;
2126 HasResourceClass = true;
2127 break;
2128 }
2129 case attr::HLSLResourceDimension: {
2130 llvm::dxil::ResourceDimension RD =
2131 cast<HLSLResourceDimensionAttr>(A)->getDimension();
2132 if (HasResourceDimension) {
2133 S.Diag(A->getLocation(), ResAttrs.ResourceDimension == RD
2134 ? diag::warn_duplicate_attribute_exact
2135 : diag::warn_duplicate_attribute)
2136 << A;
2137 return false;
2138 }
2139 ResAttrs.ResourceDimension = RD;
2140 HasResourceDimension = true;
2141 break;
2142 }
2143 case attr::HLSLROV:
2144 if (ResAttrs.IsROV) {
2145 S.Diag(A->getLocation(), diag::warn_duplicate_attribute_exact) << A;
2146 return false;
2147 }
2148 ResAttrs.IsROV = true;
2149 break;
2150 case attr::HLSLRawBuffer:
2151 if (ResAttrs.RawBuffer) {
2152 S.Diag(A->getLocation(), diag::warn_duplicate_attribute_exact) << A;
2153 return false;
2154 }
2155 ResAttrs.RawBuffer = true;
2156 break;
2157 case attr::HLSLIsArray:
2158 if (ResAttrs.IsArray) {
2159 S.Diag(A->getLocation(), diag::warn_duplicate_attribute_exact) << A;
2160 return false;
2161 }
2162 ResAttrs.IsArray = true;
2163 break;
2164 case attr::HLSLIsCounter:
2165 if (ResAttrs.IsCounter) {
2166 S.Diag(A->getLocation(), diag::warn_duplicate_attribute_exact) << A;
2167 return false;
2168 }
2169 ResAttrs.IsCounter = true;
2170 break;
2171 case attr::HLSLContainedType: {
2172 const HLSLContainedTypeAttr *CTAttr = cast<HLSLContainedTypeAttr>(A);
2173 QualType Ty = CTAttr->getType();
2174 if (!ContainedTy.isNull()) {
2175 S.Diag(A->getLocation(), ContainedTy == Ty
2176 ? diag::warn_duplicate_attribute_exact
2177 : diag::warn_duplicate_attribute)
2178 << A;
2179 return false;
2180 }
2181 ContainedTy = Ty;
2182 ContainedTyInfo = CTAttr->getTypeLoc();
2183 break;
2184 }
2185 default:
2186 llvm_unreachable("unhandled resource attribute type");
2187 }
2188 }
2189
2190 if (!HasResourceClass) {
2191 S.Diag(AttrList.back()->getRange().getEnd(),
2192 diag::err_hlsl_missing_resource_class);
2193 return false;
2194 }
2195
2197 Wrapped, ContainedTy, ResAttrs);
2198
2199 if (LocInfo && ContainedTyInfo) {
2200 LocInfo->Range = SourceRange(LocBegin, LocEnd);
2201 LocInfo->ContainedTyInfo = ContainedTyInfo;
2202 }
2203 return true;
2204}
2205
2206// Validates and creates an HLSL attribute that is applied as type attribute on
2207// HLSL resource. The attributes are collected in HLSLResourcesTypeAttrs and at
2208// the end of the declaration they are applied to the declaration type by
2209// wrapping it in HLSLAttributedResourceType.
2211 // only allow resource type attributes on intangible types
2212 if (!T->isHLSLResourceType()) {
2213 Diag(AL.getLoc(), diag::err_hlsl_attribute_needs_intangible_type)
2214 << AL << getASTContext().HLSLResourceTy;
2215 return false;
2216 }
2217
2218 // validate number of arguments
2219 if (!AL.checkExactlyNumArgs(SemaRef, AL.getMinArgs()))
2220 return false;
2221
2222 Attr *A = nullptr;
2223
2227 {
2228 AttributeCommonInfo::AS_CXX11, 0, false /*IsAlignas*/,
2229 false /*IsRegularKeywordAttribute*/
2230 });
2231
2232 switch (AL.getKind()) {
2233 case ParsedAttr::AT_HLSLResourceClass: {
2234 if (!AL.isArgIdent(0)) {
2235 Diag(AL.getLoc(), diag::err_attribute_argument_type)
2236 << AL << AANT_ArgumentIdentifier;
2237 return false;
2238 }
2239
2240 IdentifierLoc *Loc = AL.getArgAsIdent(0);
2241 StringRef Identifier = Loc->getIdentifierInfo()->getName();
2242 SourceLocation ArgLoc = Loc->getLoc();
2243
2244 // Validate resource class value
2245 ResourceClass RC;
2246 if (!HLSLResourceClassAttr::ConvertStrToResourceClass(Identifier, RC)) {
2247 Diag(ArgLoc, diag::warn_attribute_type_not_supported)
2248 << "ResourceClass" << Identifier;
2249 return false;
2250 }
2251 A = HLSLResourceClassAttr::Create(getASTContext(), RC, ACI);
2252 break;
2253 }
2254
2255 case ParsedAttr::AT_HLSLResourceDimension: {
2256 StringRef Identifier;
2257 SourceLocation ArgLoc;
2258 if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Identifier, &ArgLoc))
2259 return false;
2260
2261 // Validate resource dimension value
2262 llvm::dxil::ResourceDimension RD;
2263 if (!HLSLResourceDimensionAttr::ConvertStrToResourceDimension(Identifier,
2264 RD)) {
2265 Diag(ArgLoc, diag::warn_attribute_type_not_supported)
2266 << "ResourceDimension" << Identifier;
2267 return false;
2268 }
2269 A = HLSLResourceDimensionAttr::Create(getASTContext(), RD, ACI);
2270 break;
2271 }
2272
2273 case ParsedAttr::AT_HLSLROV:
2274 A = HLSLROVAttr::Create(getASTContext(), ACI);
2275 break;
2276
2277 case ParsedAttr::AT_HLSLRawBuffer:
2278 A = HLSLRawBufferAttr::Create(getASTContext(), ACI);
2279 break;
2280
2281 case ParsedAttr::AT_HLSLIsCounter:
2282 A = HLSLIsCounterAttr::Create(getASTContext(), ACI);
2283 break;
2284
2285 case ParsedAttr::AT_HLSLIsArray:
2286 A = HLSLIsArrayAttr::Create(getASTContext(), ACI);
2287 break;
2288
2289 case ParsedAttr::AT_HLSLContainedType: {
2290 if (AL.getNumArgs() != 1 && !AL.hasParsedType()) {
2291 Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1;
2292 return false;
2293 }
2294
2295 TypeSourceInfo *TSI = nullptr;
2296 QualType QT = SemaRef.GetTypeFromParser(AL.getTypeArg(), &TSI);
2297 assert(TSI && "no type source info for attribute argument");
2298 if (SemaRef.RequireCompleteType(TSI->getTypeLoc().getBeginLoc(), QT,
2299 diag::err_incomplete_type))
2300 return false;
2301 A = HLSLContainedTypeAttr::Create(getASTContext(), TSI, ACI);
2302 break;
2303 }
2304
2305 default:
2306 llvm_unreachable("unhandled HLSL attribute");
2307 }
2308
2309 HLSLResourcesTypeAttrs.emplace_back(A);
2310 return true;
2311}
2312
2313// Combines all resource type attributes and creates HLSLAttributedResourceType.
2315 if (!HLSLResourcesTypeAttrs.size())
2316 return CurrentType;
2317
2318 QualType QT = CurrentType;
2321 HLSLResourcesTypeAttrs, QT, &LocInfo)) {
2322 const HLSLAttributedResourceType *RT =
2324
2325 // Temporarily store TypeLoc information for the new type.
2326 // It will be transferred to HLSLAttributesResourceTypeLoc
2327 // shortly after the type is created by TypeSpecLocFiller which
2328 // will call the TakeLocForHLSLAttribute method below.
2329 LocsForHLSLAttributedResources.insert(std::pair(RT, LocInfo));
2330 }
2331 HLSLResourcesTypeAttrs.clear();
2332 return QT;
2333}
2334
2335// Returns source location for the HLSLAttributedResourceType
2337SemaHLSL::TakeLocForHLSLAttribute(const HLSLAttributedResourceType *RT) {
2338 HLSLAttributedResourceLocInfo LocInfo = {};
2339 auto I = LocsForHLSLAttributedResources.find(RT);
2340 if (I != LocsForHLSLAttributedResources.end()) {
2341 LocInfo = I->second;
2342 LocsForHLSLAttributedResources.erase(I);
2343 return LocInfo;
2344 }
2345 LocInfo.Range = SourceRange();
2346 return LocInfo;
2347}
2348
2349// Walks though the global variable declaration, collects all resource binding
2350// requirements and adds them to Bindings
2351void SemaHLSL::collectResourceBindingsOnUserRecordDecl(const VarDecl *VD,
2352 const RecordType *RT) {
2353 const RecordDecl *RD = RT->getDecl()->getDefinitionOrSelf();
2354 for (FieldDecl *FD : RD->fields()) {
2355 const Type *Ty = FD->getType()->getUnqualifiedDesugaredType();
2356
2357 // Unwrap arrays
2358 // FIXME: Calculate array size while unwrapping
2359 assert(!Ty->isIncompleteArrayType() &&
2360 "incomplete arrays inside user defined types are not supported");
2361 while (Ty->isConstantArrayType()) {
2364 }
2365
2366 if (!Ty->isRecordType())
2367 continue;
2368
2369 if (const HLSLAttributedResourceType *AttrResType =
2370 HLSLAttributedResourceType::findHandleTypeOnResource(Ty)) {
2371 // Add a new DeclBindingInfo to Bindings if it does not already exist
2372 ResourceClass RC = AttrResType->getAttrs().ResourceClass;
2373 DeclBindingInfo *DBI = Bindings.getDeclBindingInfo(VD, RC);
2374 if (!DBI)
2375 Bindings.addDeclBindingInfo(VD, RC);
2376 } else if (const RecordType *RT = dyn_cast<RecordType>(Ty)) {
2377 // Recursively scan embedded struct or class; it would be nice to do this
2378 // without recursion, but tricky to correctly calculate the size of the
2379 // binding, which is something we are probably going to need to do later
2380 // on. Hopefully nesting of structs in structs too many levels is
2381 // unlikely.
2382 collectResourceBindingsOnUserRecordDecl(VD, RT);
2383 }
2384 }
2385}
2386
2387// Diagnose localized register binding errors for a single binding; does not
2388// diagnose resource binding on user record types, that will be done later
2389// in processResourceBindingOnDecl based on the information collected in
2390// collectResourceBindingsOnVarDecl.
2391// Returns false if the register binding is not valid.
2393 Decl *D, RegisterType RegType,
2394 bool SpecifiedSpace) {
2395 int RegTypeNum = static_cast<int>(RegType);
2396
2397 // check if the decl type is groupshared
2398 if (D->hasAttr<HLSLGroupSharedAddressSpaceAttr>()) {
2399 S.Diag(ArgLoc, diag::err_hlsl_binding_type_mismatch) << RegTypeNum;
2400 return false;
2401 }
2402
2403 // Cbuffers and Tbuffers are HLSLBufferDecl types
2404 if (HLSLBufferDecl *CBufferOrTBuffer = dyn_cast<HLSLBufferDecl>(D)) {
2405 ResourceClass RC = CBufferOrTBuffer->isCBuffer() ? ResourceClass::CBuffer
2406 : ResourceClass::SRV;
2407 if (RegType == getRegisterType(RC))
2408 return true;
2409
2410 S.Diag(D->getLocation(), diag::err_hlsl_binding_type_mismatch)
2411 << RegTypeNum;
2412 return false;
2413 }
2414
2415 // Samplers, UAVs, and SRVs are VarDecl types
2416 assert(isa<VarDecl>(D) && "D is expected to be VarDecl or HLSLBufferDecl");
2417 VarDecl *VD = cast<VarDecl>(D);
2418
2419 // Resource
2420 if (const HLSLAttributedResourceType *AttrResType =
2421 HLSLAttributedResourceType::findHandleTypeOnResource(
2422 VD->getType().getTypePtr())) {
2423 if (RegType == getRegisterType(AttrResType))
2424 return true;
2425
2426 S.Diag(D->getLocation(), diag::err_hlsl_binding_type_mismatch)
2427 << RegTypeNum;
2428 return false;
2429 }
2430
2431 const clang::Type *Ty = VD->getType().getTypePtr();
2432 while (Ty->isArrayType())
2434
2435 // Basic types
2436 if (Ty->isArithmeticType() || Ty->isVectorType()) {
2437 bool DeclaredInCOrTBuffer = isa<HLSLBufferDecl>(D->getDeclContext());
2438 if (SpecifiedSpace && !DeclaredInCOrTBuffer)
2439 S.Diag(ArgLoc, diag::err_hlsl_space_on_global_constant);
2440
2441 if (!DeclaredInCOrTBuffer && (Ty->isIntegralType(S.getASTContext()) ||
2442 Ty->isFloatingType() || Ty->isVectorType())) {
2443 // Register annotation on default constant buffer declaration ($Globals)
2444 if (RegType == RegisterType::CBuffer)
2445 S.Diag(ArgLoc, diag::warn_hlsl_deprecated_register_type_b);
2446 else if (RegType != RegisterType::C)
2447 S.Diag(ArgLoc, diag::err_hlsl_binding_type_mismatch) << RegTypeNum;
2448 else
2449 return true;
2450 } else {
2451 if (RegType == RegisterType::C)
2452 S.Diag(ArgLoc, diag::warn_hlsl_register_type_c_packoffset);
2453 else
2454 S.Diag(ArgLoc, diag::err_hlsl_binding_type_mismatch) << RegTypeNum;
2455 }
2456 return false;
2457 }
2458 if (Ty->isRecordType())
2459 // RecordTypes will be diagnosed in processResourceBindingOnDecl
2460 // that is called from ActOnVariableDeclarator
2461 return true;
2462
2463 // Anything else is an error
2464 S.Diag(ArgLoc, diag::err_hlsl_binding_type_mismatch) << RegTypeNum;
2465 return false;
2466}
2467
2469 RegisterType regType) {
2470 // make sure that there are no two register annotations
2471 // applied to the decl with the same register type
2472 bool RegisterTypesDetected[5] = {false};
2473 RegisterTypesDetected[static_cast<int>(regType)] = true;
2474
2475 for (auto it = TheDecl->attr_begin(); it != TheDecl->attr_end(); ++it) {
2476 if (HLSLResourceBindingAttr *attr =
2477 dyn_cast<HLSLResourceBindingAttr>(*it)) {
2478
2479 RegisterType otherRegType = attr->getRegisterType();
2480 if (RegisterTypesDetected[static_cast<int>(otherRegType)]) {
2481 int otherRegTypeNum = static_cast<int>(otherRegType);
2482 S.Diag(TheDecl->getLocation(),
2483 diag::err_hlsl_duplicate_register_annotation)
2484 << otherRegTypeNum;
2485 return false;
2486 }
2487 RegisterTypesDetected[static_cast<int>(otherRegType)] = true;
2488 }
2489 }
2490 return true;
2491}
2492
2494 Decl *D, RegisterType RegType,
2495 bool SpecifiedSpace) {
2496
2497 // exactly one of these two types should be set
2498 assert(((isa<VarDecl>(D) && !isa<HLSLBufferDecl>(D)) ||
2499 (!isa<VarDecl>(D) && isa<HLSLBufferDecl>(D))) &&
2500 "expecting VarDecl or HLSLBufferDecl");
2501
2502 // check if the declaration contains resource matching the register type
2503 if (!DiagnoseLocalRegisterBinding(S, ArgLoc, D, RegType, SpecifiedSpace))
2504 return false;
2505
2506 // next, if multiple register annotations exist, check that none conflict.
2507 return ValidateMultipleRegisterAnnotations(S, D, RegType);
2508}
2509
2510// return false if the slot count exceeds the limit, true otherwise
2511static bool AccumulateHLSLResourceSlots(QualType Ty, uint64_t &StartSlot,
2512 const uint64_t &Limit,
2513 const ResourceClass ResClass,
2514 ASTContext &Ctx,
2515 uint64_t ArrayCount = 1) {
2516 Ty = Ty.getCanonicalType();
2517 const Type *T = Ty.getTypePtr();
2518
2519 // Early exit if already overflowed
2520 if (StartSlot > Limit)
2521 return false;
2522
2523 // Case 1: array type
2524 if (const auto *AT = dyn_cast<ArrayType>(T)) {
2525 uint64_t Count = 1;
2526
2527 if (const auto *CAT = dyn_cast<ConstantArrayType>(AT))
2528 Count = CAT->getSize().getZExtValue();
2529
2530 QualType ElemTy = AT->getElementType();
2531 return AccumulateHLSLResourceSlots(ElemTy, StartSlot, Limit, ResClass, Ctx,
2532 ArrayCount * Count);
2533 }
2534
2535 // Case 2: resource leaf
2536 if (auto ResTy = dyn_cast<HLSLAttributedResourceType>(T)) {
2537 // First ensure this resource counts towards the corresponding
2538 // register type limit.
2539 if (ResTy->getAttrs().ResourceClass != ResClass)
2540 return true;
2541
2542 // Validate highest slot used
2543 uint64_t EndSlot = StartSlot + ArrayCount - 1;
2544 if (EndSlot > Limit)
2545 return false;
2546
2547 // Advance SlotCount past the consumed range
2548 StartSlot = EndSlot + 1;
2549 return true;
2550 }
2551
2552 // Case 3: struct / record
2553 if (const auto *RT = dyn_cast<RecordType>(T)) {
2554 const RecordDecl *RD = RT->getDecl();
2555
2556 if (const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
2557 for (const CXXBaseSpecifier &Base : CXXRD->bases()) {
2558 if (!AccumulateHLSLResourceSlots(Base.getType(), StartSlot, Limit,
2559 ResClass, Ctx, ArrayCount))
2560 return false;
2561 }
2562 }
2563
2564 for (const FieldDecl *Field : RD->fields()) {
2565 if (!AccumulateHLSLResourceSlots(Field->getType(), StartSlot, Limit,
2566 ResClass, Ctx, ArrayCount))
2567 return false;
2568 }
2569
2570 return true;
2571 }
2572
2573 // Case 4: everything else
2574 return true;
2575}
2576
2577// return true if there is something invalid, false otherwise
2578static bool ValidateRegisterNumber(uint64_t SlotNum, Decl *TheDecl,
2579 ASTContext &Ctx, RegisterType RegTy) {
2580 const uint64_t Limit = UINT32_MAX;
2581 if (SlotNum > Limit)
2582 return true;
2583
2584 // after verifying the number doesn't exceed uint32max, we don't need
2585 // to look further into c or i register types
2586 if (RegTy == RegisterType::C || RegTy == RegisterType::I)
2587 return false;
2588
2589 if (VarDecl *VD = dyn_cast<VarDecl>(TheDecl)) {
2590 uint64_t BaseSlot = SlotNum;
2591
2592 if (!AccumulateHLSLResourceSlots(VD->getType(), SlotNum, Limit,
2593 getResourceClass(RegTy), Ctx))
2594 return true;
2595
2596 // After AccumulateHLSLResourceSlots runs, SlotNum is now
2597 // the first free slot; last used was SlotNum - 1
2598 return (BaseSlot > Limit);
2599 }
2600 // handle the cbuffer/tbuffer case
2601 if (isa<HLSLBufferDecl>(TheDecl))
2602 // resources cannot be put within a cbuffer, so no need
2603 // to analyze the structure since the register number
2604 // won't be pushed any higher.
2605 return (SlotNum > Limit);
2606
2607 // we don't expect any other decl type, so fail
2608 llvm_unreachable("unexpected decl type");
2609}
2610
2612 if (VarDecl *VD = dyn_cast<VarDecl>(TheDecl)) {
2613 QualType Ty = VD->getType();
2614 if (const auto *IAT = dyn_cast<IncompleteArrayType>(Ty))
2615 Ty = IAT->getElementType();
2616 if (SemaRef.RequireCompleteType(TheDecl->getBeginLoc(), Ty,
2617 diag::err_incomplete_type))
2618 return;
2619 }
2620
2621 StringRef Slot = "";
2622 StringRef Space = "";
2623 SourceLocation SlotLoc, SpaceLoc;
2624
2625 if (!AL.isArgIdent(0)) {
2626 Diag(AL.getLoc(), diag::err_attribute_argument_type)
2627 << AL << AANT_ArgumentIdentifier;
2628 return;
2629 }
2630 IdentifierLoc *Loc = AL.getArgAsIdent(0);
2631
2632 if (AL.getNumArgs() == 2) {
2633 Slot = Loc->getIdentifierInfo()->getName();
2634 SlotLoc = Loc->getLoc();
2635 if (!AL.isArgIdent(1)) {
2636 Diag(AL.getLoc(), diag::err_attribute_argument_type)
2637 << AL << AANT_ArgumentIdentifier;
2638 return;
2639 }
2640 Loc = AL.getArgAsIdent(1);
2641 Space = Loc->getIdentifierInfo()->getName();
2642 SpaceLoc = Loc->getLoc();
2643 } else {
2644 StringRef Str = Loc->getIdentifierInfo()->getName();
2645 if (Str.starts_with("space")) {
2646 Space = Str;
2647 SpaceLoc = Loc->getLoc();
2648 } else {
2649 Slot = Str;
2650 SlotLoc = Loc->getLoc();
2651 Space = "space0";
2652 }
2653 }
2654
2655 RegisterType RegType = RegisterType::SRV;
2656 std::optional<unsigned> SlotNum;
2657 unsigned SpaceNum = 0;
2658
2659 // Validate slot
2660 if (!Slot.empty()) {
2661 if (!convertToRegisterType(Slot, &RegType)) {
2662 Diag(SlotLoc, diag::err_hlsl_binding_type_invalid) << Slot.substr(0, 1);
2663 return;
2664 }
2665 if (RegType == RegisterType::I) {
2666 Diag(SlotLoc, diag::warn_hlsl_deprecated_register_type_i);
2667 return;
2668 }
2669 const StringRef SlotNumStr = Slot.substr(1);
2670
2671 uint64_t N;
2672
2673 // validate that the slot number is a non-empty number
2674 if (SlotNumStr.getAsInteger(10, N)) {
2675 Diag(SlotLoc, diag::err_hlsl_unsupported_register_number);
2676 return;
2677 }
2678
2679 // Validate register number. It should not exceed UINT32_MAX,
2680 // including if the resource type is an array that starts
2681 // before UINT32_MAX, but ends afterwards.
2682 if (ValidateRegisterNumber(N, TheDecl, getASTContext(), RegType)) {
2683 Diag(SlotLoc, diag::err_hlsl_register_number_too_large);
2684 return;
2685 }
2686
2687 // the slot number has been validated and does not exceed UINT32_MAX
2688 SlotNum = (unsigned)N;
2689 }
2690
2691 // Validate space
2692 if (!Space.starts_with("space")) {
2693 Diag(SpaceLoc, diag::err_hlsl_expected_space) << Space;
2694 return;
2695 }
2696 StringRef SpaceNumStr = Space.substr(5);
2697 if (SpaceNumStr.getAsInteger(10, SpaceNum)) {
2698 Diag(SpaceLoc, diag::err_hlsl_expected_space) << Space;
2699 return;
2700 }
2701
2702 // If we have slot, diagnose it is the right register type for the decl
2703 if (SlotNum.has_value())
2704 if (!DiagnoseHLSLRegisterAttribute(SemaRef, SlotLoc, TheDecl, RegType,
2705 !SpaceLoc.isInvalid()))
2706 return;
2707
2708 HLSLResourceBindingAttr *NewAttr =
2709 HLSLResourceBindingAttr::Create(getASTContext(), Slot, Space, AL);
2710 if (NewAttr) {
2711 NewAttr->setBinding(RegType, SlotNum, SpaceNum);
2712 TheDecl->addAttr(NewAttr);
2713 }
2714}
2715
2717 HLSLParamModifierAttr *NewAttr = mergeParamModifierAttr(
2718 D, AL,
2719 static_cast<HLSLParamModifierAttr::Spelling>(AL.getSemanticSpelling()));
2720 if (NewAttr)
2721 D->addAttr(NewAttr);
2722}
2723
2724static bool isMatrixOrArrayOfMatrix(const ASTContext &Ctx, QualType QT) {
2725 const Type *Ty = QT->getUnqualifiedDesugaredType();
2726 while (isa<ArrayType>(Ty))
2728 return Ty->isDependentType() || Ty->isConstantMatrixType();
2729}
2730
2731/// Walks the existing AttributedType sugar of \p T looking for a previously
2732/// applied HLSLRowMajor/HLSLColumnMajor marker. If one is found, populates
2733/// \p ExistingKind with its attr::Kind and returns true.
2735 attr::Kind &ExistingKind) {
2736 QualType Cur = T;
2737 while (const auto *AT = Cur->getAs<AttributedType>()) {
2738 attr::Kind K = AT->getAttrKind();
2739 if (K == attr::HLSLRowMajor || K == attr::HLSLColumnMajor) {
2740 ExistingKind = K;
2741 return true;
2742 }
2743 Cur = AT->getModifiedType();
2744 }
2745 return false;
2746}
2747
2749 if (T.isNull())
2750 return nullptr;
2751
2752 ASTContext &Ctx = getASTContext();
2753 attr::Kind AttrK = AL.getKind() == ParsedAttr::AT_HLSLRowMajor
2754 ? attr::HLSLRowMajor
2755 : attr::HLSLColumnMajor;
2756
2757 // For non-dependent types, the operand must be a matrix (or array of
2758 // matrices).
2759 if (!T->isDependentType() && !isMatrixOrArrayOfMatrix(Ctx, T)) {
2760 Diag(AL.getLoc(), diag::err_hlsl_matrix_layout_non_matrix)
2761 << AL.getAttrName();
2762 AL.setInvalid();
2763 return nullptr;
2764 }
2765
2766 // Conflict / duplicate detection by walking existing sugar.
2767 attr::Kind ExistingKind;
2768 if (findExistingMatrixLayoutMarker(T, ExistingKind)) {
2769 if (ExistingKind == AttrK) {
2770 Diag(AL.getLoc(), diag::warn_duplicate_attribute_exact)
2771 << AL.getAttrName();
2772 Diag(AL.getLoc(), diag::note_previous_attribute);
2773 return nullptr;
2774 }
2775 IdentifierInfo *ExistingII = &Ctx.Idents.get(
2776 ExistingKind == attr::HLSLRowMajor ? "row_major" : "column_major");
2777 Diag(AL.getLoc(), diag::err_hlsl_matrix_layout_conflict)
2778 << AL.getAttrName() << ExistingII;
2779 Diag(AL.getLoc(), diag::note_conflicting_attribute);
2780 AL.setInvalid();
2781 return nullptr;
2782 }
2783
2784 if (AttrK == attr::HLSLRowMajor)
2785 return ::new (Ctx) HLSLRowMajorAttr(Ctx, AL);
2786 return ::new (Ctx) HLSLColumnMajorAttr(Ctx, AL);
2787}
2788
2789// Re-validates an HLSL `row_major` / `column_major` attribute after template
2790// substitution. The parse-time check in `buildMatrixLayoutTypeAttr` is skipped
2791// for dependent types; `TransformAttributedType` calls this once the type is
2792// concrete. Returns `true` (and emits a diagnostic) if the substituted type is
2793// not a matrix or array of matrices, signaling the caller to abort the
2794// transform.
2796 SourceLocation Loc) {
2797 if (K != attr::HLSLRowMajor && K != attr::HLSLColumnMajor)
2798 return false;
2799 if (T.isNull() || T->isDependentType())
2800 return false;
2802 return false;
2804 K == attr::HLSLRowMajor ? "row_major" : "column_major");
2805 Diag(Loc, diag::err_hlsl_matrix_layout_non_matrix) << II;
2806 return true;
2807}
2808
2809// Transpose and matrix mul need to read the destination layout.
2810// Elementwise builtins reuse the operand layout instead.
2811static bool isLayoutAdaptingMatrixBuiltin(unsigned BuiltinID) {
2812 switch (BuiltinID) {
2813 case Builtin::BI__builtin_hlsl_mul:
2814 case Builtin::BI__builtin_hlsl_transpose:
2815 return true;
2816 default:
2817 return false;
2818 }
2819}
2820
2822 if (!E || DestType.isNull())
2823 return;
2824 const auto *DestMat = DestType->getAs<ConstantMatrixType>();
2825 if (!DestMat)
2826 return;
2827 auto *Call = dyn_cast<CallExpr>(E->IgnoreParenImpCasts());
2828 if (!Call)
2829 return;
2830 const FunctionDecl *Callee = Call->getDirectCallee();
2831 if (!Callee || !isLayoutAdaptingMatrixBuiltin(Callee->getBuiltinID()))
2832 return;
2833 const auto *CallMat = Call->getType()->getAs<ConstantMatrixType>();
2834 if (!CallMat || CallMat->getNumRows() != DestMat->getNumRows() ||
2835 CallMat->getNumColumns() != DestMat->getNumColumns())
2836 return;
2837 // Re-type the call with the destination sugar so CodeGen lowers into that
2838 // layout, not the TU default.
2839 Call->setType(DestType.getUnqualifiedType());
2840}
2841
2842namespace {
2843
2844/// This class implements HLSL availability diagnostics for default
2845/// and relaxed mode
2846///
2847/// The goal of this diagnostic is to emit an error or warning when an
2848/// unavailable API is found in code that is reachable from the shader
2849/// entry function or from an exported function (when compiling a shader
2850/// library).
2851///
2852/// This is done by traversing the AST of all shader entry point functions
2853/// and of all exported functions, and any functions that are referenced
2854/// from this AST. In other words, any functions that are reachable from
2855/// the entry points.
2856class DiagnoseHLSLAvailability : public DynamicRecursiveASTVisitor {
2857 Sema &SemaRef;
2858
2859 // Stack of functions to be scaned
2861
2862 // Tracks which environments functions have been scanned in.
2863 //
2864 // Maps FunctionDecl to an unsigned number that represents the set of shader
2865 // environments the function has been scanned for.
2866 // The llvm::Triple::EnvironmentType enum values for shader stages guaranteed
2867 // to be numbered from llvm::Triple::Pixel to llvm::Triple::Amplification
2868 // (verified by static_asserts in Triple.cpp), we can use it to index
2869 // individual bits in the set, as long as we shift the values to start with 0
2870 // by subtracting the value of llvm::Triple::Pixel first.
2871 //
2872 // The N'th bit in the set will be set if the function has been scanned
2873 // in shader environment whose llvm::Triple::EnvironmentType integer value
2874 // equals (llvm::Triple::Pixel + N).
2875 //
2876 // For example, if a function has been scanned in compute and pixel stage
2877 // environment, the value will be 0x21 (100001 binary) because:
2878 //
2879 // (int)(llvm::Triple::Pixel - llvm::Triple::Pixel) == 0
2880 // (int)(llvm::Triple::Compute - llvm::Triple::Pixel) == 5
2881 //
2882 // A FunctionDecl is mapped to 0 (or not included in the map) if it has not
2883 // been scanned in any environment.
2884 llvm::DenseMap<const FunctionDecl *, unsigned> ScannedDecls;
2885
2886 // Do not access these directly, use the get/set methods below to make
2887 // sure the values are in sync
2888 llvm::Triple::EnvironmentType CurrentShaderEnvironment;
2889 unsigned CurrentShaderStageBit;
2890
2891 // True if scanning a function that was already scanned in a different
2892 // shader stage context, and therefore we should not report issues that
2893 // depend only on shader model version because they would be duplicate.
2894 bool ReportOnlyShaderStageIssues;
2895
2896 // Helper methods for dealing with current stage context / environment
2897 void SetShaderStageContext(llvm::Triple::EnvironmentType ShaderType) {
2898 static_assert(sizeof(unsigned) >= 4);
2899 assert(HLSLShaderAttr::isValidShaderType(ShaderType));
2900 assert((unsigned)(ShaderType - llvm::Triple::Pixel) < 31 &&
2901 "ShaderType is too big for this bitmap"); // 31 is reserved for
2902 // "unknown"
2903
2904 unsigned bitmapIndex = ShaderType - llvm::Triple::Pixel;
2905 CurrentShaderEnvironment = ShaderType;
2906 CurrentShaderStageBit = (1 << bitmapIndex);
2907 }
2908
2909 void SetUnknownShaderStageContext() {
2910 CurrentShaderEnvironment = llvm::Triple::UnknownEnvironment;
2911 CurrentShaderStageBit = (1 << 31);
2912 }
2913
2914 llvm::Triple::EnvironmentType GetCurrentShaderEnvironment() const {
2915 return CurrentShaderEnvironment;
2916 }
2917
2918 bool InUnknownShaderStageContext() const {
2919 return CurrentShaderEnvironment == llvm::Triple::UnknownEnvironment;
2920 }
2921
2922 // Helper methods for dealing with shader stage bitmap
2923 void AddToScannedFunctions(const FunctionDecl *FD) {
2924 unsigned &ScannedStages = ScannedDecls[FD];
2925 ScannedStages |= CurrentShaderStageBit;
2926 }
2927
2928 unsigned GetScannedStages(const FunctionDecl *FD) { return ScannedDecls[FD]; }
2929
2930 bool WasAlreadyScannedInCurrentStage(const FunctionDecl *FD) {
2931 return WasAlreadyScannedInCurrentStage(GetScannedStages(FD));
2932 }
2933
2934 bool WasAlreadyScannedInCurrentStage(unsigned ScannerStages) {
2935 return ScannerStages & CurrentShaderStageBit;
2936 }
2937
2938 static bool NeverBeenScanned(unsigned ScannedStages) {
2939 return ScannedStages == 0;
2940 }
2941
2942 // Scanning methods
2943 void HandleFunctionOrMethodRef(FunctionDecl *FD, Expr *RefExpr);
2944 void CheckDeclAvailability(NamedDecl *D, const AvailabilityAttr *AA,
2945 SourceRange Range);
2946 const AvailabilityAttr *FindAvailabilityAttr(const Decl *D);
2947 bool HasMatchingEnvironmentOrNone(const AvailabilityAttr *AA);
2948
2949public:
2950 DiagnoseHLSLAvailability(Sema &SemaRef)
2951 : SemaRef(SemaRef),
2952 CurrentShaderEnvironment(llvm::Triple::UnknownEnvironment),
2953 CurrentShaderStageBit(0), ReportOnlyShaderStageIssues(false) {}
2954
2955 // AST traversal methods
2956 void RunOnTranslationUnit(const TranslationUnitDecl *TU);
2957 void RunOnFunction(const FunctionDecl *FD);
2958
2959 bool VisitDeclRefExpr(DeclRefExpr *DRE) override {
2960 FunctionDecl *FD = llvm::dyn_cast<FunctionDecl>(DRE->getDecl());
2961 if (FD)
2962 HandleFunctionOrMethodRef(FD, DRE);
2963 return true;
2964 }
2965
2966 bool VisitMemberExpr(MemberExpr *ME) override {
2967 FunctionDecl *FD = llvm::dyn_cast<FunctionDecl>(ME->getMemberDecl());
2968 if (FD)
2969 HandleFunctionOrMethodRef(FD, ME);
2970 return true;
2971 }
2972};
2973
2974void DiagnoseHLSLAvailability::HandleFunctionOrMethodRef(FunctionDecl *FD,
2975 Expr *RefExpr) {
2976 assert((isa<DeclRefExpr>(RefExpr) || isa<MemberExpr>(RefExpr)) &&
2977 "expected DeclRefExpr or MemberExpr");
2978
2979 // has a definition -> add to stack to be scanned
2980 const FunctionDecl *FDWithBody = nullptr;
2981 if (FD->hasBody(FDWithBody)) {
2982 if (!WasAlreadyScannedInCurrentStage(FDWithBody))
2983 DeclsToScan.push_back(FDWithBody);
2984 return;
2985 }
2986
2987 // no body -> diagnose availability
2988 const AvailabilityAttr *AA = FindAvailabilityAttr(FD);
2989 if (AA)
2990 CheckDeclAvailability(
2991 FD, AA, SourceRange(RefExpr->getBeginLoc(), RefExpr->getEndLoc()));
2992}
2993
2994void DiagnoseHLSLAvailability::RunOnTranslationUnit(
2995 const TranslationUnitDecl *TU) {
2996 const TargetInfo &TargetInfo = SemaRef.getASTContext().getTargetInfo();
2997 std::string &EntryName = TargetInfo.getTargetOpts().HLSLEntry;
2998 bool IsLibraryShader = TargetInfo.getTriple().getEnvironment() ==
2999 llvm::Triple::EnvironmentType::Library;
3000 SourceLocation EntryLoc{};
3001
3002 // Iterate over all shader entry functions and library exports, and for those
3003 // that have a body (definiton), run diag scan on each, setting appropriate
3004 // shader environment context based on whether it is a shader entry function
3005 // or an exported function. Exported functions can be in namespaces and in
3006 // export declarations so we need to scan those declaration contexts as well.
3008 DeclContextsToScan.push_back(TU);
3009
3010 while (!DeclContextsToScan.empty()) {
3011 const DeclContext *DC = DeclContextsToScan.pop_back_val();
3012 for (auto &D : DC->decls()) {
3013 // do not scan implicit declaration generated by the implementation
3014 if (D->isImplicit())
3015 continue;
3016
3017 // for namespace or export declaration add the context to the list to be
3018 // scanned later
3019 if (llvm::dyn_cast<NamespaceDecl>(D) || llvm::dyn_cast<ExportDecl>(D)) {
3020 DeclContextsToScan.push_back(llvm::dyn_cast<DeclContext>(D));
3021 continue;
3022 }
3023
3024 // skip over other decls or function decls without body
3025 const FunctionDecl *FD = llvm::dyn_cast<FunctionDecl>(D);
3026 if (!FD || !FD->isThisDeclarationADefinition())
3027 continue;
3028
3029 // shader entry point
3030 if (HLSLShaderAttr *ShaderAttr = FD->getAttr<HLSLShaderAttr>()) {
3031 if (!IsLibraryShader && FD->getName() == EntryName) {
3032 if (EntryLoc.isValid()) {
3033 SemaRef.Diag(FD->getLocation(),
3034 diag::err_hlsl_ambiguous_entry_point)
3035 << EntryName;
3036 SemaRef.Diag(EntryLoc, diag::note_previous_declaration_as)
3037 << EntryName;
3038 return;
3039 }
3040 EntryLoc = FD->getLocation();
3041 }
3042 SetShaderStageContext(ShaderAttr->getType());
3043 RunOnFunction(FD);
3044 continue;
3045 }
3046 // exported library function
3047 // FIXME: replace this loop with external linkage check once issue #92071
3048 // is resolved
3049 bool isExport = FD->isInExportDeclContext();
3050 if (!isExport) {
3051 for (const auto *Redecl : FD->redecls()) {
3052 if (Redecl->isInExportDeclContext()) {
3053 isExport = true;
3054 break;
3055 }
3056 }
3057 }
3058 if (isExport) {
3059 SetUnknownShaderStageContext();
3060 RunOnFunction(FD);
3061 continue;
3062 }
3063 }
3064 }
3065
3066 if (!IsLibraryShader && EntryLoc.isInvalid()) {
3067 SemaRef.Diag(TU->getLocation(), diag::err_hlsl_missing_entry_point)
3068 << EntryName;
3069 return;
3070 }
3071}
3072
3073void DiagnoseHLSLAvailability::RunOnFunction(const FunctionDecl *FD) {
3074 assert(DeclsToScan.empty() && "DeclsToScan should be empty");
3075 DeclsToScan.push_back(FD);
3076
3077 while (!DeclsToScan.empty()) {
3078 // Take one decl from the stack and check it by traversing its AST.
3079 // For any CallExpr found during the traversal add it's callee to the top of
3080 // the stack to be processed next. Functions already processed are stored in
3081 // ScannedDecls.
3082 const FunctionDecl *FD = DeclsToScan.pop_back_val();
3083
3084 // Decl was already scanned
3085 const unsigned ScannedStages = GetScannedStages(FD);
3086 if (WasAlreadyScannedInCurrentStage(ScannedStages))
3087 continue;
3088
3089 ReportOnlyShaderStageIssues = !NeverBeenScanned(ScannedStages);
3090
3091 AddToScannedFunctions(FD);
3092 TraverseStmt(FD->getBody());
3093 }
3094}
3095
3096bool DiagnoseHLSLAvailability::HasMatchingEnvironmentOrNone(
3097 const AvailabilityAttr *AA) {
3098 const IdentifierInfo *IIEnvironment = AA->getEnvironment();
3099 if (!IIEnvironment)
3100 return true;
3101
3102 llvm::Triple::EnvironmentType CurrentEnv = GetCurrentShaderEnvironment();
3103 if (CurrentEnv == llvm::Triple::UnknownEnvironment)
3104 return false;
3105
3106 llvm::Triple::EnvironmentType AttrEnv =
3107 AvailabilityAttr::getEnvironmentType(IIEnvironment->getName());
3108
3109 return CurrentEnv == AttrEnv;
3110}
3111
3112const AvailabilityAttr *
3113DiagnoseHLSLAvailability::FindAvailabilityAttr(const Decl *D) {
3114 AvailabilityAttr const *PartialMatch = nullptr;
3115 // Check each AvailabilityAttr to find the one for this platform.
3116 // For multiple attributes with the same platform try to find one for this
3117 // environment.
3118 for (const auto *A : D->attrs()) {
3119 if (const auto *Avail = dyn_cast<AvailabilityAttr>(A)) {
3120 const AvailabilityAttr *EffectiveAvail = Avail->getEffectiveAttr();
3121 StringRef AttrPlatform = EffectiveAvail->getPlatform()->getName();
3122 StringRef TargetPlatform =
3124
3125 // Match the platform name.
3126 if (AttrPlatform == TargetPlatform) {
3127 // Find the best matching attribute for this environment
3128 if (HasMatchingEnvironmentOrNone(EffectiveAvail))
3129 return Avail;
3130 PartialMatch = Avail;
3131 }
3132 }
3133 }
3134 return PartialMatch;
3135}
3136
3137// Check availability against target shader model version and current shader
3138// stage and emit diagnostic
3139void DiagnoseHLSLAvailability::CheckDeclAvailability(NamedDecl *D,
3140 const AvailabilityAttr *AA,
3141 SourceRange Range) {
3142
3143 const IdentifierInfo *IIEnv = AA->getEnvironment();
3144
3145 if (!IIEnv) {
3146 // The availability attribute does not have environment -> it depends only
3147 // on shader model version and not on specific the shader stage.
3148
3149 // Skip emitting the diagnostics if the diagnostic mode is set to
3150 // strict (-fhlsl-strict-availability) because all relevant diagnostics
3151 // were already emitted in the DiagnoseUnguardedAvailability scan
3152 // (SemaAvailability.cpp).
3153 if (SemaRef.getLangOpts().HLSLStrictAvailability)
3154 return;
3155
3156 // Do not report shader-stage-independent issues if scanning a function
3157 // that was already scanned in a different shader stage context (they would
3158 // be duplicate)
3159 if (ReportOnlyShaderStageIssues)
3160 return;
3161
3162 } else {
3163 // The availability attribute has environment -> we need to know
3164 // the current stage context to property diagnose it.
3165 if (InUnknownShaderStageContext())
3166 return;
3167 }
3168
3169 // Check introduced version and if environment matches
3170 bool EnvironmentMatches = HasMatchingEnvironmentOrNone(AA);
3171 VersionTuple Introduced = AA->getIntroduced();
3172 VersionTuple TargetVersion =
3174
3175 if (TargetVersion >= Introduced && EnvironmentMatches)
3176 return;
3177
3178 // Emit diagnostic message
3179 const TargetInfo &TI = SemaRef.getASTContext().getTargetInfo();
3180 llvm::StringRef PlatformName(
3181 AvailabilityAttr::getPrettyPlatformName(TI.getPlatformName()));
3182
3183 llvm::StringRef CurrentEnvStr =
3184 llvm::Triple::getEnvironmentTypeName(GetCurrentShaderEnvironment());
3185
3186 llvm::StringRef AttrEnvStr =
3187 AA->getEnvironment() ? AA->getEnvironment()->getName() : "";
3188 bool UseEnvironment = !AttrEnvStr.empty();
3189
3190 if (EnvironmentMatches) {
3191 SemaRef.Diag(Range.getBegin(), diag::warn_hlsl_availability)
3192 << Range << D << PlatformName << Introduced.getAsString()
3193 << UseEnvironment << CurrentEnvStr;
3194 } else {
3195 SemaRef.Diag(Range.getBegin(), diag::warn_hlsl_availability_unavailable)
3196 << Range << D;
3197 }
3198
3199 SemaRef.Diag(D->getLocation(), diag::note_partial_availability_specified_here)
3200 << D << PlatformName << Introduced.getAsString()
3201 << SemaRef.Context.getTargetInfo().getPlatformMinVersion().getAsString()
3202 << UseEnvironment << AttrEnvStr << CurrentEnvStr;
3203}
3204
3205} // namespace
3206
3208 // process default CBuffer - create buffer layout struct and invoke codegenCGH
3209 if (!DefaultCBufferDecls.empty()) {
3211 SemaRef.getASTContext(), SemaRef.getCurLexicalContext(),
3212 DefaultCBufferDecls);
3213 addImplicitBindingAttrToDecl(SemaRef, DefaultCBuffer, RegisterType::CBuffer,
3215 SemaRef.getCurLexicalContext()->addDecl(DefaultCBuffer);
3217
3218 // Set HasValidPackoffset if any of the decls has a register(c#) annotation;
3219 for (const Decl *VD : DefaultCBufferDecls) {
3220 const HLSLResourceBindingAttr *RBA =
3221 VD->getAttr<HLSLResourceBindingAttr>();
3222 if (RBA && RBA->hasRegisterSlot() &&
3223 RBA->getRegisterType() == HLSLResourceBindingAttr::RegisterType::C) {
3224 DefaultCBuffer->setHasValidPackoffset(true);
3225 break;
3226 }
3227 }
3228
3229 DeclGroupRef DG(DefaultCBuffer);
3230 SemaRef.Consumer.HandleTopLevelDecl(DG);
3231 }
3232 diagnoseAvailabilityViolations(TU);
3233}
3234
3235// For resource member access through a global struct array, verify that the
3236// array index selecting the struct element is a constant integer expression.
3237// Returns false if the member expression is invalid.
3239 assert((ME->getType()->isHLSLResourceRecord() ||
3241 "expected member expr to have resource record type or array of them");
3242
3243 // Walk the AST from MemberExpr to the VarDecl of the parent struct instance
3244 // and take note of any non-constant array indexing along the way. If the
3245 // VarDecl we find is a global variable, report error if there was any
3246 // non-constant array index in the resource member access along the way.
3247 const Expr *NonConstIndexExpr = nullptr;
3248 const Expr *E = ME->getBase();
3249 while (E) {
3250 if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
3251 if (!NonConstIndexExpr)
3252 return true;
3253
3254 const VarDecl *VD = cast<VarDecl>(DRE->getDecl());
3255 if (!VD->hasGlobalStorage())
3256 return true;
3257
3258 SemaRef.Diag(NonConstIndexExpr->getExprLoc(),
3259 diag::err_hlsl_resource_member_array_access_not_constant);
3260 return false;
3261 }
3262
3263 if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(E)) {
3264 const Expr *IdxExpr = ASE->getIdx();
3265 if (!IdxExpr->isIntegerConstantExpr(SemaRef.getASTContext()))
3266 NonConstIndexExpr = IdxExpr;
3267 E = ASE->getBase();
3268 } else if (const auto *SubME = dyn_cast<MemberExpr>(E)) {
3269 E = SubME->getBase();
3270 } else if (const auto *ICE = dyn_cast<ImplicitCastExpr>(E)) {
3271 E = ICE->getSubExpr();
3272 } else {
3273 llvm_unreachable("unexpected expr type in resource member access");
3274 }
3275 }
3276 return true;
3277}
3278
3280 CXXRecordDecl *RD) {
3281 QualType AddrSpaceType =
3282 SemaRef.Context.getCanonicalType(SemaRef.Context.getAddrSpaceQualType(
3283 Type.withConst(), LangAS::hlsl_constant));
3284 QualType ReturnTy = SemaRef.Context.getCanonicalType(
3285 SemaRef.Context.getLValueReferenceType(AddrSpaceType));
3286
3287 DeclarationName ConvName =
3288 SemaRef.Context.DeclarationNames.getCXXConversionFunctionName(
3289 CanQualType::CreateUnsafe(ReturnTy));
3290 LookupResult ConvR(SemaRef, ConvName, SourceLocation(),
3292 [[maybe_unused]] bool LookupSucceeded =
3293 SemaRef.LookupQualifiedName(ConvR, RD);
3294 assert(LookupSucceeded);
3295
3296 for (NamedDecl *D : ConvR) {
3298 return D;
3299 }
3300 return nullptr;
3301}
3302
3303std::optional<ExprResult>
3305 QualType BaseType = BaseExpr->getType();
3306 const HLSLAttributedResourceType *ResTy =
3307 HLSLAttributedResourceType::findHandleTypeOnResource(
3308 BaseType.getTypePtr());
3309 if (!ResTy ||
3310 ResTy->getAttrs().ResourceClass != llvm::dxil::ResourceClass::CBuffer)
3311 return std::nullopt;
3312
3313 QualType TemplateType = ResTy->getContainedType();
3314
3315 NamedDecl *NamedConversionDecl = getConstantBufferConversionFunction(
3316 TemplateType, BaseType->getAsCXXRecordDecl());
3317 assert(NamedConversionDecl &&
3318 "Could not find conversion function for ConstantBuffer.");
3319 auto *ConversionDecl =
3320 cast<CXXConversionDecl>(NamedConversionDecl->getUnderlyingDecl());
3321
3322 return SemaRef.BuildCXXMemberCallExpr(BaseExpr, NamedConversionDecl,
3323 ConversionDecl,
3324 /*HadMultipleCandidates=*/false);
3325}
3326
3327void SemaHLSL::diagnoseAvailabilityViolations(TranslationUnitDecl *TU) {
3328 // Skip running the diagnostics scan if the diagnostic mode is
3329 // strict (-fhlsl-strict-availability) and the target shader stage is known
3330 // because all relevant diagnostics were already emitted in the
3331 // DiagnoseUnguardedAvailability scan (SemaAvailability.cpp).
3333 if (SemaRef.getLangOpts().HLSLStrictAvailability &&
3334 TI.getTriple().getEnvironment() != llvm::Triple::EnvironmentType::Library)
3335 return;
3336
3337 DiagnoseHLSLAvailability(SemaRef).RunOnTranslationUnit(TU);
3338}
3339
3340static bool CheckAllArgsHaveSameType(Sema *S, CallExpr *TheCall) {
3341 assert(TheCall->getNumArgs() > 1);
3342 QualType ArgTy0 = TheCall->getArg(0)->getType();
3343
3344 for (unsigned I = 1, N = TheCall->getNumArgs(); I < N; ++I) {
3346 ArgTy0, TheCall->getArg(I)->getType())) {
3347 S->Diag(TheCall->getBeginLoc(), diag::err_vec_builtin_incompatible_vector)
3348 << TheCall->getDirectCallee() << /*useAllTerminology*/ true
3349 << SourceRange(TheCall->getArg(0)->getBeginLoc(),
3350 TheCall->getArg(N - 1)->getEndLoc());
3351 return true;
3352 }
3353 }
3354 return false;
3355}
3356
3358 QualType ArgType = Arg->getType();
3360 S->Diag(Arg->getBeginLoc(), diag::err_typecheck_convert_incompatible)
3361 << ArgType << ExpectedType << 1 << 0 << 0;
3362 return true;
3363 }
3364 return false;
3365}
3366
3368 Sema *S, CallExpr *TheCall,
3369 llvm::function_ref<bool(Sema *S, SourceLocation Loc, int ArgOrdinal,
3370 clang::QualType PassedType)>
3371 Check) {
3372 for (unsigned I = 0; I < TheCall->getNumArgs(); ++I) {
3373 Expr *Arg = TheCall->getArg(I);
3374 if (Check(S, Arg->getBeginLoc(), I + 1, Arg->getType()))
3375 return true;
3376 }
3377 return false;
3378}
3379
3381 int ArgOrdinal,
3382 clang::QualType PassedType) {
3383 clang::QualType BaseType =
3384 PassedType->isVectorType()
3385 ? PassedType->castAs<clang::VectorType>()->getElementType()
3386 : PassedType;
3387 if (!BaseType->isFloat32Type())
3388 return S->Diag(Loc, diag::err_builtin_invalid_arg_type)
3389 << ArgOrdinal << /* scalar or vector of */ 5 << /* no int */ 0
3390 << /* float */ 1 << PassedType;
3391 return false;
3392}
3393
3395 int ArgOrdinal,
3396 clang::QualType PassedType) {
3397 clang::QualType BaseType = PassedType;
3398 if (const auto *VT = PassedType->getAs<clang::VectorType>())
3399 BaseType = VT->getElementType();
3400 else if (const auto *MT = PassedType->getAs<clang::MatrixType>())
3401 BaseType = MT->getElementType();
3402
3403 if (!BaseType->isHalfType() && !BaseType->isFloat32Type())
3404 return S->Diag(Loc, diag::err_builtin_invalid_arg_type)
3405 << ArgOrdinal << /* scalar or vector of */ 5 << /* no int */ 0
3406 << /* half or float */ 2 << PassedType;
3407 return false;
3408}
3409
3411 int ArgOrdinal,
3412 clang::QualType PassedType) {
3413 clang::QualType BaseType =
3414 PassedType->isVectorType()
3415 ? PassedType->castAs<clang::VectorType>()->getElementType()
3416 : PassedType->isMatrixType()
3417 ? PassedType->castAs<clang::MatrixType>()->getElementType()
3418 : PassedType;
3419 if (!BaseType->isDoubleType()) {
3420 // FIXME: adopt standard `err_builtin_invalid_arg_type` instead of using
3421 // this custom error.
3422 return S->Diag(Loc, diag::err_builtin_requires_double_type)
3423 << ArgOrdinal << PassedType;
3424 }
3425
3426 return false;
3427}
3428
3429static bool CheckModifiableLValue(Sema *S, CallExpr *TheCall,
3430 unsigned ArgIndex) {
3431 auto *Arg = TheCall->getArg(ArgIndex);
3432 SourceLocation OrigLoc = Arg->getExprLoc();
3433 if (Arg->IgnoreCasts()->isModifiableLvalue(S->Context, &OrigLoc) ==
3435 return false;
3436 S->Diag(OrigLoc, diag::error_hlsl_inout_lvalue) << Arg << 0;
3437 return true;
3438}
3439
3440// Verifies that the argument at `ArgIndex` of `TheCall` refers to memory in
3441// one of `AllowedSpaces`. Intended for HLSL builtins (e.g. atomics).
3442static bool CheckArgAddrSpaceOneOf(Sema *S, CallExpr *TheCall,
3443 unsigned ArgIndex,
3444 ArrayRef<LangAS> AllowedSpaces) {
3445 Expr *Arg = TheCall->getArg(ArgIndex);
3446 QualType LValueTy = Arg->IgnoreCasts()->getType();
3447 if (llvm::is_contained(AllowedSpaces, LValueTy.getAddressSpace()))
3448 return false;
3449 S->Diag(Arg->getBeginLoc(), diag::err_hlsl_atomic_arg_addr_space)
3450 << (ArgIndex + 1) << LValueTy;
3451 return true;
3452}
3453
3454static bool CheckNoDoubleVectors(Sema *S, SourceLocation Loc, int ArgOrdinal,
3455 clang::QualType PassedType) {
3456 const auto *VecTy = PassedType->getAs<VectorType>();
3457 if (!VecTy)
3458 return false;
3459
3460 if (VecTy->getElementType()->isDoubleType())
3461 return S->Diag(Loc, diag::err_builtin_invalid_arg_type)
3462 << ArgOrdinal << /* scalar */ 1 << /* no int */ 0 << /* fp */ 1
3463 << PassedType;
3464 return false;
3465}
3466
3468 int ArgOrdinal,
3469 clang::QualType PassedType) {
3470 if (!PassedType->hasIntegerRepresentation() &&
3471 !PassedType->hasFloatingRepresentation())
3472 return S->Diag(Loc, diag::err_builtin_invalid_arg_type)
3473 << ArgOrdinal << /* scalar or vector of */ 5 << /* integer */ 1
3474 << /* fp */ 1 << PassedType;
3475 return false;
3476}
3477
3479 int ArgOrdinal,
3480 clang::QualType PassedType) {
3481 if (auto *VecTy = PassedType->getAs<VectorType>())
3482 if (VecTy->getElementType()->isUnsignedIntegerType())
3483 return false;
3484
3485 return S->Diag(Loc, diag::err_builtin_invalid_arg_type)
3486 << ArgOrdinal << /* vector of */ 4 << /* uint */ 3 << /* no fp */ 0
3487 << PassedType;
3488}
3489
3490// checks for unsigned ints of all sizes
3492 int ArgOrdinal,
3493 clang::QualType PassedType) {
3494 if (!PassedType->hasUnsignedIntegerRepresentation())
3495 return S->Diag(Loc, diag::err_builtin_invalid_arg_type)
3496 << ArgOrdinal << /* scalar or vector of */ 5 << /* unsigned int */ 3
3497 << /* no fp */ 0 << PassedType;
3498 return false;
3499}
3500
3501static bool CheckExpectedBitWidth(Sema *S, CallExpr *TheCall,
3502 unsigned ArgOrdinal, unsigned Width) {
3503 QualType ArgTy = TheCall->getArg(0)->getType();
3504 if (auto *VTy = ArgTy->getAs<VectorType>())
3505 ArgTy = VTy->getElementType();
3506 // ensure arg type has expected bit width
3507 uint64_t ElementBitCount =
3509 if (ElementBitCount != Width) {
3510 S->Diag(TheCall->getArg(0)->getBeginLoc(),
3511 diag::err_integer_incorrect_bit_count)
3512 << Width << ElementBitCount;
3513 return true;
3514 }
3515 return false;
3516}
3517
3519 QualType ReturnType) {
3520 auto *VecTyA = TheCall->getArg(0)->getType()->getAs<VectorType>();
3521 if (VecTyA)
3522 ReturnType =
3523 S->Context.getExtVectorType(ReturnType, VecTyA->getNumElements());
3524
3525 TheCall->setType(ReturnType);
3526}
3527
3528static bool CheckScalarOrVector(Sema *S, CallExpr *TheCall, QualType Scalar,
3529 unsigned ArgIndex) {
3530 assert(TheCall->getNumArgs() >= ArgIndex);
3531 QualType ArgType = TheCall->getArg(ArgIndex)->getType();
3532 auto *VTy = ArgType->getAs<VectorType>();
3533 // not the scalar or vector<scalar>
3534 if (!(S->Context.hasSameUnqualifiedType(ArgType, Scalar) ||
3535 (VTy &&
3536 S->Context.hasSameUnqualifiedType(VTy->getElementType(), Scalar)))) {
3537 S->Diag(TheCall->getArg(0)->getBeginLoc(),
3538 diag::err_typecheck_expect_scalar_or_vector)
3539 << ArgType << Scalar;
3540 return true;
3541 }
3542 return false;
3543}
3544
3546 QualType Scalar, unsigned ArgIndex) {
3547 assert(TheCall->getNumArgs() > ArgIndex);
3548
3549 Expr *Arg = TheCall->getArg(ArgIndex);
3550 QualType ArgType = Arg->getType();
3551
3552 // Scalar: T
3553 if (S->Context.hasSameUnqualifiedType(ArgType, Scalar))
3554 return false;
3555
3556 // Vector: vector<T>
3557 if (const auto *VTy = ArgType->getAs<VectorType>()) {
3558 if (S->Context.hasSameUnqualifiedType(VTy->getElementType(), Scalar))
3559 return false;
3560 }
3561
3562 // Matrix: ConstantMatrixType with element type T
3563 if (const auto *MTy = ArgType->getAs<ConstantMatrixType>()) {
3564 if (S->Context.hasSameUnqualifiedType(MTy->getElementType(), Scalar))
3565 return false;
3566 }
3567
3568 // Not a scalar/vector/matrix-of-scalar
3569 S->Diag(Arg->getBeginLoc(),
3570 diag::err_typecheck_expect_scalar_or_vector_or_matrix)
3571 << ArgType << Scalar;
3572 return true;
3573}
3574
3575static bool CheckAnyScalarOrVector(Sema *S, CallExpr *TheCall,
3576 unsigned ArgIndex) {
3577 assert(TheCall->getNumArgs() >= ArgIndex);
3578 QualType ArgType = TheCall->getArg(ArgIndex)->getType();
3579 auto *VTy = ArgType->getAs<VectorType>();
3580 // not the scalar or vector<scalar>
3581 if (!(ArgType->isScalarType() ||
3582 (VTy && VTy->getElementType()->isScalarType()))) {
3583 S->Diag(TheCall->getArg(0)->getBeginLoc(),
3584 diag::err_typecheck_expect_any_scalar_or_vector)
3585 << ArgType << 1;
3586 return true;
3587 }
3588 return false;
3589}
3590
3591// Check that the argument is not a bool or vector<bool>
3592// Returns true on error
3594 unsigned ArgIndex) {
3595 QualType BoolType = S->getASTContext().BoolTy;
3596 assert(ArgIndex < TheCall->getNumArgs());
3597 QualType ArgType = TheCall->getArg(ArgIndex)->getType();
3598 auto *VTy = ArgType->getAs<VectorType>();
3599 // is the bool or vector<bool>
3600 if (S->Context.hasSameUnqualifiedType(ArgType, BoolType) ||
3601 (VTy &&
3602 S->Context.hasSameUnqualifiedType(VTy->getElementType(), BoolType))) {
3603 S->Diag(TheCall->getArg(0)->getBeginLoc(),
3604 diag::err_typecheck_expect_any_scalar_or_vector)
3605 << ArgType << 0;
3606 return true;
3607 }
3608 return false;
3609}
3610
3611static bool CheckWaveActive(Sema *S, CallExpr *TheCall) {
3612 if (CheckNotBoolScalarOrVector(S, TheCall, 0))
3613 return true;
3614 return false;
3615}
3616
3617static bool CheckWavePrefix(Sema *S, CallExpr *TheCall) {
3618 if (CheckNotBoolScalarOrVector(S, TheCall, 0))
3619 return true;
3620 return false;
3621}
3622
3623static bool CheckBoolSelect(Sema *S, CallExpr *TheCall) {
3624 assert(TheCall->getNumArgs() == 3);
3625 Expr *Arg1 = TheCall->getArg(1);
3626 Expr *Arg2 = TheCall->getArg(2);
3627 if (!S->Context.hasSameUnqualifiedType(Arg1->getType(), Arg2->getType())) {
3628 S->Diag(TheCall->getBeginLoc(),
3629 diag::err_typecheck_call_different_arg_types)
3630 << Arg1->getType() << Arg2->getType() << Arg1->getSourceRange()
3631 << Arg2->getSourceRange();
3632 return true;
3633 }
3634
3635 TheCall->setType(Arg1->getType());
3636 return false;
3637}
3638
3639static bool CheckVectorSelect(Sema *S, CallExpr *TheCall) {
3640 assert(TheCall->getNumArgs() == 3);
3641 Expr *Arg1 = TheCall->getArg(1);
3642 QualType Arg1Ty = Arg1->getType();
3643 Expr *Arg2 = TheCall->getArg(2);
3644 QualType Arg2Ty = Arg2->getType();
3645
3646 QualType Arg1ScalarTy = Arg1Ty;
3647 if (auto VTy = Arg1ScalarTy->getAs<VectorType>())
3648 Arg1ScalarTy = VTy->getElementType();
3649
3650 QualType Arg2ScalarTy = Arg2Ty;
3651 if (auto VTy = Arg2ScalarTy->getAs<VectorType>())
3652 Arg2ScalarTy = VTy->getElementType();
3653
3654 if (!S->Context.hasSameUnqualifiedType(Arg1ScalarTy, Arg2ScalarTy))
3655 S->Diag(Arg1->getBeginLoc(), diag::err_hlsl_builtin_scalar_vector_mismatch)
3656 << /* second and third */ 1 << TheCall->getCallee() << Arg1Ty << Arg2Ty;
3657
3658 QualType Arg0Ty = TheCall->getArg(0)->getType();
3659 unsigned Arg0Length = Arg0Ty->getAs<VectorType>()->getNumElements();
3660 unsigned Arg1Length = Arg1Ty->isVectorType()
3661 ? Arg1Ty->getAs<VectorType>()->getNumElements()
3662 : 0;
3663 unsigned Arg2Length = Arg2Ty->isVectorType()
3664 ? Arg2Ty->getAs<VectorType>()->getNumElements()
3665 : 0;
3666 if (Arg1Length > 0 && Arg0Length != Arg1Length) {
3667 S->Diag(TheCall->getBeginLoc(),
3668 diag::err_typecheck_vector_lengths_not_equal)
3669 << Arg0Ty << Arg1Ty << TheCall->getArg(0)->getSourceRange()
3670 << Arg1->getSourceRange();
3671 return true;
3672 }
3673
3674 if (Arg2Length > 0 && Arg0Length != Arg2Length) {
3675 S->Diag(TheCall->getBeginLoc(),
3676 diag::err_typecheck_vector_lengths_not_equal)
3677 << Arg0Ty << Arg2Ty << TheCall->getArg(0)->getSourceRange()
3678 << Arg2->getSourceRange();
3679 return true;
3680 }
3681
3682 TheCall->setType(
3683 S->getASTContext().getExtVectorType(Arg1ScalarTy, Arg0Length));
3684 return false;
3685}
3686
3687static bool CheckIndexType(Sema *S, CallExpr *TheCall, unsigned IndexArgIndex) {
3688 assert(TheCall->getNumArgs() > IndexArgIndex && "Index argument missing");
3689 QualType ArgType = TheCall->getArg(IndexArgIndex)->getType();
3690 QualType IndexTy = ArgType;
3691 unsigned int ActualDim = 1;
3692 if (const auto *VTy = IndexTy->getAs<VectorType>()) {
3693 ActualDim = VTy->getNumElements();
3694 IndexTy = VTy->getElementType();
3695 }
3696 if (!IndexTy->isIntegerType()) {
3697 S->Diag(TheCall->getArg(IndexArgIndex)->getBeginLoc(),
3698 diag::err_typecheck_expect_int)
3699 << ArgType;
3700 return true;
3701 }
3702
3703 QualType ResourceArgTy = TheCall->getArg(0)->getType();
3704 const HLSLAttributedResourceType *ResTy =
3705 ResourceArgTy.getTypePtr()->getAs<HLSLAttributedResourceType>();
3706 assert(ResTy && "Resource argument must be a resource");
3707 HLSLAttributedResourceType::Attributes ResAttrs = ResTy->getAttrs();
3708
3709 unsigned int ExpectedDim = 1;
3710 if (ResAttrs.ResourceDimension != llvm::dxil::ResourceDimension::Unknown)
3711 ExpectedDim = getResourceDimensions(ResAttrs.ResourceDimension) +
3712 (ResAttrs.IsArray ? 1 : 0);
3713
3714 if (ActualDim != ExpectedDim) {
3715 S->Diag(TheCall->getArg(IndexArgIndex)->getBeginLoc(),
3716 diag::err_hlsl_builtin_resource_coordinate_dimension_mismatch)
3717 << cast<NamedDecl>(TheCall->getCalleeDecl()) << ExpectedDim
3718 << ActualDim;
3719 return true;
3720 }
3721
3722 return false;
3723}
3724
3726 Sema *S, CallExpr *TheCall, unsigned ArgIndex,
3727 llvm::function_ref<bool(const HLSLAttributedResourceType *ResType)> Check =
3728 nullptr) {
3729 assert(TheCall->getNumArgs() >= ArgIndex);
3730 QualType ArgType = TheCall->getArg(ArgIndex)->getType();
3731 const HLSLAttributedResourceType *ResTy =
3732 ArgType.getTypePtr()->getAs<HLSLAttributedResourceType>();
3733 if (!ResTy) {
3734 S->Diag(TheCall->getArg(ArgIndex)->getBeginLoc(),
3735 diag::err_typecheck_expect_hlsl_resource)
3736 << ArgType;
3737 return true;
3738 }
3739 if (Check && Check(ResTy)) {
3740 S->Diag(TheCall->getArg(ArgIndex)->getExprLoc(),
3741 diag::err_invalid_hlsl_resource_type)
3742 << ArgType;
3743 return true;
3744 }
3745 return false;
3746}
3747
3748static bool CheckVectorElementCount(Sema *S, QualType PassedType,
3749 QualType BaseType, unsigned ExpectedCount,
3750 SourceLocation Loc) {
3751 unsigned PassedCount = 1;
3752 if (const auto *VecTy = PassedType->getAs<VectorType>())
3753 PassedCount = VecTy->getNumElements();
3754
3755 if (PassedCount != ExpectedCount) {
3757 S->Context.getExtVectorType(BaseType, ExpectedCount);
3758 S->Diag(Loc, diag::err_typecheck_convert_incompatible)
3759 << PassedType << ExpectedType << 1 << 0 << 0;
3760 return true;
3761 }
3762 return false;
3763}
3764
3765enum class SampleKind { Sample, Bias, Grad, Level, Cmp, CmpLevelZero };
3766
3768 bool IncludeArraySlice = true) {
3769 // Check the texture handle.
3770 if (CheckResourceHandle(&S, TheCall, 0,
3771 [](const HLSLAttributedResourceType *ResType) {
3772 return ResType->getAttrs().ResourceDimension ==
3773 llvm::dxil::ResourceDimension::Unknown;
3774 }))
3775 return true;
3776
3777 // Check the sampler handle.
3778 if (CheckResourceHandle(&S, TheCall, 1,
3779 [](const HLSLAttributedResourceType *ResType) {
3780 return ResType->getAttrs().ResourceClass !=
3781 llvm::hlsl::ResourceClass::Sampler;
3782 }))
3783 return true;
3784
3785 auto *ResourceTy =
3786 TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
3787
3788 // Check the location.
3789 unsigned ExpectedDim =
3790 getResourceDimensions(ResourceTy->getAttrs().ResourceDimension) +
3791 (IncludeArraySlice && ResourceTy->getAttrs().IsArray ? 1 : 0);
3792 if (CheckVectorElementCount(&S, TheCall->getArg(2)->getType(),
3793 S.Context.FloatTy, ExpectedDim,
3794 TheCall->getBeginLoc()))
3795 return true;
3796
3797 return false;
3798}
3799
3800static bool CheckCalculateLodBuiltin(Sema &S, CallExpr *TheCall) {
3801 if (S.checkArgCount(TheCall, 3))
3802 return true;
3803
3804 // CalculateLevelOfDetail location uses resource dimension only (e.g. float2
3805 // for 2D), not an extra array slice component like Sample/Gather.
3806 if (CheckTextureSamplerAndLocation(S, TheCall, /*IncludeArraySlice=*/false))
3807 return true;
3808
3809 TheCall->setType(S.Context.FloatTy);
3810 return false;
3811}
3812
3813static bool CheckGatherBuiltin(Sema &S, CallExpr *TheCall, bool IsCmp) {
3814 if (S.checkArgCountRange(TheCall, IsCmp ? 5 : 4, IsCmp ? 6 : 5))
3815 return true;
3816
3817 if (CheckTextureSamplerAndLocation(S, TheCall))
3818 return true;
3819
3820 unsigned NextIdx = 3;
3821 if (IsCmp) {
3822 // Check the compare value.
3823 QualType CmpTy = TheCall->getArg(NextIdx)->getType();
3824 if (!CmpTy->isFloatingType() || CmpTy->isVectorType()) {
3825 S.Diag(TheCall->getArg(NextIdx)->getBeginLoc(),
3826 diag::err_typecheck_convert_incompatible)
3827 << CmpTy << S.Context.FloatTy << 1 << 0 << 0;
3828 return true;
3829 }
3830 NextIdx++;
3831 }
3832
3833 // Check the component operand.
3834 Expr *ComponentArg = TheCall->getArg(NextIdx);
3835 QualType ComponentTy = ComponentArg->getType();
3836 if (!ComponentTy->isIntegerType() || ComponentTy->isVectorType()) {
3837 S.Diag(ComponentArg->getBeginLoc(),
3838 diag::err_typecheck_convert_incompatible)
3839 << ComponentTy << S.Context.UnsignedIntTy << 1 << 0 << 0;
3840 return true;
3841 }
3842
3843 // GatherCmp operations on Vulkan target must use component 0 (Red).
3844 if (IsCmp && S.getASTContext().getTargetInfo().getTriple().isSPIRV()) {
3845 std::optional<llvm::APSInt> ComponentOpt =
3846 ComponentArg->getIntegerConstantExpr(S.getASTContext());
3847 if (ComponentOpt) {
3848 int64_t ComponentVal = ComponentOpt->getSExtValue();
3849 if (ComponentVal != 0) {
3850 // Issue an error if the component is not 0 (Red).
3851 // 0 -> Red, 1 -> Green, 2 -> Blue, 3 -> Alpha
3852 assert(ComponentVal >= 0 && ComponentVal <= 3 &&
3853 "The component is not in the expected range.");
3854 S.Diag(ComponentArg->getBeginLoc(),
3855 diag::err_hlsl_gathercmp_invalid_component)
3856 << ComponentVal;
3857 return true;
3858 }
3859 }
3860 }
3861
3862 NextIdx++;
3863
3864 // Check the offset operand.
3865 const HLSLAttributedResourceType *ResourceTy =
3866 TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
3867 if (TheCall->getNumArgs() > NextIdx) {
3868 unsigned ExpectedDim =
3869 getResourceDimensions(ResourceTy->getAttrs().ResourceDimension);
3870 if (CheckVectorElementCount(&S, TheCall->getArg(NextIdx)->getType(),
3871 S.Context.IntTy, ExpectedDim,
3872 TheCall->getArg(NextIdx)->getBeginLoc()))
3873 return true;
3874 NextIdx++;
3875 }
3876
3877 assert(ResourceTy->hasContainedType() &&
3878 "Expecting a contained type for resource with a dimension "
3879 "attribute.");
3880 QualType ReturnType = ResourceTy->getContainedType();
3881
3882 if (IsCmp) {
3883 if (!ReturnType->hasFloatingRepresentation()) {
3884 S.Diag(TheCall->getBeginLoc(), diag::err_hlsl_samplecmp_requires_float);
3885 return true;
3886 }
3887 }
3888
3889 if (const auto *VecTy = ReturnType->getAs<VectorType>())
3890 ReturnType = VecTy->getElementType();
3891 ReturnType = S.Context.getExtVectorType(ReturnType, 4);
3892
3893 TheCall->setType(ReturnType);
3894
3895 return false;
3896}
3897static bool CheckLoadLevelBuiltin(Sema &S, CallExpr *TheCall) {
3898 if (S.checkArgCountRange(TheCall, 2, 3))
3899 return true;
3900
3901 // Check the texture handle.
3902 if (CheckResourceHandle(&S, TheCall, 0,
3903 [](const HLSLAttributedResourceType *ResType) {
3904 return ResType->getAttrs().ResourceDimension ==
3905 llvm::dxil::ResourceDimension::Unknown;
3906 }))
3907 return true;
3908
3909 auto *ResourceTy =
3910 TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
3911
3912 // Check the location + lod (int3 for Texture2D, int4 for Texture2DArray).
3913 unsigned ResourceDim =
3914 getResourceDimensions(ResourceTy->getAttrs().ResourceDimension);
3915 unsigned LocationDim = ResourceDim + (ResourceTy->getAttrs().IsArray ? 1 : 0);
3916 QualType CoordLODTy = TheCall->getArg(1)->getType();
3917 if (CheckVectorElementCount(&S, CoordLODTy, S.Context.IntTy, LocationDim + 1,
3918 TheCall->getArg(1)->getBeginLoc()))
3919 return true;
3920
3921 QualType EltTy = CoordLODTy;
3922 if (const auto *VTy = EltTy->getAs<VectorType>())
3923 EltTy = VTy->getElementType();
3924 if (!EltTy->isIntegerType()) {
3925 S.Diag(TheCall->getArg(1)->getBeginLoc(), diag::err_typecheck_expect_int)
3926 << CoordLODTy;
3927 return true;
3928 }
3929
3930 // Check the offset operand (int2 for 2D textures; no array slice).
3931 if (TheCall->getNumArgs() > 2) {
3932 if (CheckVectorElementCount(&S, TheCall->getArg(2)->getType(),
3933 S.Context.IntTy, ResourceDim,
3934 TheCall->getArg(2)->getBeginLoc()))
3935 return true;
3936 }
3937
3938 TheCall->setType(ResourceTy->getContainedType());
3939 return false;
3940}
3941
3942static bool CheckSamplingBuiltin(Sema &S, CallExpr *TheCall, SampleKind Kind) {
3943 unsigned MinArgs, MaxArgs;
3944 if (Kind == SampleKind::Sample) {
3945 MinArgs = 3;
3946 MaxArgs = 5;
3947 } else if (Kind == SampleKind::Bias) {
3948 MinArgs = 4;
3949 MaxArgs = 6;
3950 } else if (Kind == SampleKind::Grad) {
3951 MinArgs = 5;
3952 MaxArgs = 7;
3953 } else if (Kind == SampleKind::Level) {
3954 MinArgs = 4;
3955 MaxArgs = 5;
3956 } else if (Kind == SampleKind::Cmp) {
3957 MinArgs = 4;
3958 MaxArgs = 6;
3959 } else {
3960 assert(Kind == SampleKind::CmpLevelZero);
3961 MinArgs = 4;
3962 MaxArgs = 5;
3963 }
3964
3965 if (S.checkArgCountRange(TheCall, MinArgs, MaxArgs))
3966 return true;
3967
3968 if (CheckTextureSamplerAndLocation(S, TheCall))
3969 return true;
3970
3971 const HLSLAttributedResourceType *ResourceTy =
3972 TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
3973 unsigned ExpectedDim =
3974 getResourceDimensions(ResourceTy->getAttrs().ResourceDimension);
3975
3976 unsigned NextIdx = 3;
3977 if (Kind == SampleKind::Bias || Kind == SampleKind::Level ||
3978 Kind == SampleKind::Cmp || Kind == SampleKind::CmpLevelZero) {
3979 // Check the bias, lod level, or compare value, depending on the kind.
3980 // All of them must be a scalar float value.
3981 QualType BiasOrLODOrCmpTy = TheCall->getArg(NextIdx)->getType();
3982 if (!BiasOrLODOrCmpTy->isFloatingType() ||
3983 BiasOrLODOrCmpTy->isVectorType()) {
3984 S.Diag(TheCall->getArg(NextIdx)->getBeginLoc(),
3985 diag::err_typecheck_convert_incompatible)
3986 << BiasOrLODOrCmpTy << S.Context.FloatTy << 1 << 0 << 0;
3987 return true;
3988 }
3989 NextIdx++;
3990 } else if (Kind == SampleKind::Grad) {
3991 // Check the DDX operand.
3992 if (CheckVectorElementCount(&S, TheCall->getArg(NextIdx)->getType(),
3993 S.Context.FloatTy, ExpectedDim,
3994 TheCall->getArg(NextIdx)->getBeginLoc()))
3995 return true;
3996
3997 // Check the DDY operand.
3998 if (CheckVectorElementCount(&S, TheCall->getArg(NextIdx + 1)->getType(),
3999 S.Context.FloatTy, ExpectedDim,
4000 TheCall->getArg(NextIdx + 1)->getBeginLoc()))
4001 return true;
4002 NextIdx += 2;
4003 }
4004
4005 // Check the offset operand.
4006 if (TheCall->getNumArgs() > NextIdx) {
4007 if (CheckVectorElementCount(&S, TheCall->getArg(NextIdx)->getType(),
4008 S.Context.IntTy, ExpectedDim,
4009 TheCall->getArg(NextIdx)->getBeginLoc()))
4010 return true;
4011 NextIdx++;
4012 }
4013
4014 // Check the clamp operand.
4015 if (Kind != SampleKind::Level && Kind != SampleKind::CmpLevelZero &&
4016 TheCall->getNumArgs() > NextIdx) {
4017 QualType ClampTy = TheCall->getArg(NextIdx)->getType();
4018 if (!ClampTy->isFloatingType() || ClampTy->isVectorType()) {
4019 S.Diag(TheCall->getArg(NextIdx)->getBeginLoc(),
4020 diag::err_typecheck_convert_incompatible)
4021 << ClampTy << S.Context.FloatTy << 1 << 0 << 0;
4022 return true;
4023 }
4024 }
4025
4026 assert(ResourceTy->hasContainedType() &&
4027 "Expecting a contained type for resource with a dimension "
4028 "attribute.");
4029 QualType ReturnType = ResourceTy->getContainedType();
4030 if (Kind == SampleKind::Cmp || Kind == SampleKind::CmpLevelZero) {
4031 if (!ReturnType->hasFloatingRepresentation()) {
4032 S.Diag(TheCall->getBeginLoc(), diag::err_hlsl_samplecmp_requires_float);
4033 return true;
4034 }
4035 ReturnType = S.Context.FloatTy;
4036 }
4037 TheCall->setType(ReturnType);
4038
4039 return false;
4040}
4041
4042// Note: returning true in this case results in CheckBuiltinFunctionCall
4043// returning an ExprError
4044bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
4045 switch (BuiltinID) {
4046 case Builtin::BI__builtin_hlsl_adduint64: {
4047 if (SemaRef.checkArgCount(TheCall, 2))
4048 return true;
4049
4050 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
4052 return true;
4053
4054 // ensure arg integers are 32-bits
4055 if (CheckExpectedBitWidth(&SemaRef, TheCall, 0, 32))
4056 return true;
4057
4058 // ensure both args are vectors of total bit size of a multiple of 64
4059 auto *VTy = TheCall->getArg(0)->getType()->getAs<VectorType>();
4060 int NumElementsArg = VTy->getNumElements();
4061 if (NumElementsArg != 2 && NumElementsArg != 4) {
4062 SemaRef.Diag(TheCall->getBeginLoc(), diag::err_vector_incorrect_bit_count)
4063 << 1 /*a multiple of*/ << 64 << NumElementsArg * 32;
4064 return true;
4065 }
4066
4067 // ensure first arg and second arg have the same type
4068 if (CheckAllArgsHaveSameType(&SemaRef, TheCall))
4069 return true;
4070
4071 ExprResult A = TheCall->getArg(0);
4072 QualType ArgTyA = A.get()->getType();
4073 // return type is the same as the input type
4074 TheCall->setType(ArgTyA);
4075 break;
4076 }
4077 case Builtin::BI__builtin_hlsl_resource_getpointer: {
4078 if (SemaRef.checkArgCountRange(TheCall, 1, 2) ||
4079 CheckResourceHandle(&SemaRef, TheCall, 0) ||
4080 (TheCall->getNumArgs() == 2 && CheckIndexType(&SemaRef, TheCall, 1)))
4081 return true;
4082
4083 auto *ResourceTy =
4084 TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
4085 QualType ContainedTy = ResourceTy->getContainedType();
4086 auto ReturnType = SemaRef.Context.getAddrSpaceQualType(
4087 ContainedTy,
4088 getLangASFromResourceClass(ResourceTy->getAttrs().ResourceClass));
4089 ReturnType = SemaRef.Context.getPointerType(ReturnType);
4090 TheCall->setType(ReturnType);
4091
4092 break;
4093 }
4094 case Builtin::BI__builtin_hlsl_resource_getpointer_typed: {
4095 if (SemaRef.checkArgCount(TheCall, 3) ||
4096 CheckResourceHandle(&SemaRef, TheCall, 0) ||
4097 CheckIndexType(&SemaRef, TheCall, 1))
4098 return true;
4099
4100 QualType ElementTy = TheCall->getArg(2)->getType();
4101 assert(ElementTy->isPointerType() &&
4102 "expected pointer type for second argument");
4103 ElementTy = ElementTy->getPointeeType();
4104
4105 // Reject array types
4106 if (ElementTy->isArrayType())
4107 return SemaRef.Diag(
4108 cast<FunctionDecl>(SemaRef.CurContext)->getPointOfInstantiation(),
4109 diag::err_invalid_use_of_array_type);
4110
4111 auto *ResourceTy =
4112 TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
4113 auto ReturnType = SemaRef.Context.getAddrSpaceQualType(
4114 ElementTy,
4115 getLangASFromResourceClass(ResourceTy->getAttrs().ResourceClass));
4116 ReturnType = SemaRef.Context.getPointerType(ReturnType);
4117 TheCall->setType(ReturnType);
4118
4119 break;
4120 }
4121 case Builtin::BI__builtin_hlsl_resource_load_with_status: {
4122 if (SemaRef.checkArgCount(TheCall, 3) ||
4123 CheckResourceHandle(&SemaRef, TheCall, 0) ||
4124 CheckArgTypeMatches(&SemaRef, TheCall->getArg(1),
4125 SemaRef.getASTContext().UnsignedIntTy) ||
4126 CheckArgTypeMatches(&SemaRef, TheCall->getArg(2),
4127 SemaRef.getASTContext().UnsignedIntTy) ||
4128 CheckModifiableLValue(&SemaRef, TheCall, 2))
4129 return true;
4130
4131 auto *ResourceTy =
4132 TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
4133 QualType ReturnType = ResourceTy->getContainedType();
4134 TheCall->setType(ReturnType);
4135
4136 break;
4137 }
4138 case Builtin::BI__builtin_hlsl_resource_load_with_status_typed: {
4139 if (SemaRef.checkArgCount(TheCall, 4) ||
4140 CheckResourceHandle(&SemaRef, TheCall, 0) ||
4141 CheckArgTypeMatches(&SemaRef, TheCall->getArg(1),
4142 SemaRef.getASTContext().UnsignedIntTy) ||
4143 CheckArgTypeMatches(&SemaRef, TheCall->getArg(2),
4144 SemaRef.getASTContext().UnsignedIntTy) ||
4145 CheckModifiableLValue(&SemaRef, TheCall, 2))
4146 return true;
4147
4148 QualType ReturnType = TheCall->getArg(3)->getType();
4149 assert(ReturnType->isPointerType() &&
4150 "expected pointer type for second argument");
4151 ReturnType = ReturnType->getPointeeType();
4152
4153 // Reject array types
4154 if (ReturnType->isArrayType())
4155 return SemaRef.Diag(
4156 cast<FunctionDecl>(SemaRef.CurContext)->getPointOfInstantiation(),
4157 diag::err_invalid_use_of_array_type);
4158
4159 TheCall->setType(ReturnType);
4160
4161 break;
4162 }
4163 case Builtin::BI__builtin_hlsl_resource_load_level:
4164 return CheckLoadLevelBuiltin(SemaRef, TheCall);
4165 case Builtin::BI__builtin_hlsl_resource_sample:
4167 case Builtin::BI__builtin_hlsl_resource_sample_bias:
4169 case Builtin::BI__builtin_hlsl_resource_sample_grad:
4171 case Builtin::BI__builtin_hlsl_resource_sample_level:
4173 case Builtin::BI__builtin_hlsl_resource_sample_cmp:
4175 case Builtin::BI__builtin_hlsl_resource_sample_cmp_level_zero:
4177 case Builtin::BI__builtin_hlsl_resource_calculate_lod:
4178 case Builtin::BI__builtin_hlsl_resource_calculate_lod_unclamped:
4179 return CheckCalculateLodBuiltin(SemaRef, TheCall);
4180 case Builtin::BI__builtin_hlsl_resource_gather:
4181 return CheckGatherBuiltin(SemaRef, TheCall, /*IsCmp=*/false);
4182 case Builtin::BI__builtin_hlsl_resource_gather_cmp:
4183 return CheckGatherBuiltin(SemaRef, TheCall, /*IsCmp=*/true);
4184 case Builtin::BI__builtin_hlsl_resource_uninitializedhandle: {
4185 assert(TheCall->getNumArgs() == 1 && "expected 1 arg");
4186 // Update return type to be the attributed resource type from arg0.
4187 QualType ResourceTy = TheCall->getArg(0)->getType();
4188 TheCall->setType(ResourceTy);
4189 break;
4190 }
4191 case Builtin::BI__builtin_hlsl_resource_handlefrombinding: {
4192 assert(TheCall->getNumArgs() == 6 && "expected 6 args");
4193 // Update return type to be the attributed resource type from arg0.
4194 QualType ResourceTy = TheCall->getArg(0)->getType();
4195 TheCall->setType(ResourceTy);
4196 break;
4197 }
4198 case Builtin::BI__builtin_hlsl_resource_handlefromimplicitbinding: {
4199 assert(TheCall->getNumArgs() == 6 && "expected 6 args");
4200 // Update return type to be the attributed resource type from arg0.
4201 QualType ResourceTy = TheCall->getArg(0)->getType();
4202 TheCall->setType(ResourceTy);
4203 break;
4204 }
4205 case Builtin::BI__builtin_hlsl_resource_counterhandlefromimplicitbinding: {
4206 assert(TheCall->getNumArgs() == 3 && "expected 3 args");
4207 ASTContext &AST = SemaRef.getASTContext();
4208 QualType MainHandleTy = TheCall->getArg(0)->getType();
4209 auto *MainResType = MainHandleTy->getAs<HLSLAttributedResourceType>();
4210 auto MainAttrs = MainResType->getAttrs();
4211 assert(!MainAttrs.IsCounter && "cannot create a counter from a counter");
4212 MainAttrs.IsCounter = true;
4213 QualType CounterHandleTy = AST.getHLSLAttributedResourceType(
4214 MainResType->getWrappedType(), MainResType->getContainedType(),
4215 MainAttrs);
4216 // Update return type to be the attributed resource type from arg0
4217 // with added IsCounter flag.
4218 TheCall->setType(CounterHandleTy);
4219 break;
4220 }
4221 case Builtin::BI__builtin_hlsl_and:
4222 case Builtin::BI__builtin_hlsl_or: {
4223 if (SemaRef.checkArgCount(TheCall, 2))
4224 return true;
4225 if (CheckScalarOrVectorOrMatrix(&SemaRef, TheCall, getASTContext().BoolTy,
4226 0))
4227 return true;
4228 if (CheckAllArgsHaveSameType(&SemaRef, TheCall))
4229 return true;
4230
4231 ExprResult A = TheCall->getArg(0);
4232 QualType ArgTyA = A.get()->getType();
4233 // return type is the same as the input type
4234 TheCall->setType(ArgTyA);
4235 break;
4236 }
4237 case Builtin::BI__builtin_hlsl_all:
4238 case Builtin::BI__builtin_hlsl_any: {
4239 if (SemaRef.checkArgCount(TheCall, 1))
4240 return true;
4241 if (CheckAnyScalarOrVector(&SemaRef, TheCall, 0))
4242 return true;
4243 break;
4244 }
4245 case Builtin::BI__builtin_hlsl_asdouble: {
4246 if (SemaRef.checkArgCount(TheCall, 2))
4247 return true;
4249 &SemaRef, TheCall,
4250 /*only check for uint*/ SemaRef.Context.UnsignedIntTy,
4251 /* arg index */ 0))
4252 return true;
4254 &SemaRef, TheCall,
4255 /*only check for uint*/ SemaRef.Context.UnsignedIntTy,
4256 /* arg index */ 1))
4257 return true;
4258 if (CheckAllArgsHaveSameType(&SemaRef, TheCall))
4259 return true;
4260
4261 SetElementTypeAsReturnType(&SemaRef, TheCall, getASTContext().DoubleTy);
4262 break;
4263 }
4264 case Builtin::BI__builtin_hlsl_elementwise_clamp: {
4265 if (SemaRef.BuiltinElementwiseTernaryMath(
4266 TheCall, /*ArgTyRestr=*/
4268 return true;
4269 break;
4270 }
4271 case Builtin::BI__builtin_hlsl_dot: {
4272 // arg count is checked by BuiltinVectorToScalarMath
4273 if (SemaRef.BuiltinVectorToScalarMath(TheCall))
4274 return true;
4276 return true;
4277 break;
4278 }
4279 case Builtin::BI__builtin_hlsl_elementwise_firstbithigh:
4280 case Builtin::BI__builtin_hlsl_elementwise_firstbitlow: {
4281 if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall))
4282 return true;
4283
4284 const Expr *Arg = TheCall->getArg(0);
4285 QualType ArgTy = Arg->getType();
4286 QualType EltTy = ArgTy;
4287
4288 QualType ResTy = SemaRef.Context.UnsignedIntTy;
4289
4290 if (auto *VecTy = EltTy->getAs<VectorType>()) {
4291 EltTy = VecTy->getElementType();
4292 ResTy = SemaRef.Context.getExtVectorType(ResTy, VecTy->getNumElements());
4293 }
4294
4295 if (!EltTy->isIntegerType()) {
4296 Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
4297 << 1 << /* scalar or vector of */ 5 << /* integer ty */ 1
4298 << /* no fp */ 0 << ArgTy;
4299 return true;
4300 }
4301
4302 TheCall->setType(ResTy);
4303 break;
4304 }
4305 case Builtin::BI__builtin_hlsl_select: {
4306 if (SemaRef.checkArgCount(TheCall, 3))
4307 return true;
4308 if (CheckScalarOrVector(&SemaRef, TheCall, getASTContext().BoolTy, 0))
4309 return true;
4310 QualType ArgTy = TheCall->getArg(0)->getType();
4311 if (ArgTy->isBooleanType() && CheckBoolSelect(&SemaRef, TheCall))
4312 return true;
4313 auto *VTy = ArgTy->getAs<VectorType>();
4314 if (VTy && VTy->getElementType()->isBooleanType() &&
4315 CheckVectorSelect(&SemaRef, TheCall))
4316 return true;
4317 break;
4318 }
4319 case Builtin::BI__builtin_hlsl_elementwise_saturate:
4320 case Builtin::BI__builtin_hlsl_elementwise_rcp: {
4321 if (SemaRef.checkArgCount(TheCall, 1))
4322 return true;
4323 if (!TheCall->getArg(0)
4324 ->getType()
4325 ->hasFloatingRepresentation()) // half or float or double
4326 return SemaRef.Diag(TheCall->getArg(0)->getBeginLoc(),
4327 diag::err_builtin_invalid_arg_type)
4328 << /* ordinal */ 1 << /* scalar or vector */ 5 << /* no int */ 0
4329 << /* fp */ 1 << TheCall->getArg(0)->getType();
4330 if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall))
4331 return true;
4332 break;
4333 }
4334 case Builtin::BI__builtin_hlsl_elementwise_degrees:
4335 case Builtin::BI__builtin_hlsl_elementwise_radians:
4336 case Builtin::BI__builtin_hlsl_elementwise_rsqrt:
4337 case Builtin::BI__builtin_hlsl_elementwise_frac:
4338 case Builtin::BI__builtin_hlsl_elementwise_ddx_coarse:
4339 case Builtin::BI__builtin_hlsl_elementwise_ddy_coarse:
4340 case Builtin::BI__builtin_hlsl_elementwise_ddx_fine:
4341 case Builtin::BI__builtin_hlsl_elementwise_ddy_fine: {
4342 if (SemaRef.checkArgCount(TheCall, 1))
4343 return true;
4344 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
4346 return true;
4347 if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall))
4348 return true;
4349 break;
4350 }
4351 case Builtin::BI__builtin_hlsl_elementwise_isinf:
4352 case Builtin::BI__builtin_hlsl_elementwise_isnan: {
4353 if (SemaRef.checkArgCount(TheCall, 1))
4354 return true;
4355 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
4357 return true;
4358 if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall))
4359 return true;
4361 break;
4362 }
4363 case Builtin::BI__builtin_hlsl_lerp: {
4364 if (SemaRef.checkArgCount(TheCall, 3))
4365 return true;
4366 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
4368 return true;
4369 if (CheckAllArgsHaveSameType(&SemaRef, TheCall))
4370 return true;
4371 if (SemaRef.BuiltinElementwiseTernaryMath(TheCall))
4372 return true;
4373 break;
4374 }
4375 case Builtin::BI__builtin_hlsl_mad: {
4376 if (SemaRef.BuiltinElementwiseTernaryMath(
4377 TheCall, /*ArgTyRestr=*/
4379 return true;
4380 break;
4381 }
4382 case Builtin::BI__builtin_hlsl_mul: {
4383 if (SemaRef.checkArgCount(TheCall, 2))
4384 return true;
4385
4386 Expr *Arg0 = TheCall->getArg(0);
4387 Expr *Arg1 = TheCall->getArg(1);
4388 QualType Ty0 = Arg0->getType();
4389 QualType Ty1 = Arg1->getType();
4390
4391 auto getElemType = [](QualType T) -> QualType {
4392 if (const auto *VTy = T->getAs<VectorType>())
4393 return VTy->getElementType();
4394 if (const auto *MTy = T->getAs<ConstantMatrixType>())
4395 return MTy->getElementType();
4396 return T;
4397 };
4398
4399 QualType EltTy0 = getElemType(Ty0);
4400
4401 bool IsVec0 = Ty0->isVectorType();
4402 bool IsMat0 = Ty0->isConstantMatrixType();
4403 bool IsVec1 = Ty1->isVectorType();
4404 bool IsMat1 = Ty1->isConstantMatrixType();
4405
4406 QualType RetTy;
4407
4408 if (IsVec0 && IsMat1) {
4409 auto *MatTy = Ty1->castAs<ConstantMatrixType>();
4410 RetTy = getASTContext().getExtVectorType(EltTy0, MatTy->getNumColumns());
4411 } else if (IsMat0 && IsVec1) {
4412 auto *MatTy = Ty0->castAs<ConstantMatrixType>();
4413 RetTy = getASTContext().getExtVectorType(EltTy0, MatTy->getNumRows());
4414 } else {
4415 assert(IsMat0 && IsMat1);
4416 auto *MatTy0 = Ty0->castAs<ConstantMatrixType>();
4417 auto *MatTy1 = Ty1->castAs<ConstantMatrixType>();
4419 EltTy0, MatTy0->getNumRows(), MatTy1->getNumColumns());
4420 }
4421
4422 TheCall->setType(RetTy);
4423 break;
4424 }
4425 case Builtin::BI__builtin_hlsl_normalize: {
4426 if (SemaRef.checkArgCount(TheCall, 1))
4427 return true;
4428 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
4430 return true;
4431 ExprResult A = TheCall->getArg(0);
4432 QualType ArgTyA = A.get()->getType();
4433 // return type is the same as the input type
4434 TheCall->setType(ArgTyA);
4435 break;
4436 }
4437 case Builtin::BI__builtin_elementwise_fma: {
4438 if (SemaRef.checkArgCount(TheCall, 3) ||
4439 CheckAllArgsHaveSameType(&SemaRef, TheCall)) {
4440 return true;
4441 }
4442
4443 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
4445 return true;
4446
4447 ExprResult A = TheCall->getArg(0);
4448 QualType ArgTyA = A.get()->getType();
4449 // return type is the same as input type
4450 TheCall->setType(ArgTyA);
4451 break;
4452 }
4453 case Builtin::BI__builtin_hlsl_transpose: {
4454 if (SemaRef.checkArgCount(TheCall, 1))
4455 return true;
4456
4457 Expr *Arg = TheCall->getArg(0);
4458 QualType ArgTy = Arg->getType();
4459
4460 const auto *MatTy = ArgTy->getAs<ConstantMatrixType>();
4461 if (!MatTy) {
4462 SemaRef.Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
4463 << 1 << /* matrix */ 3 << /* no int */ 0 << /* no fp */ 0 << ArgTy;
4464 return true;
4465 }
4466
4468 MatTy->getElementType(), MatTy->getNumColumns(), MatTy->getNumRows());
4469 TheCall->setType(RetTy);
4470 break;
4471 }
4472 case Builtin::BI__builtin_hlsl_elementwise_sign: {
4473 if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall))
4474 return true;
4475 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
4477 return true;
4479 break;
4480 }
4481 case Builtin::BI__builtin_hlsl_step: {
4482 if (SemaRef.checkArgCount(TheCall, 2))
4483 return true;
4484 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
4486 return true;
4487
4488 ExprResult A = TheCall->getArg(0);
4489 QualType ArgTyA = A.get()->getType();
4490 // return type is the same as the input type
4491 TheCall->setType(ArgTyA);
4492 break;
4493 }
4494 case Builtin::BI__builtin_hlsl_wave_active_all_equal: {
4495 if (SemaRef.checkArgCount(TheCall, 1))
4496 return true;
4497
4498 // Ensure input expr type is a scalar/vector
4499 if (CheckAnyScalarOrVector(&SemaRef, TheCall, 0))
4500 return true;
4501
4502 QualType InputTy = TheCall->getArg(0)->getType();
4503 ASTContext &Ctx = getASTContext();
4504
4505 QualType RetTy;
4506
4507 // If vector, construct bool vector of same size
4508 if (const auto *VecTy = InputTy->getAs<ExtVectorType>()) {
4509 unsigned NumElts = VecTy->getNumElements();
4510 RetTy = Ctx.getExtVectorType(Ctx.BoolTy, NumElts);
4511 } else {
4512 // Scalar case
4513 RetTy = Ctx.BoolTy;
4514 }
4515
4516 TheCall->setType(RetTy);
4517 break;
4518 }
4519 case Builtin::BI__builtin_hlsl_wave_active_max:
4520 case Builtin::BI__builtin_hlsl_wave_active_min:
4521 case Builtin::BI__builtin_hlsl_wave_active_sum:
4522 case Builtin::BI__builtin_hlsl_wave_active_product: {
4523 if (SemaRef.checkArgCount(TheCall, 1))
4524 return true;
4525
4526 // Ensure input expr type is a scalar/vector and the same as the return type
4527 if (CheckAnyScalarOrVector(&SemaRef, TheCall, 0))
4528 return true;
4529 if (CheckWaveActive(&SemaRef, TheCall))
4530 return true;
4531 ExprResult Expr = TheCall->getArg(0);
4532 QualType ArgTyExpr = Expr.get()->getType();
4533 TheCall->setType(ArgTyExpr);
4534 break;
4535 }
4536 case Builtin::BI__builtin_hlsl_wave_active_bit_or:
4537 case Builtin::BI__builtin_hlsl_wave_active_bit_xor:
4538 case Builtin::BI__builtin_hlsl_wave_active_bit_and: {
4539 if (SemaRef.checkArgCount(TheCall, 1))
4540 return true;
4541
4542 // Ensure input expr type is a scalar/vector
4543 if (CheckAnyScalarOrVector(&SemaRef, TheCall, 0))
4544 return true;
4545
4546 if (CheckWaveActive(&SemaRef, TheCall))
4547 return true;
4548
4549 // Ensure the expr type is interpretable as a uint or vector<uint>
4550 ExprResult Expr = TheCall->getArg(0);
4551 QualType ArgTyExpr = Expr.get()->getType();
4552 auto *VTy = ArgTyExpr->getAs<VectorType>();
4553 if (!(ArgTyExpr->isIntegerType() ||
4554 (VTy && VTy->getElementType()->isIntegerType()))) {
4555 SemaRef.Diag(TheCall->getArg(0)->getBeginLoc(),
4556 diag::err_builtin_invalid_arg_type)
4557 << ArgTyExpr << SemaRef.Context.UnsignedIntTy << 1 << 0 << 0;
4558 return true;
4559 }
4560
4561 // Ensure input expr type is the same as the return type
4562 TheCall->setType(ArgTyExpr);
4563 break;
4564 }
4565 case Builtin::BI__builtin_hlsl_interlocked_add:
4566 case Builtin::BI__builtin_hlsl_interlocked_or: {
4567 // The builtin's prototype in Builtins.td is `void (...)`, so direct calls
4568 // to `__builtin_hlsl_interlocked_add` bypass argument checking entirely.
4569 // When reached via the synthesized `InterlockedAdd` overload set in
4570 // HLSLExternalSemaSource, overload resolution has already enforced the
4571 // argument count, integer-type matching, and the address-space requirement
4572 // on `dest`. The checks below are a safety net for callers that invoke the
4573 // builtin by its mangled name and would otherwise reach CodeGen unchecked.
4574 if (TheCall->getNumArgs() < 2) {
4575 SemaRef.Diag(TheCall->getEndLoc(),
4576 diag::err_typecheck_call_too_few_args_at_least)
4577 << /*callee_type=*/0 << /*min_arg_count=*/2 << TheCall->getNumArgs()
4578 << /*is_non_object=*/0 << TheCall->getSourceRange();
4579 return true;
4580 }
4581 if (SemaRef.checkArgCountAtMost(TheCall, 3))
4582 return true;
4583
4584 QualType DestTy = TheCall->getArg(0)->getType().getUnqualifiedType();
4585 if (!DestTy->isIntegerType()) {
4586 SemaRef.Diag(TheCall->getArg(0)->getBeginLoc(),
4587 diag::err_builtin_invalid_arg_type)
4588 << /*ordinal=*/1 << /*scalar*/ 1 << /*integer*/ 1 << /*no float*/ 0
4589 << DestTy;
4590 return true;
4591 }
4592
4593 if (CheckModifiableLValue(&SemaRef, TheCall, 0))
4594 return true;
4595
4596 if (CheckArgAddrSpaceOneOf(&SemaRef, TheCall, 0,
4598 return true;
4599
4600 if (CheckArgTypeMatches(&SemaRef, TheCall->getArg(1), DestTy))
4601 return true;
4602
4603 if (TheCall->getNumArgs() == 3) {
4604 if (CheckArgTypeMatches(&SemaRef, TheCall->getArg(2), DestTy))
4605 return true;
4606 if (CheckModifiableLValue(&SemaRef, TheCall, 2))
4607 return true;
4608 }
4609
4610 TheCall->setType(SemaRef.Context.VoidTy);
4611 break;
4612 }
4613 // Note these are llvm builtins that we want to catch invalid intrinsic
4614 // generation. Normal handling of these builtins will occur elsewhere.
4615 case Builtin::BI__builtin_elementwise_bitreverse: {
4616 // does not include a check for number of arguments
4617 // because that is done previously
4618 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
4620 return true;
4621 break;
4622 }
4623 case Builtin::BI__builtin_hlsl_wave_prefix_count_bits: {
4624 if (SemaRef.checkArgCount(TheCall, 1))
4625 return true;
4626
4627 QualType ArgType = TheCall->getArg(0)->getType();
4628
4629 if (!(ArgType->isScalarType())) {
4630 SemaRef.Diag(TheCall->getArg(0)->getBeginLoc(),
4631 diag::err_typecheck_expect_any_scalar_or_vector)
4632 << ArgType << 0;
4633 return true;
4634 }
4635
4636 if (!(ArgType->isBooleanType())) {
4637 SemaRef.Diag(TheCall->getArg(0)->getBeginLoc(),
4638 diag::err_typecheck_expect_any_scalar_or_vector)
4639 << ArgType << 0;
4640 return true;
4641 }
4642
4643 break;
4644 }
4645 case Builtin::BI__builtin_hlsl_wave_read_lane_at: {
4646 if (SemaRef.checkArgCount(TheCall, 2))
4647 return true;
4648
4649 // Ensure index parameter type can be interpreted as a uint
4650 ExprResult Index = TheCall->getArg(1);
4651 QualType ArgTyIndex = Index.get()->getType();
4652 if (!ArgTyIndex->isIntegerType()) {
4653 SemaRef.Diag(TheCall->getArg(1)->getBeginLoc(),
4654 diag::err_typecheck_convert_incompatible)
4655 << ArgTyIndex << SemaRef.Context.UnsignedIntTy << 1 << 0 << 0;
4656 return true;
4657 }
4658
4659 // Ensure input expr type is a scalar/vector and the same as the return type
4660 if (CheckAnyScalarOrVector(&SemaRef, TheCall, 0))
4661 return true;
4662
4663 ExprResult Expr = TheCall->getArg(0);
4664 QualType ArgTyExpr = Expr.get()->getType();
4665 TheCall->setType(ArgTyExpr);
4666 break;
4667 }
4668 case Builtin::BI__builtin_hlsl_wave_get_lane_index: {
4669 if (SemaRef.checkArgCount(TheCall, 0))
4670 return true;
4671 break;
4672 }
4673 case Builtin::BI__builtin_hlsl_wave_prefix_sum:
4674 case Builtin::BI__builtin_hlsl_wave_prefix_product: {
4675 if (SemaRef.checkArgCount(TheCall, 1))
4676 return true;
4677
4678 // Ensure input expr type is a scalar/vector and the same as the return type
4679 if (CheckAnyScalarOrVector(&SemaRef, TheCall, 0))
4680 return true;
4681 if (CheckWavePrefix(&SemaRef, TheCall))
4682 return true;
4683 ExprResult Expr = TheCall->getArg(0);
4684 QualType ArgTyExpr = Expr.get()->getType();
4685 TheCall->setType(ArgTyExpr);
4686 break;
4687 }
4688 case Builtin::BI__builtin_hlsl_quad_read_across_x:
4689 case Builtin::BI__builtin_hlsl_quad_read_across_y:
4690 case Builtin::BI__builtin_hlsl_quad_read_across_diagonal: {
4691 if (SemaRef.checkArgCount(TheCall, 1))
4692 return true;
4693
4694 if (CheckAnyScalarOrVector(&SemaRef, TheCall, 0))
4695 return true;
4696 if (CheckNotBoolScalarOrVector(&SemaRef, TheCall, 0))
4697 return true;
4698 ExprResult Expr = TheCall->getArg(0);
4699 QualType ArgTyExpr = Expr.get()->getType();
4700 TheCall->setType(ArgTyExpr);
4701 break;
4702 }
4703 case Builtin::BI__builtin_hlsl_elementwise_splitdouble: {
4704 if (SemaRef.checkArgCount(TheCall, 3))
4705 return true;
4706
4707 if (CheckScalarOrVectorOrMatrix(&SemaRef, TheCall, SemaRef.Context.DoubleTy,
4708 0) ||
4710 SemaRef.Context.UnsignedIntTy, 1) ||
4712 SemaRef.Context.UnsignedIntTy, 2))
4713 return true;
4714
4715 if (CheckModifiableLValue(&SemaRef, TheCall, 1) ||
4716 CheckModifiableLValue(&SemaRef, TheCall, 2))
4717 return true;
4718 break;
4719 }
4720 case Builtin::BI__builtin_hlsl_elementwise_clip: {
4721 if (SemaRef.checkArgCount(TheCall, 1))
4722 return true;
4723
4724 if (CheckScalarOrVector(&SemaRef, TheCall, SemaRef.Context.FloatTy, 0))
4725 return true;
4726 break;
4727 }
4728 case Builtin::BI__builtin_elementwise_acos:
4729 case Builtin::BI__builtin_elementwise_asin:
4730 case Builtin::BI__builtin_elementwise_atan:
4731 case Builtin::BI__builtin_elementwise_atan2:
4732 case Builtin::BI__builtin_elementwise_ceil:
4733 case Builtin::BI__builtin_elementwise_cos:
4734 case Builtin::BI__builtin_elementwise_cosh:
4735 case Builtin::BI__builtin_elementwise_exp:
4736 case Builtin::BI__builtin_elementwise_exp2:
4737 case Builtin::BI__builtin_elementwise_exp10:
4738 case Builtin::BI__builtin_elementwise_floor:
4739 case Builtin::BI__builtin_elementwise_fmod:
4740 case Builtin::BI__builtin_elementwise_log:
4741 case Builtin::BI__builtin_elementwise_log2:
4742 case Builtin::BI__builtin_elementwise_log10:
4743 case Builtin::BI__builtin_elementwise_pow:
4744 case Builtin::BI__builtin_elementwise_roundeven:
4745 case Builtin::BI__builtin_elementwise_sin:
4746 case Builtin::BI__builtin_elementwise_sinh:
4747 case Builtin::BI__builtin_elementwise_sqrt:
4748 case Builtin::BI__builtin_elementwise_tan:
4749 case Builtin::BI__builtin_elementwise_tanh:
4750 case Builtin::BI__builtin_elementwise_trunc: {
4751 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
4753 return true;
4754 break;
4755 }
4756 case Builtin::BI__builtin_hlsl_buffer_update_counter: {
4757 assert(TheCall->getNumArgs() == 2 && "expected 2 args");
4758 auto checkResTy = [](const HLSLAttributedResourceType *ResTy) -> bool {
4759 return !(ResTy->getAttrs().ResourceClass == ResourceClass::UAV &&
4760 ResTy->getAttrs().RawBuffer && ResTy->hasContainedType());
4761 };
4762 if (CheckResourceHandle(&SemaRef, TheCall, 0, checkResTy))
4763 return true;
4764 Expr *OffsetExpr = TheCall->getArg(1);
4765 std::optional<llvm::APSInt> Offset =
4766 OffsetExpr->getIntegerConstantExpr(SemaRef.getASTContext());
4767 if (!Offset.has_value() || std::abs(Offset->getExtValue()) != 1) {
4768 SemaRef.Diag(TheCall->getArg(1)->getBeginLoc(),
4769 diag::err_hlsl_expect_arg_const_int_one_or_neg_one)
4770 << 1;
4771 return true;
4772 }
4773 break;
4774 }
4775 case Builtin::BI__builtin_hlsl_elementwise_f16tof32: {
4776 if (SemaRef.checkArgCount(TheCall, 1))
4777 return true;
4778 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
4780 return true;
4781 // ensure arg integers are 32 bits
4782 if (CheckExpectedBitWidth(&SemaRef, TheCall, 0, 32))
4783 return true;
4784 // check it wasn't a bool type
4785 QualType ArgTy = TheCall->getArg(0)->getType();
4786 if (auto *VTy = ArgTy->getAs<VectorType>())
4787 ArgTy = VTy->getElementType();
4788 if (ArgTy->isBooleanType()) {
4789 SemaRef.Diag(TheCall->getArg(0)->getBeginLoc(),
4790 diag::err_builtin_invalid_arg_type)
4791 << 1 << /* scalar or vector of */ 5 << /* unsigned int */ 3
4792 << /* no fp */ 0 << TheCall->getArg(0)->getType();
4793 return true;
4794 }
4795
4796 SetElementTypeAsReturnType(&SemaRef, TheCall, getASTContext().FloatTy);
4797 break;
4798 }
4799 case Builtin::BI__builtin_hlsl_elementwise_f32tof16: {
4800 if (SemaRef.checkArgCount(TheCall, 1))
4801 return true;
4803 return true;
4805 getASTContext().UnsignedIntTy);
4806 break;
4807 }
4808 }
4809 return false;
4810}
4811
4815 WorkList.push_back(BaseTy);
4816 while (!WorkList.empty()) {
4817 QualType T = WorkList.pop_back_val();
4818 T = T.getCanonicalType().getUnqualifiedType();
4819 if (const auto *AT = dyn_cast<ConstantArrayType>(T)) {
4820 llvm::SmallVector<QualType, 16> ElementFields;
4821 // Generally I've avoided recursion in this algorithm, but arrays of
4822 // structs could be time-consuming to flatten and churn through on the
4823 // work list. Hopefully nesting arrays of structs containing arrays
4824 // of structs too many levels deep is unlikely.
4825 BuildFlattenedTypeList(AT->getElementType(), ElementFields);
4826 // Repeat the element's field list n times.
4827 for (uint64_t Ct = 0; Ct < AT->getZExtSize(); ++Ct)
4828 llvm::append_range(List, ElementFields);
4829 continue;
4830 }
4831 // Vectors can only have element types that are builtin types, so this can
4832 // add directly to the list instead of to the WorkList.
4833 if (const auto *VT = dyn_cast<VectorType>(T)) {
4834 List.insert(List.end(), VT->getNumElements(), VT->getElementType());
4835 continue;
4836 }
4837 if (const auto *MT = dyn_cast<ConstantMatrixType>(T)) {
4838 List.insert(List.end(), MT->getNumElementsFlattened(),
4839 MT->getElementType());
4840 continue;
4841 }
4842 if (const auto *RD = T->getAsCXXRecordDecl()) {
4843 if (RD->isStandardLayout())
4844 RD = RD->getStandardLayoutBaseWithFields();
4845
4846 // For types that we shouldn't decompose (unions and non-aggregates), just
4847 // add the type itself to the list.
4848 if (RD->isUnion() || !RD->isAggregate()) {
4849 List.push_back(T);
4850 continue;
4851 }
4852
4854 for (const auto *FD : RD->fields())
4855 if (!FD->isUnnamedBitField())
4856 FieldTypes.push_back(FD->getType());
4857 // Reverse the newly added sub-range.
4858 std::reverse(FieldTypes.begin(), FieldTypes.end());
4859 llvm::append_range(WorkList, FieldTypes);
4860
4861 // If this wasn't a standard layout type we may also have some base
4862 // classes to deal with.
4863 if (!RD->isStandardLayout()) {
4864 FieldTypes.clear();
4865 for (const auto &Base : RD->bases())
4866 FieldTypes.push_back(Base.getType());
4867 std::reverse(FieldTypes.begin(), FieldTypes.end());
4868 llvm::append_range(WorkList, FieldTypes);
4869 }
4870 continue;
4871 }
4872 List.push_back(T);
4873 }
4874}
4875
4877 if (QT.isNull())
4878 return false;
4879
4880 // Must be a class/struct.
4881 const auto *RD = QT->getAsCXXRecordDecl();
4882 if (!RD || RD->isUnion())
4883 return false;
4884
4885 // Cannot be a resource type or contain one.
4886 return !QT->isHLSLIntangibleType();
4887}
4888
4890 // null and array types are not allowed.
4891 if (QT.isNull() || QT->isArrayType())
4892 return false;
4893
4894 // UDT types are not allowed
4895 if (QT->isRecordType())
4896 return false;
4897
4898 if (QT->isBooleanType() || QT->isEnumeralType())
4899 return false;
4900
4901 // the only other valid builtin types are scalars or vectors
4902 if (QT->isArithmeticType()) {
4903 if (SemaRef.Context.getTypeSize(QT) / 8 > 16)
4904 return false;
4905 return true;
4906 }
4907
4908 if (const VectorType *VT = QT->getAs<VectorType>()) {
4909 int ArraySize = VT->getNumElements();
4910
4911 if (ArraySize > 4)
4912 return false;
4913
4914 QualType ElTy = VT->getElementType();
4915 if (ElTy->isBooleanType())
4916 return false;
4917
4918 if (SemaRef.Context.getTypeSize(QT) / 8 > 16)
4919 return false;
4920 return true;
4921 }
4922
4923 return false;
4924}
4925
4927 if (T1.isNull() || T2.isNull())
4928 return false;
4929
4932
4933 // If both types are the same canonical type, they're obviously compatible.
4934 if (SemaRef.getASTContext().hasSameType(T1, T2))
4935 return true;
4936
4938 BuildFlattenedTypeList(T1, T1Types);
4940 BuildFlattenedTypeList(T2, T2Types);
4941
4942 // Check the flattened type list
4943 return llvm::equal(T1Types, T2Types,
4944 [this](QualType LHS, QualType RHS) -> bool {
4945 return SemaRef.IsLayoutCompatible(LHS, RHS);
4946 });
4947}
4948
4950 FunctionDecl *Old) {
4951 if (New->getNumParams() != Old->getNumParams())
4952 return true;
4953
4954 bool HadError = false;
4955
4956 for (unsigned i = 0, e = New->getNumParams(); i != e; ++i) {
4957 ParmVarDecl *NewParam = New->getParamDecl(i);
4958 ParmVarDecl *OldParam = Old->getParamDecl(i);
4959
4960 // HLSL parameter declarations for inout and out must match between
4961 // declarations. In HLSL inout and out are ambiguous at the call site,
4962 // but have different calling behavior, so you cannot overload a
4963 // method based on a difference between inout and out annotations.
4964 const auto *NDAttr = NewParam->getAttr<HLSLParamModifierAttr>();
4965 unsigned NSpellingIdx = (NDAttr ? NDAttr->getSpellingListIndex() : 0);
4966 const auto *ODAttr = OldParam->getAttr<HLSLParamModifierAttr>();
4967 unsigned OSpellingIdx = (ODAttr ? ODAttr->getSpellingListIndex() : 0);
4968
4969 if (NSpellingIdx != OSpellingIdx) {
4970 SemaRef.Diag(NewParam->getLocation(),
4971 diag::err_hlsl_param_qualifier_mismatch)
4972 << NDAttr << NewParam;
4973 SemaRef.Diag(OldParam->getLocation(), diag::note_previous_declaration_as)
4974 << ODAttr;
4975 HadError = true;
4976 }
4977 }
4978 return HadError;
4979}
4980
4981// Generally follows PerformScalarCast, with cases reordered for
4982// clarity of what types are supported
4984
4985 if (!SrcTy->isScalarType() || !DestTy->isScalarType())
4986 return false;
4987
4988 if (SemaRef.getASTContext().hasSameUnqualifiedType(SrcTy, DestTy))
4989 return true;
4990
4991 switch (SrcTy->getScalarTypeKind()) {
4992 case Type::STK_Bool: // casting from bool is like casting from an integer
4993 case Type::STK_Integral:
4994 switch (DestTy->getScalarTypeKind()) {
4995 case Type::STK_Bool:
4996 case Type::STK_Integral:
4997 case Type::STK_Floating:
4998 return true;
4999 case Type::STK_CPointer:
5003 llvm_unreachable("HLSL doesn't support pointers.");
5006 llvm_unreachable("HLSL doesn't support complex types.");
5008 llvm_unreachable("HLSL doesn't support fixed point types.");
5009 }
5010 llvm_unreachable("Should have returned before this");
5011
5012 case Type::STK_Floating:
5013 switch (DestTy->getScalarTypeKind()) {
5014 case Type::STK_Floating:
5015 case Type::STK_Bool:
5016 case Type::STK_Integral:
5017 return true;
5020 llvm_unreachable("HLSL doesn't support complex types.");
5022 llvm_unreachable("HLSL doesn't support fixed point types.");
5023 case Type::STK_CPointer:
5027 llvm_unreachable("HLSL doesn't support pointers.");
5028 }
5029 llvm_unreachable("Should have returned before this");
5030
5032 case Type::STK_CPointer:
5035 llvm_unreachable("HLSL doesn't support pointers.");
5036
5038 llvm_unreachable("HLSL doesn't support fixed point types.");
5039
5042 llvm_unreachable("HLSL doesn't support complex types.");
5043 }
5044
5045 llvm_unreachable("Unhandled scalar cast");
5046}
5047
5048// Can perform an HLSL Aggregate splat cast if the Dest is an aggregate and the
5049// Src is a scalar, a vector of length 1, or a 1x1 matrix
5050// Or if Dest is a vector and Src is a vector of length 1 or a 1x1 matrix
5052
5053 QualType SrcTy = Src->getType();
5054 // Not a valid HLSL Aggregate Splat cast if Dest is a scalar or if this is
5055 // going to be a vector splat from a scalar.
5056 if ((SrcTy->isScalarType() && DestTy->isVectorType()) ||
5057 DestTy->isScalarType())
5058 return false;
5059
5060 const VectorType *SrcVecTy = SrcTy->getAs<VectorType>();
5061 const ConstantMatrixType *SrcMatTy = SrcTy->getAs<ConstantMatrixType>();
5062
5063 // Src isn't a scalar, a vector of length 1, or a 1x1 matrix
5064 if (!SrcTy->isScalarType() &&
5065 !(SrcVecTy && SrcVecTy->getNumElements() == 1) &&
5066 !(SrcMatTy && SrcMatTy->getNumElementsFlattened() == 1))
5067 return false;
5068
5069 if (SrcVecTy)
5070 SrcTy = SrcVecTy->getElementType();
5071 else if (SrcMatTy)
5072 SrcTy = SrcMatTy->getElementType();
5073
5075 BuildFlattenedTypeList(DestTy, DestTypes);
5076
5077 for (unsigned I = 0, Size = DestTypes.size(); I < Size; ++I) {
5078 if (DestTypes[I]->isUnionType())
5079 return false;
5080 if (!CanPerformScalarCast(SrcTy, DestTypes[I]))
5081 return false;
5082 }
5083 return true;
5084}
5085
5086// Can we perform an HLSL Elementwise cast?
5088
5089 // Don't handle casts where LHS and RHS are any combination of scalar/vector
5090 // There must be an aggregate somewhere
5091 QualType SrcTy = Src->getType();
5092 if (SrcTy->isScalarType()) // always a splat and this cast doesn't handle that
5093 return false;
5094
5095 if (SrcTy->isVectorType() &&
5096 (DestTy->isScalarType() || DestTy->isVectorType()))
5097 return false;
5098
5099 if (SrcTy->isConstantMatrixType() &&
5100 (DestTy->isScalarType() || DestTy->isConstantMatrixType()))
5101 return false;
5102
5104 BuildFlattenedTypeList(DestTy, DestTypes);
5106 BuildFlattenedTypeList(SrcTy, SrcTypes);
5107
5108 // Usually the size of SrcTypes must be greater than or equal to the size of
5109 // DestTypes.
5110 if (SrcTypes.size() < DestTypes.size())
5111 return false;
5112
5113 unsigned SrcSize = SrcTypes.size();
5114 unsigned DstSize = DestTypes.size();
5115 unsigned I;
5116 for (I = 0; I < DstSize && I < SrcSize; I++) {
5117 if (SrcTypes[I]->isUnionType() || DestTypes[I]->isUnionType())
5118 return false;
5119 if (!CanPerformScalarCast(SrcTypes[I], DestTypes[I])) {
5120 return false;
5121 }
5122 }
5123
5124 // check the rest of the source type for unions.
5125 for (; I < SrcSize; I++) {
5126 if (SrcTypes[I]->isUnionType())
5127 return false;
5128 }
5129 return true;
5130}
5131
5133 assert(Param->hasAttr<HLSLParamModifierAttr>() &&
5134 "We should not get here without a parameter modifier expression");
5135 const auto *Attr = Param->getAttr<HLSLParamModifierAttr>();
5136 if (Attr->getABI() == ParameterABI::Ordinary)
5137 return ExprResult(Arg);
5138
5139 bool IsInOut = Attr->getABI() == ParameterABI::HLSLInOut;
5140 if (!Arg->isLValue()) {
5141 SemaRef.Diag(Arg->getBeginLoc(), diag::error_hlsl_inout_lvalue)
5142 << Arg << (IsInOut ? 1 : 0);
5143 return ExprError();
5144 }
5145
5146 ASTContext &Ctx = SemaRef.getASTContext();
5147
5148 QualType Ty = Param->getType().getNonLValueExprType(Ctx);
5149
5150 // HLSL allows implicit conversions from scalars to vectors, but not the
5151 // inverse, so we need to disallow `inout` with scalar->vector or
5152 // scalar->matrix conversions.
5153 if (Arg->getType()->isScalarType() != Ty->isScalarType()) {
5154 SemaRef.Diag(Arg->getBeginLoc(), diag::error_hlsl_inout_scalar_extension)
5155 << Arg << (IsInOut ? 1 : 0);
5156 return ExprError();
5157 }
5158
5159 auto *ArgOpV = new (Ctx) OpaqueValueExpr(Param->getBeginLoc(), Arg->getType(),
5160 VK_LValue, OK_Ordinary, Arg);
5161
5162 // Parameters are initialized via copy initialization. This allows for
5163 // overload resolution of argument constructors.
5164 InitializedEntity Entity =
5166 ExprResult Res =
5167 SemaRef.PerformCopyInitialization(Entity, Param->getBeginLoc(), ArgOpV);
5168 if (Res.isInvalid())
5169 return ExprError();
5170 Expr *Base = Res.get();
5171 // After the cast, drop the reference type when creating the exprs.
5172 Ty = Ty.getNonLValueExprType(Ctx);
5173 auto *OpV = new (Ctx)
5174 OpaqueValueExpr(Param->getBeginLoc(), Ty, VK_LValue, OK_Ordinary, Base);
5175
5176 // Writebacks are performed with `=` binary operator, which allows for
5177 // overload resolution on writeback result expressions.
5178 Res = SemaRef.ActOnBinOp(SemaRef.getCurScope(), Arg->getBeginLoc(),
5179 tok::equal, ArgOpV, OpV);
5180
5181 if (Res.isInvalid())
5182 return ExprError();
5183 Expr *Writeback = Res.get();
5184 auto *OutExpr =
5185 HLSLOutArgExpr::Create(Ctx, Ty, ArgOpV, OpV, Writeback, IsInOut);
5186
5187 return ExprResult(OutExpr);
5188}
5189
5191 // If HLSL gains support for references, all the cites that use this will need
5192 // to be updated with semantic checking to produce errors for
5193 // pointers/references.
5194 assert(!Ty->isReferenceType() &&
5195 "Pointer and reference types cannot be inout or out parameters");
5196 Ty = SemaRef.getASTContext().getLValueReferenceType(Ty);
5197 Ty.addRestrict();
5198 return Ty;
5199}
5200
5201// Returns true if the type has a non-empty constant buffer layout (if it is
5202// scalar, vector or matrix, or if it contains any of these.
5204 const Type *Ty = QT->getUnqualifiedDesugaredType();
5205 if (Ty->isScalarType() || Ty->isVectorType() || Ty->isMatrixType())
5206 return true;
5207
5209 return false;
5210
5211 if (const auto *RD = Ty->getAsCXXRecordDecl()) {
5212 for (const auto *FD : RD->fields()) {
5214 return true;
5215 }
5216 assert(RD->getNumBases() <= 1 &&
5217 "HLSL doesn't support multiple inheritance");
5218 return RD->getNumBases()
5219 ? hasConstantBufferLayout(RD->bases_begin()->getType())
5220 : false;
5221 }
5222
5223 if (const auto *AT = dyn_cast<ArrayType>(Ty)) {
5224 if (const auto *CAT = dyn_cast<ConstantArrayType>(AT))
5225 if (isZeroSizedArray(CAT))
5226 return false;
5228 }
5229
5230 return false;
5231}
5232
5233static bool IsDefaultBufferConstantDecl(const ASTContext &Ctx, VarDecl *VD) {
5234 bool IsVulkan =
5235 Ctx.getTargetInfo().getTriple().getOS() == llvm::Triple::Vulkan;
5236 bool IsVKPushConstant = IsVulkan && VD->hasAttr<HLSLVkPushConstantAttr>();
5237 QualType QT = VD->getType();
5238 return VD->getDeclContext()->isTranslationUnit() &&
5239 QT.getAddressSpace() == LangAS::Default &&
5240 VD->getStorageClass() != SC_Static &&
5241 !VD->hasAttr<HLSLVkConstantIdAttr>() && !IsVKPushConstant &&
5243}
5244
5246 // The variable already has an address space (groupshared for ex).
5247 if (Decl->getType().hasAddressSpace())
5248 return;
5249
5250 if (Decl->getType()->isDependentType())
5251 return;
5252
5253 QualType Type = Decl->getType();
5254
5255 if (Decl->hasAttr<HLSLVkExtBuiltinInputAttr>()) {
5256 LangAS ImplAS = LangAS::hlsl_input;
5257 Type = SemaRef.getASTContext().getAddrSpaceQualType(Type, ImplAS);
5258 Decl->setType(Type);
5259 return;
5260 }
5261
5262 if (Decl->hasAttr<HLSLVkExtBuiltinOutputAttr>()) {
5263 LangAS ImplAS = LangAS::hlsl_output;
5264 Type = SemaRef.getASTContext().getAddrSpaceQualType(Type, ImplAS);
5265 Decl->setType(Type);
5266
5267 // HLSL uses `static` differently than C++. For BuiltIn output, the static
5268 // does not imply private to the module scope.
5269 // Marking it as external to reflect the semantic this attribute brings.
5270 // See https://github.com/microsoft/hlsl-specs/issues/350
5271 Decl->setStorageClass(SC_Extern);
5272 return;
5273 }
5274
5275 bool IsVulkan = getASTContext().getTargetInfo().getTriple().getOS() ==
5276 llvm::Triple::Vulkan;
5277 if (IsVulkan && Decl->hasAttr<HLSLVkPushConstantAttr>()) {
5278 if (HasDeclaredAPushConstant)
5279 SemaRef.Diag(Decl->getLocation(), diag::err_hlsl_push_constant_unique);
5280
5282 Type = SemaRef.getASTContext().getAddrSpaceQualType(Type, ImplAS);
5283 Decl->setType(Type);
5284 HasDeclaredAPushConstant = true;
5285 return;
5286 }
5287
5288 if (Type->isSamplerT() || Type->isVoidType())
5289 return;
5290
5291 // Resource handles.
5293 return;
5294
5295 // Only static globals belong to the Private address space.
5296 // Non-static globals belongs to the cbuffer.
5297 if (Decl->getStorageClass() != SC_Static && !Decl->isStaticDataMember())
5298 return;
5299
5301 Type = SemaRef.getASTContext().getAddrSpaceQualType(Type, ImplAS);
5302 Decl->setType(Type);
5303}
5304
5305namespace {
5306
5307// Helper class for assigning bindings to resources declared within a struct.
5308// It keeps track of all binding attributes declared on a struct instance, and
5309// the offsets for each register type that have been assigned so far.
5310// Handles both explicit and implicit bindings.
5311class StructBindingContext {
5312 // Bindings and offsets per register type. We only need to support four
5313 // register types - SRV (u), UAV (t), CBuffer (c), and Sampler (s).
5314 HLSLResourceBindingAttr *RegBindingsAttrs[4];
5315 unsigned RegBindingOffset[4];
5316
5317 // Make sure the RegisterType values are what we expect
5318 static_assert(static_cast<unsigned>(RegisterType::SRV) == 0 &&
5319 static_cast<unsigned>(RegisterType::UAV) == 1 &&
5320 static_cast<unsigned>(RegisterType::CBuffer) == 2 &&
5321 static_cast<unsigned>(RegisterType::Sampler) == 3,
5322 "unexpected register type values");
5323
5324 // Vulkan binding attribute does not vary by register type.
5325 HLSLVkBindingAttr *VkBindingAttr;
5326 unsigned VkBindingOffset;
5327
5328public:
5329 // Constructor: gather all binding attributes on a struct instance and
5330 // initialize offsets.
5331 StructBindingContext(VarDecl *VD) {
5332 for (unsigned i = 0; i < 4; ++i) {
5333 RegBindingsAttrs[i] = nullptr;
5334 RegBindingOffset[i] = 0;
5335 }
5336 VkBindingAttr = nullptr;
5337 VkBindingOffset = 0;
5338
5339 ASTContext &AST = VD->getASTContext();
5340 bool IsSpirv = AST.getTargetInfo().getTriple().isSPIRV();
5341
5342 for (Attr *A : VD->attrs()) {
5343 if (auto *RBA = dyn_cast<HLSLResourceBindingAttr>(A)) {
5344 RegisterType RegType = RBA->getRegisterType();
5345 unsigned RegTypeIdx = static_cast<unsigned>(RegType);
5346 // Ignore unsupported register annotations, such as 'c' or 'i'.
5347 if (RegTypeIdx < 4)
5348 RegBindingsAttrs[RegTypeIdx] = RBA;
5349 continue;
5350 }
5351 // Gather the Vulkan binding attributes only if the target is SPIR-V.
5352 if (IsSpirv) {
5353 if (auto *VBA = dyn_cast<HLSLVkBindingAttr>(A))
5354 VkBindingAttr = VBA;
5355 }
5356 }
5357 }
5358
5359 // Creates a binding attribute for a resource based on the gathered attributes
5360 // and the required register type and range.
5361 Attr *createBindingAttr(SemaHLSL &S, ASTContext &AST, RegisterType RegType,
5362 unsigned Range, bool HasCounter) {
5363 assert(static_cast<unsigned>(RegType) < 4 && "unexpected register type");
5364
5365 if (VkBindingAttr) {
5366 unsigned Offset = VkBindingOffset;
5367 VkBindingOffset += Range;
5368 return HLSLVkBindingAttr::CreateImplicit(
5369 AST, VkBindingAttr->getBinding() + Offset, VkBindingAttr->getSet(),
5370 VkBindingAttr->getRange());
5371 }
5372
5373 HLSLResourceBindingAttr *RBA =
5374 RegBindingsAttrs[static_cast<unsigned>(RegType)];
5375 HLSLResourceBindingAttr *NewAttr = nullptr;
5376
5377 if (RBA && RBA->hasRegisterSlot()) {
5378 // Explicit binding - create a new attribute with offseted slot number
5379 // based on the required register type.
5380 unsigned Offset = RegBindingOffset[static_cast<unsigned>(RegType)];
5381 RegBindingOffset[static_cast<unsigned>(RegType)] += Range;
5382
5383 unsigned NewSlotNumber = RBA->getSlotNumber() + Offset;
5384 StringRef NewSlotNumberStr =
5385 createRegisterString(AST, RBA->getRegisterType(), NewSlotNumber);
5386 NewAttr = HLSLResourceBindingAttr::CreateImplicit(
5387 AST, NewSlotNumberStr, RBA->getSpace(), RBA->getRange());
5388 NewAttr->setBinding(RegType, NewSlotNumber, RBA->getSpaceNumber());
5389 } else {
5390 // No binding attribute or space-only binding - create a binding
5391 // attribute for implicit binding.
5392 NewAttr = HLSLResourceBindingAttr::CreateImplicit(AST, "", "0", {});
5393 NewAttr->setBinding(RegType, std::nullopt,
5394 RBA ? RBA->getSpaceNumber() : 0);
5395 NewAttr->setImplicitBindingOrderID(S.getNextImplicitBindingOrderID());
5396 }
5397 if (HasCounter)
5398 NewAttr->setImplicitCounterBindingOrderID(
5400 return NewAttr;
5401 }
5402};
5403
5404// Creates a global variable declaration for a resource field embedded in a
5405// struct, assigns it a binding, initializes it, and associates it with the
5406// struct declaration via an HLSLAssociatedResourceDeclAttr.
5407static void createGlobalResourceDeclForStruct(
5408 Sema &S, VarDecl *ParentVD, SourceLocation Loc, IdentifierInfo *Id,
5409 QualType ResTy, StructBindingContext &BindingCtx) {
5410 assert(isResourceRecordTypeOrArrayOf(ResTy) &&
5411 "expected resource type or array of resources");
5412
5413 DeclContext *DC = ParentVD->getNonTransparentDeclContext();
5414 assert(DC->isTranslationUnit() && "expected translation unit decl context");
5415
5416 ASTContext &AST = S.getASTContext();
5417 VarDecl *ResDecl =
5418 VarDecl::Create(AST, DC, Loc, Loc, Id, ResTy, nullptr, SC_None);
5419
5420 unsigned Range = 1;
5421 const Type *SingleResTy = ResTy.getTypePtr()->getUnqualifiedDesugaredType();
5422 while (const auto *AT = dyn_cast<ArrayType>(SingleResTy)) {
5423 const auto *CAT = dyn_cast<ConstantArrayType>(AT);
5424 Range = CAT ? (Range * CAT->getSize().getZExtValue()) : 0;
5425 SingleResTy =
5427 }
5428 const HLSLAttributedResourceType *ResHandleTy =
5429 HLSLAttributedResourceType::findHandleTypeOnResource(SingleResTy);
5430
5431 // Add a binding attribute to the global resource declaration.
5432 bool HasCounter = hasCounterHandle(SingleResTy->getAsCXXRecordDecl());
5433 Attr *BindingAttr = BindingCtx.createBindingAttr(
5434 S.HLSL(), AST, getRegisterType(ResHandleTy), Range, HasCounter);
5435 ResDecl->addAttr(BindingAttr);
5436 ResDecl->addAttr(InternalLinkageAttr::CreateImplicit(AST));
5437 ResDecl->setImplicit();
5438
5439 if (Range == 1)
5440 S.HLSL().initGlobalResourceDecl(ResDecl);
5441 else
5442 S.HLSL().initGlobalResourceArrayDecl(ResDecl);
5443
5444 ParentVD->addAttr(
5445 HLSLAssociatedResourceDeclAttr::CreateImplicit(AST, ResDecl));
5446 DC->addDecl(ResDecl);
5447
5448 DeclGroupRef DG(ResDecl);
5450}
5451
5452static void handleArrayOfStructWithResources(
5453 Sema &S, VarDecl *ParentVD, const ConstantArrayType *CAT,
5454 EmbeddedResourceNameBuilder &NameBuilder, StructBindingContext &BindingCtx);
5455
5456// Scans base and all fields of a struct/class type to find all embedded
5457// resources or resource arrays. Creates a global variable for each resource
5458// found.
5459static void handleStructWithResources(Sema &S, VarDecl *ParentVD,
5460 const CXXRecordDecl *RD,
5461 EmbeddedResourceNameBuilder &NameBuilder,
5462 StructBindingContext &BindingCtx) {
5463
5464 // Scan the base classes.
5465 assert(RD->getNumBases() <= 1 && "HLSL doesn't support multiple inheritance");
5466 const auto *BasesIt = RD->bases_begin();
5467 if (BasesIt != RD->bases_end()) {
5468 QualType QT = BasesIt->getType();
5469 if (QT->isHLSLIntangibleType()) {
5470 CXXRecordDecl *BaseRD = QT->getAsCXXRecordDecl();
5471 NameBuilder.pushBaseName(BaseRD->getName());
5472 handleStructWithResources(S, ParentVD, BaseRD, NameBuilder, BindingCtx);
5473 NameBuilder.pop();
5474 }
5475 }
5476 // Process this class fields.
5477 for (const FieldDecl *FD : RD->fields()) {
5478 QualType FDTy = FD->getType().getCanonicalType();
5479 if (!FDTy->isHLSLIntangibleType())
5480 continue;
5481
5482 NameBuilder.pushName(FD->getName());
5483
5485 IdentifierInfo *II = NameBuilder.getNameAsIdentifier(S.getASTContext());
5486 createGlobalResourceDeclForStruct(S, ParentVD, FD->getLocation(), II,
5487 FDTy, BindingCtx);
5488 } else if (const auto *RD = FDTy->getAsCXXRecordDecl()) {
5489 handleStructWithResources(S, ParentVD, RD, NameBuilder, BindingCtx);
5490
5491 } else if (const auto *ArrayTy = dyn_cast<ConstantArrayType>(FDTy)) {
5492 assert(!FDTy->isHLSLResourceRecordArray() &&
5493 "resource arrays should have been already handled");
5494 handleArrayOfStructWithResources(S, ParentVD, ArrayTy, NameBuilder,
5495 BindingCtx);
5496 }
5497 NameBuilder.pop();
5498 }
5499}
5500
5501// Processes array of structs with resources.
5502static void
5503handleArrayOfStructWithResources(Sema &S, VarDecl *ParentVD,
5504 const ConstantArrayType *CAT,
5505 EmbeddedResourceNameBuilder &NameBuilder,
5506 StructBindingContext &BindingCtx) {
5507
5508 QualType ElementTy = CAT->getElementType().getCanonicalType();
5509 assert(ElementTy->isHLSLIntangibleType() && "Expected HLSL intangible type");
5510
5511 const ConstantArrayType *SubCAT = dyn_cast<ConstantArrayType>(ElementTy);
5512 const CXXRecordDecl *ElementRD = ElementTy->getAsCXXRecordDecl();
5513
5514 if (!SubCAT && !ElementRD)
5515 return;
5516
5517 for (unsigned I = 0, E = CAT->getSize().getZExtValue(); I < E; ++I) {
5518 NameBuilder.pushArrayIndex(I);
5519 if (ElementRD)
5520 handleStructWithResources(S, ParentVD, ElementRD, NameBuilder,
5521 BindingCtx);
5522 else
5523 handleArrayOfStructWithResources(S, ParentVD, SubCAT, NameBuilder,
5524 BindingCtx);
5525 NameBuilder.pop();
5526 }
5527}
5528
5529} // namespace
5530
5531// Scans all fields of a user-defined struct (or array of structs)
5532// to find all embedded resources or resource arrays. For each resource
5533// a global variable of the resource type is created and associated
5534// with the parent declaration (VD) through a HLSLAssociatedResourceDeclAttr
5535// attribute.
5536void SemaHLSL::handleGlobalStructOrArrayOfWithResources(VarDecl *VD) {
5537 EmbeddedResourceNameBuilder NameBuilder(VD->getName());
5538 StructBindingContext BindingCtx(VD);
5539
5540 const Type *VDTy = VD->getType().getTypePtr();
5541 assert(VDTy->isHLSLIntangibleType() && !isResourceRecordTypeOrArrayOf(VD) &&
5542 "Expected non-resource struct or array type");
5543
5544 if (const CXXRecordDecl *RD = VDTy->getAsCXXRecordDecl()) {
5545 handleStructWithResources(SemaRef, VD, RD, NameBuilder, BindingCtx);
5546 return;
5547 }
5548
5549 if (const auto *CAT = dyn_cast<ConstantArrayType>(VDTy)) {
5550 handleArrayOfStructWithResources(SemaRef, VD, CAT, NameBuilder, BindingCtx);
5551 return;
5552 }
5553}
5554
5556 if (VD->hasGlobalStorage()) {
5557 // make sure the declaration has a complete type
5558 if (SemaRef.RequireCompleteType(
5559 VD->getLocation(),
5560 SemaRef.getASTContext().getBaseElementType(VD->getType()),
5561 diag::err_typecheck_decl_incomplete_type)) {
5562 VD->setInvalidDecl();
5564 return;
5565 }
5566
5567 // Global variables outside a cbuffer block that are not a resource, static,
5568 // groupshared, or an empty array or struct belong to the default constant
5569 // buffer $Globals (to be created at the end of the translation unit).
5571 // update address space to hlsl_constant
5574 VD->setType(NewTy);
5575 DefaultCBufferDecls.push_back(VD);
5576 }
5577
5578 // find all resources bindings on decl
5579 if (VD->getType()->isHLSLIntangibleType())
5580 collectResourceBindingsOnVarDecl(VD);
5581
5582 if (VD->hasAttr<HLSLVkConstantIdAttr>())
5584
5586 VD->getStorageClass() != SC_Static) {
5587 // Add internal linkage attribute to non-static resource variables. The
5588 // global externally visible storage is accessed through the handle, which
5589 // is a member. The variable itself is not externally visible.
5590 VD->addAttr(InternalLinkageAttr::CreateImplicit(getASTContext()));
5591 }
5592
5593 // process explicit bindings
5594 processExplicitBindingsOnDecl(VD);
5595
5596 // Add implicit binding attribute to non-static resource arrays.
5597 if (VD->getType()->isHLSLResourceRecordArray() &&
5598 VD->getStorageClass() != SC_Static) {
5599 // If the resource array does not have an explicit binding attribute,
5600 // create an implicit one. It will be used to transfer implicit binding
5601 // order_ID to codegen.
5602 ResourceBindingAttrs Binding(VD);
5603 if (!Binding.isExplicit()) {
5604 uint32_t OrderID = getNextImplicitBindingOrderID();
5605 if (Binding.hasBinding())
5606 Binding.setImplicitOrderID(OrderID);
5607 else {
5610 OrderID);
5611 // Re-create the binding object to pick up the new attribute.
5612 Binding = ResourceBindingAttrs(VD);
5613 }
5614 }
5615
5616 // Get to the base type of a potentially multi-dimensional array.
5618
5619 const CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
5620 if (hasCounterHandle(RD)) {
5621 if (!Binding.hasCounterImplicitOrderID()) {
5622 uint32_t OrderID = getNextImplicitBindingOrderID();
5623 Binding.setCounterImplicitOrderID(OrderID);
5624 }
5625 }
5626 }
5627
5628 // Process resources in user-defined structs, or arrays of such structs.
5629 const Type *VDTy = VD->getType().getTypePtr();
5630 if (VD->getStorageClass() != SC_Static && VDTy->isHLSLIntangibleType() &&
5632 handleGlobalStructOrArrayOfWithResources(VD);
5633
5634 // Mark groupshared variables as extern so they will have
5635 // external storage and won't be default initialized
5636 if (VD->hasAttr<HLSLGroupSharedAddressSpaceAttr>())
5638 }
5639
5641}
5642
5644 assert(VD->getType()->isHLSLResourceRecord() &&
5645 "expected resource record type");
5646
5647 ASTContext &AST = SemaRef.getASTContext();
5648 uint64_t UIntTySize = AST.getTypeSize(AST.UnsignedIntTy);
5649 uint64_t IntTySize = AST.getTypeSize(AST.IntTy);
5650
5651 // Gather resource binding attributes.
5652 ResourceBindingAttrs Binding(VD);
5653
5654 // Find correct initialization method and create its arguments.
5655 QualType ResourceTy = VD->getType();
5656 CXXRecordDecl *ResourceDecl = ResourceTy->getAsCXXRecordDecl();
5657 CXXMethodDecl *CreateMethod = nullptr;
5659
5660 bool HasCounter = hasCounterHandle(ResourceDecl);
5661 const char *CreateMethodName;
5662 if (Binding.isExplicit())
5663 CreateMethodName = HasCounter ? "__createFromBindingWithImplicitCounter"
5664 : "__createFromBinding";
5665 else
5666 CreateMethodName = HasCounter
5667 ? "__createFromImplicitBindingWithImplicitCounter"
5668 : "__createFromImplicitBinding";
5669
5670 CreateMethod =
5671 lookupMethod(SemaRef, ResourceDecl, CreateMethodName, VD->getLocation());
5672
5673 if (!CreateMethod) {
5674 // This can happen if someone creates a struct that looks like an HLSL
5675 // resource record but does not have the required static create method.
5676 // No binding will be generated for it.
5677 assert(!ResourceDecl->isImplicit() &&
5678 "create method lookup should always succeed for built-in resource "
5679 "records");
5680 return false;
5681 }
5682
5683 if (Binding.isExplicit()) {
5684 IntegerLiteral *RegSlot =
5685 IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, Binding.getSlot()),
5687 Args.push_back(RegSlot);
5688 } else {
5689 uint32_t OrderID = (Binding.hasImplicitOrderID())
5690 ? Binding.getImplicitOrderID()
5692 IntegerLiteral *OrderId =
5693 IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, OrderID),
5695 Args.push_back(OrderId);
5696 }
5697
5698 IntegerLiteral *Space =
5699 IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, Binding.getSpace()),
5701 Args.push_back(Space);
5702
5704 AST, llvm::APInt(IntTySize, 1), AST.IntTy, SourceLocation());
5705 Args.push_back(RangeSize);
5706
5708 AST, llvm::APInt(UIntTySize, 0), AST.UnsignedIntTy, SourceLocation());
5709 Args.push_back(Index);
5710
5711 StringRef VarName = VD->getName();
5713 AST, VarName, StringLiteralKind::Ordinary, false,
5714 AST.getStringLiteralArrayType(AST.CharTy.withConst(), VarName.size()),
5715 SourceLocation());
5717 AST, AST.getPointerType(AST.CharTy.withConst()), CK_ArrayToPointerDecay,
5718 Name, nullptr, VK_PRValue, FPOptionsOverride());
5719 Args.push_back(NameCast);
5720
5721 if (HasCounter) {
5722 // Will this be in the correct order?
5723 uint32_t CounterOrderID = getNextImplicitBindingOrderID();
5724 IntegerLiteral *CounterId =
5725 IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, CounterOrderID),
5727 Args.push_back(CounterId);
5728 }
5729
5730 // Make sure the create method template is instantiated and emitted.
5731 if (!CreateMethod->isDefined() && CreateMethod->isTemplateInstantiation())
5732 SemaRef.InstantiateFunctionDefinition(VD->getLocation(), CreateMethod,
5733 true);
5734
5735 // Create CallExpr with a call to the static method and set it as the decl
5736 // initialization.
5738 AST, NestedNameSpecifierLoc(), SourceLocation(), CreateMethod, false,
5739 CreateMethod->getNameInfo(), CreateMethod->getType(), VK_PRValue);
5740
5741 auto *ImpCast = ImplicitCastExpr::Create(
5742 AST, AST.getPointerType(CreateMethod->getType()),
5743 CK_FunctionToPointerDecay, DRE, nullptr, VK_PRValue, FPOptionsOverride());
5744
5745 CallExpr *InitExpr =
5746 CallExpr::Create(AST, ImpCast, Args, ResourceTy, VK_PRValue,
5748 VD->setInit(InitExpr);
5750 SemaRef.CheckCompleteVariableDeclaration(VD);
5751 return true;
5752}
5753
5755 assert(VD->getType()->isHLSLResourceRecordArray() &&
5756 "expected array of resource records");
5757
5758 // Individual resources in a resource array are not initialized here. They
5759 // are initialized later on during codegen when the individual resources are
5760 // accessed. Codegen will emit a call to the resource initialization method
5761 // with the specified array index. We need to make sure though that the method
5762 // for the specific resource type is instantiated, so codegen can emit a call
5763 // to it when the array element is accessed.
5764
5765 // Find correct initialization method based on the resource binding
5766 // information.
5767 ASTContext &AST = SemaRef.getASTContext();
5768 QualType ResElementTy = AST.getBaseElementType(VD->getType());
5769 CXXRecordDecl *ResourceDecl = ResElementTy->getAsCXXRecordDecl();
5770 CXXMethodDecl *CreateMethod = nullptr;
5771
5772 bool HasCounter = hasCounterHandle(ResourceDecl);
5773 ResourceBindingAttrs ResourceAttrs(VD);
5774 if (ResourceAttrs.isExplicit())
5775 // Resource has explicit binding.
5776 CreateMethod =
5777 lookupMethod(SemaRef, ResourceDecl,
5778 HasCounter ? "__createFromBindingWithImplicitCounter"
5779 : "__createFromBinding",
5780 VD->getLocation());
5781 else
5782 // Resource has implicit binding.
5783 CreateMethod = lookupMethod(
5784 SemaRef, ResourceDecl,
5785 HasCounter ? "__createFromImplicitBindingWithImplicitCounter"
5786 : "__createFromImplicitBinding",
5787 VD->getLocation());
5788
5789 if (!CreateMethod)
5790 return false;
5791
5792 // Make sure the create method template is instantiated and emitted.
5793 if (!CreateMethod->isDefined() && CreateMethod->isTemplateInstantiation())
5794 SemaRef.InstantiateFunctionDefinition(VD->getLocation(), CreateMethod,
5795 true);
5796 return true;
5797}
5798
5799// Returns true if the initialization has been handled.
5800// Returns false to use default initialization.
5802 // Objects in the hlsl_constant address space are initialized
5803 // externally, so don't synthesize an implicit initializer.
5805 return true;
5806
5807 if (VD->hasGlobalStorage() && VD->getStorageClass() != SC_Static) {
5808 const Type *Ty = VD->getType().getTypePtr();
5810 return true;
5812 return true;
5813 }
5814
5815 // User-defined structs/classes do not have constructors.
5816 // When declared at a global scope, they are part of the constant buffer
5817 // and should not be initialized by the compiler.
5818 // When declared at a local scope, they are not initialized.
5819 // Also applies to arrays of user-defined structs/classes.
5820 const Type *Ty = VD->getType()->getUnqualifiedDesugaredType();
5821 while (Ty->isArrayType())
5823 if (CXXRecordDecl *RD = Ty->getAsCXXRecordDecl())
5824 return !RD->isHLSLBuiltinRecord();
5825
5826 return false;
5827}
5828
5829std::optional<const DeclBindingInfo *> SemaHLSL::inferGlobalBinding(Expr *E) {
5830 if (auto *Ternary = dyn_cast<ConditionalOperator>(E)) {
5831 auto TrueInfo = inferGlobalBinding(Ternary->getTrueExpr());
5832 auto FalseInfo = inferGlobalBinding(Ternary->getFalseExpr());
5833 if (!TrueInfo || !FalseInfo)
5834 return std::nullopt;
5835 if (*TrueInfo != *FalseInfo)
5836 return std::nullopt;
5837 return TrueInfo;
5838 }
5839
5840 if (auto *ASE = dyn_cast<ArraySubscriptExpr>(E))
5841 E = ASE->getBase()->IgnoreParenImpCasts();
5842
5843 if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParens()))
5844 if (VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
5845 const Type *Ty = VD->getType()->getUnqualifiedDesugaredType();
5846 if (Ty->isArrayType())
5848
5849 if (const auto *AttrResType =
5850 HLSLAttributedResourceType::findHandleTypeOnResource(Ty)) {
5851 ResourceClass RC = AttrResType->getAttrs().ResourceClass;
5852 return Bindings.getDeclBindingInfo(VD, RC);
5853 }
5854 }
5855
5856 return nullptr;
5857}
5858
5859void SemaHLSL::trackLocalResource(VarDecl *VD, Expr *E) {
5860 std::optional<const DeclBindingInfo *> ExprBinding = inferGlobalBinding(E);
5861 if (!ExprBinding) {
5862 SemaRef.Diag(E->getBeginLoc(),
5863 diag::warn_hlsl_assigning_local_resource_is_not_unique)
5864 << E << VD;
5865 return; // Expr use multiple resources
5866 }
5867
5868 if (*ExprBinding == nullptr)
5869 return; // No binding could be inferred to track, return without error
5870
5871 auto PrevBinding = Assigns.find(VD);
5872 if (PrevBinding == Assigns.end()) {
5873 // No previous binding recorded, simply record the new assignment
5874 Assigns.insert({VD, *ExprBinding});
5875 return;
5876 }
5877
5878 // Otherwise, warn if the assignment implies different resource bindings
5879 if (*ExprBinding != PrevBinding->second) {
5880 SemaRef.Diag(E->getBeginLoc(),
5881 diag::warn_hlsl_assigning_local_resource_is_not_unique)
5882 << E << VD;
5883 SemaRef.Diag(VD->getLocation(), diag::note_var_declared_here) << VD;
5884 return;
5885 }
5886
5887 return;
5888}
5889
5891 Expr *RHSExpr, SourceLocation Loc) {
5892 assert((LHSExpr->getType()->isHLSLResourceRecord() ||
5893 LHSExpr->getType()->isHLSLResourceRecordArray()) &&
5894 "expected LHS to be a resource record or array of resource records");
5895 if (Opc != BO_Assign)
5896 return true;
5897
5898 // If LHS is an array subscript, get the underlying declaration.
5899 Expr *E = LHSExpr;
5900 while (auto *ASE = dyn_cast<ArraySubscriptExpr>(E))
5901 E = ASE->getBase()->IgnoreParenImpCasts();
5902
5903 // Report error if LHS is a non-static resource declared at a global scope.
5904 if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParens())) {
5905 if (VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
5906 if (VD->hasGlobalStorage() && VD->getStorageClass() != SC_Static) {
5907 // assignment to global resource is not allowed
5908 SemaRef.Diag(Loc, diag::err_hlsl_assign_to_global_resource) << VD;
5909 SemaRef.Diag(VD->getLocation(), diag::note_var_declared_here) << VD;
5910 return false;
5911 }
5912
5913 trackLocalResource(VD, RHSExpr);
5914 }
5915 }
5916 return true;
5917}
5918
5919// Returns true if the given type can have an overload of the given
5920// binary operator.
5922 CXXRecordDecl *RD = LHSTy->getAsCXXRecordDecl();
5923 if (!RD)
5924 return true;
5925 return RD->isHLSLBuiltinRecord() || Opc != BO_Assign;
5926}
5927
5928// Walks though the global variable declaration, collects all resource binding
5929// requirements and adds them to Bindings
5930void SemaHLSL::collectResourceBindingsOnVarDecl(VarDecl *VD) {
5931 assert(VD->hasGlobalStorage() && VD->getType()->isHLSLIntangibleType() &&
5932 "expected global variable that contains HLSL resource");
5933
5934 // Cbuffers and Tbuffers are HLSLBufferDecl types
5935 if (const HLSLBufferDecl *CBufferOrTBuffer = dyn_cast<HLSLBufferDecl>(VD)) {
5936 Bindings.addDeclBindingInfo(VD, CBufferOrTBuffer->isCBuffer()
5937 ? ResourceClass::CBuffer
5938 : ResourceClass::SRV);
5939 return;
5940 }
5941
5942 // Unwrap arrays
5943 // FIXME: Calculate array size while unwrapping
5944 const Type *Ty = VD->getType()->getUnqualifiedDesugaredType();
5945 while (Ty->isArrayType()) {
5946 const ArrayType *AT = cast<ArrayType>(Ty);
5948 }
5949
5950 // Resource (or array of resources)
5951 if (const HLSLAttributedResourceType *AttrResType =
5952 HLSLAttributedResourceType::findHandleTypeOnResource(Ty)) {
5953 Bindings.addDeclBindingInfo(VD, AttrResType->getAttrs().ResourceClass);
5954 return;
5955 }
5956
5957 // User defined record type
5958 if (const RecordType *RT = dyn_cast<RecordType>(Ty))
5959 collectResourceBindingsOnUserRecordDecl(VD, RT);
5960}
5961
5962// Walks though the explicit resource binding attributes on the declaration,
5963// and makes sure there is a resource that matched the binding and updates
5964// DeclBindingInfoLists
5965void SemaHLSL::processExplicitBindingsOnDecl(VarDecl *VD) {
5966 assert(VD->hasGlobalStorage() && "expected global variable");
5967
5968 bool HasBinding = false;
5969 for (Attr *A : VD->attrs()) {
5970 if (isa<HLSLVkBindingAttr>(A)) {
5971 HasBinding = true;
5972 if (auto PA = VD->getAttr<HLSLVkPushConstantAttr>())
5973 Diag(PA->getLoc(), diag::err_hlsl_attr_incompatible) << A << PA;
5974 }
5975
5976 HLSLResourceBindingAttr *RBA = dyn_cast<HLSLResourceBindingAttr>(A);
5977 if (!RBA || !RBA->hasRegisterSlot())
5978 continue;
5979 HasBinding = true;
5980
5981 RegisterType RT = RBA->getRegisterType();
5982 assert(RT != RegisterType::I && "invalid or obsolete register type should "
5983 "never have an attribute created");
5984
5985 if (RT == RegisterType::C) {
5986 if (Bindings.hasBindingInfoForDecl(VD))
5987 SemaRef.Diag(VD->getLocation(),
5988 diag::warn_hlsl_user_defined_type_missing_member)
5989 << static_cast<int>(RT);
5990 continue;
5991 }
5992
5993 // Find DeclBindingInfo for this binding and update it, or report error
5994 // if it does not exist (user type does to contain resources with the
5995 // expected resource class).
5997 if (DeclBindingInfo *BI = Bindings.getDeclBindingInfo(VD, RC)) {
5998 // update binding info
5999 BI->setBindingAttribute(RBA, BindingType::Explicit);
6000 } else {
6001 SemaRef.Diag(VD->getLocation(),
6002 diag::warn_hlsl_user_defined_type_missing_member)
6003 << static_cast<int>(RT);
6004 }
6005 }
6006
6007 if (!HasBinding && isResourceRecordTypeOrArrayOf(VD))
6008 SemaRef.Diag(VD->getLocation(), diag::warn_hlsl_implicit_binding);
6009}
6010namespace {
6011class InitListTransformer {
6012 Sema &S;
6013 ASTContext &Ctx;
6014 QualType InitTy;
6015 QualType *DstIt = nullptr;
6016 Expr **ArgIt = nullptr;
6017 // Is wrapping the destination type iterator required? This is only used for
6018 // incomplete array types where we loop over the destination type since we
6019 // don't know the full number of elements from the declaration.
6020 bool Wrap;
6021
6022 bool castInitializer(Expr *E) {
6023 assert(DstIt && "This should always be something!");
6024 if (DstIt == DestTypes.end()) {
6025 if (!Wrap) {
6026 ArgExprs.push_back(E);
6027 // This is odd, but it isn't technically a failure due to conversion, we
6028 // handle mismatched counts of arguments differently.
6029 return true;
6030 }
6031 DstIt = DestTypes.begin();
6032 }
6033 InitializedEntity Entity = InitializedEntity::InitializeParameter(
6034 Ctx, *DstIt, /* Consumed (ObjC) */ false);
6035 ExprResult Res = S.PerformCopyInitialization(Entity, E->getBeginLoc(), E);
6036 if (Res.isInvalid())
6037 return false;
6038 Expr *Init = Res.get();
6039 ArgExprs.push_back(Init);
6040 DstIt++;
6041 return true;
6042 }
6043
6044 bool buildInitializerListImpl(Expr *E) {
6045 // If this is an initialization list, traverse the sub initializers.
6046 if (auto *Init = dyn_cast<InitListExpr>(E)) {
6047 for (auto *SubInit : Init->inits())
6048 if (!buildInitializerListImpl(SubInit))
6049 return false;
6050 return true;
6051 }
6052
6053 // If this is a scalar type, just enqueue the expression.
6054 QualType Ty = E->getType().getDesugaredType(Ctx);
6055
6056 if (Ty->isScalarType() || (Ty->isRecordType() && !Ty->isAggregateType()) ||
6058 return castInitializer(E);
6059
6060 // If this is an aggregate type and a prvalue, create an xvalue temporary
6061 // so the member accesses will be xvalues. Wrap it in OpaqueExpr to make
6062 // sure codegen will not generate duplicate copies.
6063 if (E->isPRValue() && Ty->isAggregateType()) {
6065 if (TmpExpr.isInvalid())
6066 return false;
6067 E = TmpExpr.get();
6068 E = new (Ctx) OpaqueValueExpr(E->getBeginLoc(), E->getType(),
6069 E->getValueKind(), E->getObjectKind(), E);
6070 }
6071
6072 if (auto *VecTy = Ty->getAs<VectorType>()) {
6073 uint64_t Size = VecTy->getNumElements();
6074
6075 QualType SizeTy = Ctx.getSizeType();
6076 uint64_t SizeTySize = Ctx.getTypeSize(SizeTy);
6077 for (uint64_t I = 0; I < Size; ++I) {
6078 auto *Idx = IntegerLiteral::Create(Ctx, llvm::APInt(SizeTySize, I),
6079 SizeTy, SourceLocation());
6080
6082 E, E->getBeginLoc(), Idx, E->getEndLoc());
6083 if (ElExpr.isInvalid())
6084 return false;
6085 if (!castInitializer(ElExpr.get()))
6086 return false;
6087 }
6088 return true;
6089 }
6090 if (auto *MTy = Ty->getAs<ConstantMatrixType>()) {
6091 unsigned Rows = MTy->getNumRows();
6092 unsigned Cols = MTy->getNumColumns();
6093 QualType ElemTy = MTy->getElementType();
6094
6095 for (unsigned R = 0; R < Rows; ++R) {
6096 for (unsigned C = 0; C < Cols; ++C) {
6097 // row index literal
6098 Expr *RowIdx = IntegerLiteral::Create(
6099 Ctx, llvm::APInt(Ctx.getIntWidth(Ctx.IntTy), R), Ctx.IntTy,
6100 E->getBeginLoc());
6101 // column index literal
6102 Expr *ColIdx = IntegerLiteral::Create(
6103 Ctx, llvm::APInt(Ctx.getIntWidth(Ctx.IntTy), C), Ctx.IntTy,
6104 E->getBeginLoc());
6106 E, RowIdx, ColIdx, E->getEndLoc());
6107 if (ElExpr.isInvalid())
6108 return false;
6109 if (!castInitializer(ElExpr.get()))
6110 return false;
6111 ElExpr.get()->setType(ElemTy);
6112 }
6113 }
6114 return true;
6115 }
6116
6117 if (auto *ArrTy = dyn_cast<ConstantArrayType>(Ty.getTypePtr())) {
6118 uint64_t Size = ArrTy->getZExtSize();
6119 QualType SizeTy = Ctx.getSizeType();
6120 uint64_t SizeTySize = Ctx.getTypeSize(SizeTy);
6121 for (uint64_t I = 0; I < Size; ++I) {
6122 auto *Idx = IntegerLiteral::Create(Ctx, llvm::APInt(SizeTySize, I),
6123 SizeTy, SourceLocation());
6125 E, E->getBeginLoc(), Idx, E->getEndLoc());
6126 if (ElExpr.isInvalid())
6127 return false;
6128 if (!buildInitializerListImpl(ElExpr.get()))
6129 return false;
6130 }
6131 return true;
6132 }
6133
6134 if (auto *RD = Ty->getAsCXXRecordDecl()) {
6135 llvm::SmallVector<CXXRecordDecl *> RecordDecls;
6136 RecordDecls.push_back(RD);
6137 while (RecordDecls.back()->getNumBases()) {
6138 CXXRecordDecl *D = RecordDecls.back();
6139 assert(D->getNumBases() == 1 &&
6140 "HLSL doesn't support multiple inheritance");
6141 RecordDecls.push_back(
6143 }
6144 while (!RecordDecls.empty()) {
6145 CXXRecordDecl *RD = RecordDecls.pop_back_val();
6146 for (auto *FD : RD->fields()) {
6147 if (FD->isUnnamedBitField())
6148 continue;
6149 DeclAccessPair Found = DeclAccessPair::make(FD, FD->getAccess());
6150 DeclarationNameInfo NameInfo(FD->getDeclName(), E->getBeginLoc());
6152 E, false, E->getBeginLoc(), CXXScopeSpec(), FD, Found, NameInfo);
6153 if (Res.isInvalid())
6154 return false;
6155 if (!buildInitializerListImpl(Res.get()))
6156 return false;
6157 }
6158 }
6159 }
6160 return true;
6161 }
6162
6163 Expr *generateInitListsImpl(QualType Ty) {
6164 Ty = Ty.getDesugaredType(Ctx);
6165 assert(ArgIt != ArgExprs.end() && "Something is off in iteration!");
6166 if (Ty->isScalarType() || (Ty->isRecordType() && !Ty->isAggregateType()) ||
6168 return *(ArgIt++);
6169
6170 llvm::SmallVector<Expr *> Inits;
6171 if (Ty->isVectorType() || Ty->isConstantArrayType() ||
6172 Ty->isConstantMatrixType()) {
6173 QualType ElTy;
6174 uint64_t Size = 0;
6175 if (auto *ATy = Ty->getAs<VectorType>()) {
6176 ElTy = ATy->getElementType();
6177 Size = ATy->getNumElements();
6178 } else if (auto *CMTy = Ty->getAs<ConstantMatrixType>()) {
6179 ElTy = CMTy->getElementType();
6180 Size = CMTy->getNumElementsFlattened();
6181 } else {
6182 auto *VTy = cast<ConstantArrayType>(Ty.getTypePtr());
6183 ElTy = VTy->getElementType();
6184 Size = VTy->getZExtSize();
6185 }
6186 for (uint64_t I = 0; I < Size; ++I)
6187 Inits.push_back(generateInitListsImpl(ElTy));
6188 }
6189 if (auto *RD = Ty->getAsCXXRecordDecl()) {
6190 llvm::SmallVector<CXXRecordDecl *> RecordDecls;
6191 RecordDecls.push_back(RD);
6192 while (RecordDecls.back()->getNumBases()) {
6193 CXXRecordDecl *D = RecordDecls.back();
6194 assert(D->getNumBases() == 1 &&
6195 "HLSL doesn't support multiple inheritance");
6196 RecordDecls.push_back(
6198 }
6199 while (!RecordDecls.empty()) {
6200 CXXRecordDecl *RD = RecordDecls.pop_back_val();
6201 for (auto *FD : RD->fields())
6202 if (!FD->isUnnamedBitField())
6203 Inits.push_back(generateInitListsImpl(FD->getType()));
6204 }
6205 }
6206 auto *NewInit =
6207 new (Ctx) InitListExpr(Ctx, Inits.front()->getBeginLoc(), Inits,
6208 Inits.back()->getEndLoc(), /*isExplicit=*/false);
6209 NewInit->setType(Ty);
6210 return NewInit;
6211 }
6212
6213public:
6214 llvm::SmallVector<QualType, 16> DestTypes;
6215 llvm::SmallVector<Expr *, 16> ArgExprs;
6216 InitListTransformer(Sema &SemaRef, const InitializedEntity &Entity)
6217 : S(SemaRef), Ctx(SemaRef.getASTContext()),
6218 Wrap(Entity.getType()->isIncompleteArrayType()) {
6219 InitTy = Entity.getType().getNonReferenceType();
6220 // When we're generating initializer lists for incomplete array types we
6221 // need to wrap around both when building the initializers and when
6222 // generating the final initializer lists.
6223 if (Wrap) {
6224 assert(InitTy->isIncompleteArrayType());
6225 const IncompleteArrayType *IAT = Ctx.getAsIncompleteArrayType(InitTy);
6226 InitTy = IAT->getElementType();
6227 }
6228 BuildFlattenedTypeList(InitTy, DestTypes);
6229 DstIt = DestTypes.begin();
6230 }
6231
6232 bool buildInitializerList(Expr *E) { return buildInitializerListImpl(E); }
6233
6234 Expr *generateInitLists() {
6235 assert(!ArgExprs.empty() &&
6236 "Call buildInitializerList to generate argument expressions.");
6237 ArgIt = ArgExprs.begin();
6238 if (!Wrap)
6239 return generateInitListsImpl(InitTy);
6240 llvm::SmallVector<Expr *> Inits;
6241 while (ArgIt != ArgExprs.end())
6242 Inits.push_back(generateInitListsImpl(InitTy));
6243
6244 auto *NewInit =
6245 new (Ctx) InitListExpr(Ctx, Inits.front()->getBeginLoc(), Inits,
6246 Inits.back()->getEndLoc(), /*isExplicit=*/false);
6247 llvm::APInt ArySize(64, Inits.size());
6248 NewInit->setType(Ctx.getConstantArrayType(InitTy, ArySize, nullptr,
6249 ArraySizeModifier::Normal, 0));
6250 return NewInit;
6251 }
6252};
6253} // namespace
6254
6255// Recursively detect any incomplete array anywhere in the type graph,
6256// including arrays, struct fields, and base classes.
6258 Ty = Ty.getCanonicalType();
6259
6260 // Array types
6261 if (const ArrayType *AT = dyn_cast<ArrayType>(Ty)) {
6263 return true;
6265 }
6266
6267 // Record (struct/class) types
6268 if (const auto *RT = Ty->getAs<RecordType>()) {
6269 const RecordDecl *RD = RT->getDecl();
6270
6271 // Walk base classes (for C++ / HLSL structs with inheritance)
6272 if (const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
6273 for (const CXXBaseSpecifier &Base : CXXRD->bases()) {
6274 if (containsIncompleteArrayType(Base.getType()))
6275 return true;
6276 }
6277 }
6278
6279 // Walk fields
6280 for (const FieldDecl *F : RD->fields()) {
6281 if (containsIncompleteArrayType(F->getType()))
6282 return true;
6283 }
6284 }
6285
6286 return false;
6287}
6288
6290 InitListExpr *Init) {
6291 // If the initializer is a scalar, just return it.
6292 if (Init->getType()->isScalarType())
6293 return true;
6294 ASTContext &Ctx = SemaRef.getASTContext();
6295 InitListTransformer ILT(SemaRef, Entity);
6296
6297 for (unsigned I = 0; I < Init->getNumInits(); ++I) {
6298 Expr *E = Init->getInit(I);
6299 if (E->HasSideEffects(Ctx)) {
6300 QualType Ty = E->getType();
6301 if (Ty->isRecordType())
6302 E = new (Ctx) MaterializeTemporaryExpr(Ty, E, E->isLValue());
6303 E = new (Ctx) OpaqueValueExpr(E->getBeginLoc(), Ty, E->getValueKind(),
6304 E->getObjectKind(), E);
6305 Init->setInit(I, E);
6306 }
6307 if (!ILT.buildInitializerList(E))
6308 return false;
6309 }
6310 size_t ExpectedSize = ILT.DestTypes.size();
6311 size_t ActualSize = ILT.ArgExprs.size();
6312 if (ExpectedSize == 0 && ActualSize == 0)
6313 return true;
6314
6315 // Reject empty initializer if *any* incomplete array exists structurally
6316 if (ActualSize == 0 && containsIncompleteArrayType(Entity.getType())) {
6317 QualType InitTy = Entity.getType().getNonReferenceType();
6318 if (InitTy.hasAddressSpace())
6319 InitTy = SemaRef.getASTContext().removeAddrSpaceQualType(InitTy);
6320
6321 SemaRef.Diag(Init->getBeginLoc(), diag::err_hlsl_incorrect_num_initializers)
6322 << /*TooManyOrFew=*/(int)(ExpectedSize < ActualSize) << InitTy
6323 << /*ExpectedSize=*/ExpectedSize << /*ActualSize=*/ActualSize;
6324 return false;
6325 }
6326
6327 // We infer size after validating legality.
6328 // For incomplete arrays it is completely arbitrary to choose whether we think
6329 // the user intended fewer or more elements. This implementation assumes that
6330 // the user intended more, and errors that there are too few initializers to
6331 // complete the final element.
6332 if (Entity.getType()->isIncompleteArrayType()) {
6333 assert(ExpectedSize > 0 &&
6334 "The expected size of an incomplete array type must be at least 1.");
6335 ExpectedSize =
6336 ((ActualSize + ExpectedSize - 1) / ExpectedSize) * ExpectedSize;
6337 }
6338
6339 // An initializer list might be attempting to initialize a reference or
6340 // rvalue-reference. When checking the initializer we should look through
6341 // the reference.
6342 QualType InitTy = Entity.getType().getNonReferenceType();
6343 if (InitTy.hasAddressSpace())
6344 InitTy = SemaRef.getASTContext().removeAddrSpaceQualType(InitTy);
6345 if (ExpectedSize != ActualSize) {
6346 int TooManyOrFew = ActualSize > ExpectedSize ? 1 : 0;
6347 SemaRef.Diag(Init->getBeginLoc(), diag::err_hlsl_incorrect_num_initializers)
6348 << TooManyOrFew << InitTy << ExpectedSize << ActualSize;
6349 return false;
6350 }
6351
6352 // generateInitListsImpl will always return an InitListExpr here, because the
6353 // scalar case is handled above.
6354 auto *NewInit = cast<InitListExpr>(ILT.generateInitLists());
6355 Init->resizeInits(Ctx, NewInit->getNumInits());
6356 for (unsigned I = 0; I < NewInit->getNumInits(); ++I)
6357 Init->updateInit(Ctx, I, NewInit->getInit(I));
6358 return true;
6359}
6360
6361static QualType ReportMatrixInvalidMember(Sema &S, StringRef Name,
6362 StringRef Expected,
6363 SourceLocation OpLoc,
6364 SourceLocation CompLoc) {
6365 S.Diag(OpLoc, diag::err_builtin_matrix_invalid_member)
6366 << Name << Expected << SourceRange(CompLoc);
6367 return QualType();
6368}
6369
6372 const IdentifierInfo *CompName,
6373 SourceLocation CompLoc) {
6374 const auto *MT = baseType->castAs<ConstantMatrixType>();
6375 StringRef AccessorName = CompName->getName();
6376 assert(!AccessorName.empty() && "Matrix Accessor must have a name");
6377
6378 unsigned Rows = MT->getNumRows();
6379 unsigned Cols = MT->getNumColumns();
6380 bool IsZeroBasedAccessor = false;
6381 unsigned ChunkLen = 0;
6382 if (AccessorName.size() < 2)
6383 return ReportMatrixInvalidMember(S, AccessorName,
6384 "length 4 for zero based: \'_mRC\' or "
6385 "length 3 for one-based: \'_RC\' accessor",
6386 OpLoc, CompLoc);
6387
6388 if (AccessorName[0] == '_') {
6389 if (AccessorName[1] == 'm') {
6390 IsZeroBasedAccessor = true;
6391 ChunkLen = 4; // zero-based: "_mRC"
6392 } else {
6393 ChunkLen = 3; // one-based: "_RC"
6394 }
6395 } else
6397 S, AccessorName, "zero based: \'_mRC\' or one-based: \'_RC\' accessor",
6398 OpLoc, CompLoc);
6399
6400 if (AccessorName.size() % ChunkLen != 0) {
6401 const llvm::StringRef Expected = IsZeroBasedAccessor
6402 ? "zero based: '_mRC' accessor"
6403 : "one-based: '_RC' accessor";
6404
6405 return ReportMatrixInvalidMember(S, AccessorName, Expected, OpLoc, CompLoc);
6406 }
6407
6408 auto isDigit = [](char c) { return c >= '0' && c <= '9'; };
6409 auto isZeroBasedIndex = [](unsigned i) { return i <= 3; };
6410 auto isOneBasedIndex = [](unsigned i) { return i >= 1 && i <= 4; };
6411
6412 bool HasRepeated = false;
6413 SmallVector<bool, 16> Seen(Rows * Cols, false);
6414 unsigned NumComponents = 0;
6415 const char *Begin = AccessorName.data();
6416
6417 for (unsigned I = 0, E = AccessorName.size(); I < E; I += ChunkLen) {
6418 const char *Chunk = Begin + I;
6419 char RowChar = 0, ColChar = 0;
6420 if (IsZeroBasedAccessor) {
6421 // Zero-based: "_mRC"
6422 if (Chunk[0] != '_' || Chunk[1] != 'm') {
6423 char Bad = (Chunk[0] != '_') ? Chunk[0] : Chunk[1];
6425 S, StringRef(&Bad, 1), "\'_m\' prefix",
6426 OpLoc.getLocWithOffset(I + (Bad == Chunk[0] ? 1 : 2)), CompLoc);
6427 }
6428 RowChar = Chunk[2];
6429 ColChar = Chunk[3];
6430 } else {
6431 // One-based: "_RC"
6432 if (Chunk[0] != '_')
6434 S, StringRef(&Chunk[0], 1), "\'_\' prefix",
6435 OpLoc.getLocWithOffset(I + 1), CompLoc);
6436 RowChar = Chunk[1];
6437 ColChar = Chunk[2];
6438 }
6439
6440 // Must be digits.
6441 bool IsDigitsError = false;
6442 if (!isDigit(RowChar)) {
6443 unsigned BadPos = IsZeroBasedAccessor ? 2 : 1;
6444 ReportMatrixInvalidMember(S, StringRef(&RowChar, 1), "row as integer",
6445 OpLoc.getLocWithOffset(I + BadPos + 1),
6446 CompLoc);
6447 IsDigitsError = true;
6448 }
6449
6450 if (!isDigit(ColChar)) {
6451 unsigned BadPos = IsZeroBasedAccessor ? 3 : 2;
6452 ReportMatrixInvalidMember(S, StringRef(&ColChar, 1), "column as integer",
6453 OpLoc.getLocWithOffset(I + BadPos + 1),
6454 CompLoc);
6455 IsDigitsError = true;
6456 }
6457 if (IsDigitsError)
6458 return QualType();
6459
6460 unsigned Row = RowChar - '0';
6461 unsigned Col = ColChar - '0';
6462
6463 bool HasIndexingError = false;
6464 if (IsZeroBasedAccessor) {
6465 // 0-based [0..3]
6466 if (!isZeroBasedIndex(Row)) {
6467 S.Diag(OpLoc, diag::err_hlsl_matrix_element_not_in_bounds)
6468 << /*row*/ 0 << /*zero-based*/ 0 << SourceRange(CompLoc);
6469 HasIndexingError = true;
6470 }
6471 if (!isZeroBasedIndex(Col)) {
6472 S.Diag(OpLoc, diag::err_hlsl_matrix_element_not_in_bounds)
6473 << /*col*/ 1 << /*zero-based*/ 0 << SourceRange(CompLoc);
6474 HasIndexingError = true;
6475 }
6476 } else {
6477 // 1-based [1..4]
6478 if (!isOneBasedIndex(Row)) {
6479 S.Diag(OpLoc, diag::err_hlsl_matrix_element_not_in_bounds)
6480 << /*row*/ 0 << /*one-based*/ 1 << SourceRange(CompLoc);
6481 HasIndexingError = true;
6482 }
6483 if (!isOneBasedIndex(Col)) {
6484 S.Diag(OpLoc, diag::err_hlsl_matrix_element_not_in_bounds)
6485 << /*col*/ 1 << /*one-based*/ 1 << SourceRange(CompLoc);
6486 HasIndexingError = true;
6487 }
6488 // Convert to 0-based after range checking.
6489 --Row;
6490 --Col;
6491 }
6492
6493 if (HasIndexingError)
6494 return QualType();
6495
6496 // Note: matrix swizzle index is hard coded. That means Row and Col can
6497 // potentially be larger than Rows and Cols if matrix size is less than
6498 // the max index size.
6499 bool HasBoundsError = false;
6500 if (Row >= Rows) {
6501 Diag(OpLoc, diag::err_hlsl_matrix_index_out_of_bounds)
6502 << /*Row*/ 0 << Row << Rows << SourceRange(CompLoc);
6503 HasBoundsError = true;
6504 }
6505 if (Col >= Cols) {
6506 Diag(OpLoc, diag::err_hlsl_matrix_index_out_of_bounds)
6507 << /*Col*/ 1 << Col << Cols << SourceRange(CompLoc);
6508 HasBoundsError = true;
6509 }
6510 if (HasBoundsError)
6511 return QualType();
6512
6513 unsigned FlatIndex = Row * Cols + Col;
6514 if (Seen[FlatIndex])
6515 HasRepeated = true;
6516 Seen[FlatIndex] = true;
6517 ++NumComponents;
6518 }
6519 if (NumComponents == 0 || NumComponents > 4) {
6520 S.Diag(OpLoc, diag::err_hlsl_matrix_swizzle_invalid_length)
6521 << NumComponents << SourceRange(CompLoc);
6522 return QualType();
6523 }
6524
6525 QualType ElemTy = MT->getElementType();
6526 if (NumComponents == 1)
6527 return ElemTy;
6528 QualType VT = S.Context.getExtVectorType(ElemTy, NumComponents);
6529 if (HasRepeated)
6530 VK = VK_PRValue;
6531
6532 for (Sema::ExtVectorDeclsType::iterator
6534 E = S.ExtVectorDecls.end();
6535 I != E; ++I) {
6536 if ((*I)->getUnderlyingType() == VT)
6538 /*Qualifier=*/std::nullopt, *I);
6539 }
6540
6541 return VT;
6542}
6543
6545 // If initializing a local resource, track the resource binding it is using
6546 if (VDecl->getType()->isHLSLResourceRecord() && !VDecl->hasGlobalStorage())
6547 trackLocalResource(VDecl, Init);
6548
6549 const HLSLVkConstantIdAttr *ConstIdAttr =
6550 VDecl->getAttr<HLSLVkConstantIdAttr>();
6551 if (!ConstIdAttr)
6552 return true;
6553
6554 ASTContext &Context = SemaRef.getASTContext();
6555
6556 APValue InitValue;
6557 if (!Init->isCXX11ConstantExpr(Context, &InitValue)) {
6558 Diag(VDecl->getLocation(), diag::err_specialization_const);
6559 VDecl->setInvalidDecl();
6560 return false;
6561 }
6562
6563 Builtin::ID BID =
6565
6566 // Argument 1: The ID from the attribute
6567 int ConstantID = ConstIdAttr->getId();
6568 llvm::APInt IDVal(Context.getIntWidth(Context.IntTy), ConstantID);
6569 Expr *IdExpr = IntegerLiteral::Create(Context, IDVal, Context.IntTy,
6570 ConstIdAttr->getLocation());
6571
6572 SmallVector<Expr *, 2> Args = {IdExpr, Init};
6573 Expr *C = SemaRef.BuildBuiltinCallExpr(Init->getExprLoc(), BID, Args);
6574 if (C->getType()->getCanonicalTypeUnqualified() !=
6576 C = SemaRef
6577 .BuildCStyleCastExpr(SourceLocation(),
6578 Context.getTrivialTypeSourceInfo(
6579 Init->getType(), Init->getExprLoc()),
6580 SourceLocation(), C)
6581 .get();
6582 }
6583 Init = C;
6584 return true;
6585}
6586
6588 SourceLocation NameLoc) {
6589 if (!Template)
6590 return QualType();
6591
6592 DeclContext *DC = Template->getDeclContext();
6593 if (!DC->isNamespace() || !cast<NamespaceDecl>(DC)->getIdentifier() ||
6594 cast<NamespaceDecl>(DC)->getName() != "hlsl")
6595 return QualType();
6596
6597 TemplateParameterList *Params = Template->getTemplateParameters();
6598 if (!Params || Params->size() != 1)
6599 return QualType();
6600
6601 if (!Template->isImplicit())
6602 return QualType();
6603
6604 // We manually extract default arguments here instead of letting
6605 // CheckTemplateIdType handle it. This ensures that for resource types that
6606 // lack a default argument (like Buffer), we return a null QualType, which
6607 // triggers the "requires template arguments" error rather than a less
6608 // descriptive "too few template arguments" error.
6609 TemplateArgumentListInfo TemplateArgs(NameLoc, NameLoc);
6610 for (NamedDecl *P : *Params) {
6611 if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(P)) {
6612 if (TTP->hasDefaultArgument()) {
6613 TemplateArgs.addArgument(TTP->getDefaultArgument());
6614 continue;
6615 }
6616 } else if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P)) {
6617 if (NTTP->hasDefaultArgument()) {
6618 TemplateArgs.addArgument(NTTP->getDefaultArgument());
6619 continue;
6620 }
6621 } else if (auto *TTPD = dyn_cast<TemplateTemplateParmDecl>(P)) {
6622 if (TTPD->hasDefaultArgument()) {
6623 TemplateArgs.addArgument(TTPD->getDefaultArgument());
6624 continue;
6625 }
6626 }
6627 return QualType();
6628 }
6629
6630 return SemaRef.CheckTemplateIdType(
6632 TemplateArgs, nullptr, /*ForNestedNameSpecifier=*/false);
6633}
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 CheckTextureSamplerAndLocation(Sema &S, CallExpr *TheCall, bool IncludeArraySlice=true)
static bool CheckVectorSelect(Sema *S, CallExpr *TheCall)
static QualType handleFloatVectorBinOpConversion(Sema &SemaRef, ExprResult &LHS, ExprResult &RHS, QualType LHSType, QualType RHSType, QualType LElTy, QualType RElTy, bool IsCompAssign)
static const Type * getHostLayoutFieldType(QualType QT)
Definition SemaHLSL.cpp: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 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:808
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:890
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:927
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:2247
base_class_range bases()
Definition DeclCXX.h:608
unsigned getNumBases() const
Retrieves the number of base classes of this class.
Definition DeclCXX.h:602
bool isHLSLBuiltinRecord() const
Returns true if the class is a built-in HLSL record.
Definition DeclCXX.h: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:2949
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition Expr.h:3153
SourceLocation getBeginLoc() const
Definition Expr.h:3283
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:3132
Expr * getCallee()
Definition Expr.h:3096
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition Expr.h:3140
SourceLocation getEndLoc() const
Definition Expr.h:3302
Decl * getCalleeDecl()
Definition Expr.h:3126
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:1466
bool isNamespace() const
Definition DeclBase.h:2219
lookup_result lookup(DeclarationName Name) const
lookup - Find the declarations (if any) with the given Name in this context.
bool isTranslationUnit() const
Definition DeclBase.h:2202
void addDecl(Decl *D)
Add the declaration D into this context.
decl_range decls() const
decls_begin/decls_end - Iterate over the declarations stored in this context.
Definition DeclBase.h:2403
DeclContext * getNonTransparentContext()
A reference to a declared variable, function, enum, etc.
Definition Expr.h:1276
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:1344
Decl - This represents one declaration (or definition), e.g.
Definition DeclBase.h:86
T * getAttr() const
Definition DeclBase.h:581
ASTContext & getASTContext() const LLVM_READONLY
Definition DeclBase.cpp:550
void addAttr(Attr *A)
attr_iterator attr_end() const
Definition DeclBase.h:550
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
Definition DeclBase.h:601
void setInvalidDecl(bool Invalid=true)
setInvalidDecl - Indicates the Decl had a semantic error.
Definition DeclBase.cpp:178
bool isInExportDeclContext() const
Whether this declaration was exported in a lexical context.
attr_iterator attr_begin() const
Definition DeclBase.h:547
DeclContext * getNonTransparentDeclContext()
Return the non transparent context.
SourceLocation getLocation() const
Definition DeclBase.h:447
void setImplicit(bool I=true)
Definition DeclBase.h:602
DeclContext * getDeclContext()
Definition DeclBase.h:456
attr_range attrs() const
Definition DeclBase.h:543
AccessSpecifier getAccess() const
Definition DeclBase.h:515
SourceLocation getBeginLoc() const LLVM_READONLY
Definition DeclBase.h:439
void dropAttr()
Definition DeclBase.h:564
bool hasAttr() const
Definition DeclBase.h:585
The name of a declaration.
Represents a ValueDecl that came out of a declarator.
Definition Decl.h: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:3204
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:4698
static FixItHint CreateReplacement(CharSourceRange RemoveRange, StringRef Code)
Create a code modification hint that replaces the given source range with the given code string.
Definition Diagnostic.h:142
Represents a function declaration or definition.
Definition Decl.h:2029
const ParmVarDecl * getParamDecl(unsigned i) const
Definition Decl.h:2837
Stmt * getBody(const FunctionDecl *&Definition) const
Retrieve the body (definition) of the function.
Definition Decl.cpp:3257
bool isThisDeclarationADefinition() const
Returns whether this specific declaration of the function is also a definition that does not contain ...
Definition Decl.h:2350
QualType getReturnType() const
Definition Decl.h:2885
ArrayRef< ParmVarDecl * > parameters() const
Definition Decl.h:2814
bool isTemplateInstantiation() const
Determines if the given function was instantiated from a function template.
Definition Decl.cpp:4235
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:3804
DeclarationNameInfo getNameInfo() const
Definition Decl.h:2247
bool hasBody(const FunctionDecl *&Definition) const
Returns true if the function has a body.
Definition Decl.cpp:3177
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:3224
HLSLBufferDecl - Represent a cbuffer or tbuffer declaration.
Definition Decl.h:5238
static HLSLBufferDecl * Create(ASTContext &C, DeclContext *LexicalParent, bool CBuffer, SourceLocation KwLoc, IdentifierInfo *ID, SourceLocation IDLoc, SourceLocation LBrace)
Definition Decl.cpp:5908
void addLayoutStruct(CXXRecordDecl *LS)
Definition Decl.cpp:5948
void setHasValidPackoffset(bool PO)
Definition Decl.h:5283
static HLSLBufferDecl * CreateDefaultCBuffer(ASTContext &C, DeclContext *LexicalParent, ArrayRef< Decl * > DefaultCBufferDecls)
Definition Decl.cpp:5931
buffer_decl_range buffer_decls() const
Definition Decl.h:5313
static HLSLOutArgExpr * Create(const ASTContext &C, QualType Ty, OpaqueValueExpr *Base, OpaqueValueExpr *OpV, Expr *WB, bool IsInOut)
Definition Expr.cpp:5664
static HLSLRootSignatureDecl * Create(ASTContext &C, DeclContext *DC, SourceLocation Loc, IdentifierInfo *ID, llvm::dxbc::RootSignatureVersion Version, ArrayRef< llvm::hlsl::rootsig::RootElement > RootElements)
Definition Decl.cpp:5994
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:3859
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:5314
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:3370
ValueDecl * getMemberDecl() const
Retrieve the member declaration to which this expression refers.
Definition Expr.h:3453
Expr * getBase() const
Definition Expr.h:3447
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:1184
Represents a parameter to a function.
Definition Decl.h:1819
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:3686
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:4369
field_range fields() const
Definition Decl.h:4572
RecordDecl * getDefinitionOrSelf() const
Definition Decl.h:4557
bool field_empty() const
Definition Decl.h:4580
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:249
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:200
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)
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)
std::optional< ExprResult > tryPerformConstantBufferConversion(Expr *BaseExpr)
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:869
@ LookupOrdinaryName
Ordinary name lookup, which finds ordinary names (functions, variables, typedefs, etc....
Definition Sema.h:9421
@ LookupMemberName
Member name lookup, which finds the names of class/struct/union members.
Definition Sema.h:9429
ExtVectorDeclsType ExtVectorDecls
ExtVectorDecls - This is a list all the extended vector types.
Definition Sema.h:4966
ASTContext & Context
Definition Sema.h:1310
ASTContext & getASTContext() const
Definition Sema.h:941
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:769
const LangOptions & getLangOpts() const
Definition Sema.h:934
ExprResult TemporaryMaterializationConversion(Expr *E)
If E is a prvalue denoting an unmaterialized temporary, materialize it as an xvalue.
SemaHLSL & HLSL()
Definition Sema.h:1485
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:944
ASTConsumer & Consumer
Definition Sema.h:1311
bool checkArgCount(CallExpr *Call, unsigned DesiredArgCount)
Checks that a call expression's argument count is the desired number.
ExprResult CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, Expr *Idx, SourceLocation RLoc)
bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, bool InUnqualifiedLookup=false)
Perform qualified name lookup into a given context.
ExprResult PerformCopyInitialization(const InitializedEntity &Entity, SourceLocation EqualLoc, ExprResult Init, bool TopLevelOfInitList=false, bool AllowExplicit=false)
ExprResult CreateBuiltinMatrixSubscriptExpr(Expr *Base, Expr *RowIdx, Expr *ColumnIdx, SourceLocation RBLoc)
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
SourceLocation getLocWithOffset(IntTy Offset) const
Return a source location with the specified offset from this SourceLocation.
A trivial tuple used to represent a source range.
SourceLocation getEnd() const
SourceLocation getEndLoc() const LLVM_READONLY
Definition Stmt.cpp:367
void printPretty(raw_ostream &OS, PrinterHelper *Helper, const PrintingPolicy &Policy, unsigned Indentation=0, StringRef NewlineSymbol="\n", const ASTContext *Context=nullptr) const
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition Stmt.cpp:343
SourceLocation getBeginLoc() const LLVM_READONLY
Definition Stmt.cpp:355
StringLiteral - This represents a string literal expression, e.g.
Definition Expr.h:1805
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:4904
bool isUnion() const
Definition Decl.h:3972
bool isClass() const
Definition Decl.h:3971
Exposes information about the current target.
Definition TargetInfo.h:227
TargetOptions & getTargetOpts() const
Retrieve the target options.
Definition TargetInfo.h:330
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:2123
bool isArrayType() const
Definition TypeBase.h:8783
CXXRecordDecl * castAsCXXRecordDecl() const
Definition Type.h:36
bool isArithmeticType() const
Definition Type.cpp:2426
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:5527
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:2160
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:2380
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:2507
ScalarTypeKind getScalarTypeKind() const
Given that this is a scalar type, classify it.
Definition Type.cpp:2458
bool hasSignedIntegerRepresentation() const
Determine whether this type has an signed integer representation of some sort, e.g....
Definition Type.cpp:2314
bool isMatrixType() const
Definition TypeBase.h:8847
bool isHLSLResourceRecord() const
Definition Type.cpp:5514
bool hasFloatingRepresentation() const
Determine whether this type has a floating-point representation of some sort, e.g....
Definition Type.cpp:2401
bool isVectorType() const
Definition TypeBase.h:8823
bool isRealFloatingType() const
Floating point categories.
Definition Type.cpp:2409
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:2393
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:5518
void setType(QualType newType)
Definition Decl.h:724
QualType getType() const
Definition Decl.h:723
Represents a variable declaration or definition.
Definition Decl.h:932
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:1476
@ CallInit
Call-style initialization (C++98)
Definition Decl.h:940
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:1247
void setInit(Expr *I)
Definition Decl.cpp:2456
StorageClass getStorageClass() const
Returns the storage class as written in the source.
Definition Decl.h:1174
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)
SetTy< T > join(SetTy< T > A, SetTy< T > B, typename SetTy< T >::Factory &F)
Computes the union of two ImmutableSets.
Definition Utils.h:49
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