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