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