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