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