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