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