clang 22.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/Attrs.inc"
16#include "clang/AST/Decl.h"
17#include "clang/AST/DeclBase.h"
18#include "clang/AST/DeclCXX.h"
21#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/TargetParser/Triple.h"
51#include <cmath>
52#include <cstddef>
53#include <iterator>
54#include <utility>
55
56using namespace clang;
57using namespace clang::hlsl;
58using RegisterType = HLSLResourceBindingAttr::RegisterType;
59
61 CXXRecordDecl *StructDecl);
62
64 switch (RC) {
65 case ResourceClass::SRV:
66 return RegisterType::SRV;
67 case ResourceClass::UAV:
68 return RegisterType::UAV;
69 case ResourceClass::CBuffer:
70 return RegisterType::CBuffer;
71 case ResourceClass::Sampler:
72 return RegisterType::Sampler;
73 }
74 llvm_unreachable("unexpected ResourceClass value");
75}
76
77static RegisterType getRegisterType(const HLSLAttributedResourceType *ResTy) {
78 return getRegisterType(ResTy->getAttrs().ResourceClass);
79}
80
81// Converts the first letter of string Slot to RegisterType.
82// Returns false if the letter does not correspond to a valid register type.
83static bool convertToRegisterType(StringRef Slot, RegisterType *RT) {
84 assert(RT != nullptr);
85 switch (Slot[0]) {
86 case 't':
87 case 'T':
88 *RT = RegisterType::SRV;
89 return true;
90 case 'u':
91 case 'U':
92 *RT = RegisterType::UAV;
93 return true;
94 case 'b':
95 case 'B':
96 *RT = RegisterType::CBuffer;
97 return true;
98 case 's':
99 case 'S':
100 *RT = RegisterType::Sampler;
101 return true;
102 case 'c':
103 case 'C':
104 *RT = RegisterType::C;
105 return true;
106 case 'i':
107 case 'I':
108 *RT = RegisterType::I;
109 return true;
110 default:
111 return false;
112 }
113}
114
116 switch (RT) {
117 case RegisterType::SRV:
118 return ResourceClass::SRV;
119 case RegisterType::UAV:
120 return ResourceClass::UAV;
121 case RegisterType::CBuffer:
122 return ResourceClass::CBuffer;
123 case RegisterType::Sampler:
124 return ResourceClass::Sampler;
125 case RegisterType::C:
126 case RegisterType::I:
127 // Deliberately falling through to the unreachable below.
128 break;
129 }
130 llvm_unreachable("unexpected RegisterType value");
131}
132
134 const auto *BT = dyn_cast<BuiltinType>(Type);
135 if (!BT) {
136 if (!Type->isEnumeralType())
137 return Builtin::NotBuiltin;
138 return Builtin::BI__builtin_get_spirv_spec_constant_int;
139 }
140
141 switch (BT->getKind()) {
142 case BuiltinType::Bool:
143 return Builtin::BI__builtin_get_spirv_spec_constant_bool;
144 case BuiltinType::Short:
145 return Builtin::BI__builtin_get_spirv_spec_constant_short;
146 case BuiltinType::Int:
147 return Builtin::BI__builtin_get_spirv_spec_constant_int;
148 case BuiltinType::LongLong:
149 return Builtin::BI__builtin_get_spirv_spec_constant_longlong;
150 case BuiltinType::UShort:
151 return Builtin::BI__builtin_get_spirv_spec_constant_ushort;
152 case BuiltinType::UInt:
153 return Builtin::BI__builtin_get_spirv_spec_constant_uint;
154 case BuiltinType::ULongLong:
155 return Builtin::BI__builtin_get_spirv_spec_constant_ulonglong;
156 case BuiltinType::Half:
157 return Builtin::BI__builtin_get_spirv_spec_constant_half;
158 case BuiltinType::Float:
159 return Builtin::BI__builtin_get_spirv_spec_constant_float;
160 case BuiltinType::Double:
161 return Builtin::BI__builtin_get_spirv_spec_constant_double;
162 default:
163 return Builtin::NotBuiltin;
164 }
165}
166
168 ResourceClass ResClass) {
169 assert(getDeclBindingInfo(VD, ResClass) == nullptr &&
170 "DeclBindingInfo already added");
171 assert(!hasBindingInfoForDecl(VD) || BindingsList.back().Decl == VD);
172 // VarDecl may have multiple entries for different resource classes.
173 // DeclToBindingListIndex stores the index of the first binding we saw
174 // for this decl. If there are any additional ones then that index
175 // shouldn't be updated.
176 DeclToBindingListIndex.try_emplace(VD, BindingsList.size());
177 return &BindingsList.emplace_back(VD, ResClass);
178}
179
181 ResourceClass ResClass) {
182 auto Entry = DeclToBindingListIndex.find(VD);
183 if (Entry != DeclToBindingListIndex.end()) {
184 for (unsigned Index = Entry->getSecond();
185 Index < BindingsList.size() && BindingsList[Index].Decl == VD;
186 ++Index) {
187 if (BindingsList[Index].ResClass == ResClass)
188 return &BindingsList[Index];
189 }
190 }
191 return nullptr;
192}
193
195 return DeclToBindingListIndex.contains(VD);
196}
197
199
200Decl *SemaHLSL::ActOnStartBuffer(Scope *BufferScope, bool CBuffer,
201 SourceLocation KwLoc, IdentifierInfo *Ident,
202 SourceLocation IdentLoc,
203 SourceLocation LBrace) {
204 // For anonymous namespace, take the location of the left brace.
205 DeclContext *LexicalParent = SemaRef.getCurLexicalContext();
207 getASTContext(), LexicalParent, CBuffer, KwLoc, Ident, IdentLoc, LBrace);
208
209 // if CBuffer is false, then it's a TBuffer
210 auto RC = CBuffer ? llvm::hlsl::ResourceClass::CBuffer
211 : llvm::hlsl::ResourceClass::SRV;
212 Result->addAttr(HLSLResourceClassAttr::CreateImplicit(getASTContext(), RC));
213
214 SemaRef.PushOnScopeChains(Result, BufferScope);
215 SemaRef.PushDeclContext(BufferScope, Result);
216
217 return Result;
218}
219
220static unsigned calculateLegacyCbufferFieldAlign(const ASTContext &Context,
221 QualType T) {
222 // Arrays and Structs are always aligned to new buffer rows
223 if (T->isArrayType() || T->isStructureType())
224 return 16;
225
226 // Vectors are aligned to the type they contain
227 if (const VectorType *VT = T->getAs<VectorType>())
228 return calculateLegacyCbufferFieldAlign(Context, VT->getElementType());
229
230 assert(Context.getTypeSize(T) <= 64 &&
231 "Scalar bit widths larger than 64 not supported");
232
233 // Scalar types are aligned to their byte width
234 return Context.getTypeSize(T) / 8;
235}
236
237// Calculate the size of a legacy cbuffer type in bytes based on
238// https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-packing-rules
239static unsigned calculateLegacyCbufferSize(const ASTContext &Context,
240 QualType T) {
241 constexpr unsigned CBufferAlign = 16;
242 if (const auto *RD = T->getAsRecordDecl()) {
243 unsigned Size = 0;
244 for (const FieldDecl *Field : RD->fields()) {
245 QualType Ty = Field->getType();
246 unsigned FieldSize = calculateLegacyCbufferSize(Context, Ty);
247 unsigned FieldAlign = calculateLegacyCbufferFieldAlign(Context, Ty);
248
249 // If the field crosses the row boundary after alignment it drops to the
250 // next row
251 unsigned AlignSize = llvm::alignTo(Size, FieldAlign);
252 if ((AlignSize % CBufferAlign) + FieldSize > CBufferAlign) {
253 FieldAlign = CBufferAlign;
254 }
255
256 Size = llvm::alignTo(Size, FieldAlign);
257 Size += FieldSize;
258 }
259 return Size;
260 }
261
262 if (const ConstantArrayType *AT = Context.getAsConstantArrayType(T)) {
263 unsigned ElementCount = AT->getSize().getZExtValue();
264 if (ElementCount == 0)
265 return 0;
266
267 unsigned ElementSize =
268 calculateLegacyCbufferSize(Context, AT->getElementType());
269 unsigned AlignedElementSize = llvm::alignTo(ElementSize, CBufferAlign);
270 return AlignedElementSize * (ElementCount - 1) + ElementSize;
271 }
272
273 if (const VectorType *VT = T->getAs<VectorType>()) {
274 unsigned ElementCount = VT->getNumElements();
275 unsigned ElementSize =
276 calculateLegacyCbufferSize(Context, VT->getElementType());
277 return ElementSize * ElementCount;
278 }
279
280 return Context.getTypeSize(T) / 8;
281}
282
283// Validate packoffset:
284// - if packoffset it used it must be set on all declarations inside the buffer
285// - packoffset ranges must not overlap
286static void validatePackoffset(Sema &S, HLSLBufferDecl *BufDecl) {
288
289 // Make sure the packoffset annotations are either on all declarations
290 // or on none.
291 bool HasPackOffset = false;
292 bool HasNonPackOffset = false;
293 for (auto *Field : BufDecl->buffer_decls()) {
294 VarDecl *Var = dyn_cast<VarDecl>(Field);
295 if (!Var)
296 continue;
297 if (Field->hasAttr<HLSLPackOffsetAttr>()) {
298 PackOffsetVec.emplace_back(Var, Field->getAttr<HLSLPackOffsetAttr>());
299 HasPackOffset = true;
300 } else {
301 HasNonPackOffset = true;
302 }
303 }
304
305 if (!HasPackOffset)
306 return;
307
308 if (HasNonPackOffset)
309 S.Diag(BufDecl->getLocation(), diag::warn_hlsl_packoffset_mix);
310
311 // Make sure there is no overlap in packoffset - sort PackOffsetVec by offset
312 // and compare adjacent values.
313 bool IsValid = true;
314 ASTContext &Context = S.getASTContext();
315 std::sort(PackOffsetVec.begin(), PackOffsetVec.end(),
316 [](const std::pair<VarDecl *, HLSLPackOffsetAttr *> &LHS,
317 const std::pair<VarDecl *, HLSLPackOffsetAttr *> &RHS) {
318 return LHS.second->getOffsetInBytes() <
319 RHS.second->getOffsetInBytes();
320 });
321 for (unsigned i = 0; i < PackOffsetVec.size() - 1; i++) {
322 VarDecl *Var = PackOffsetVec[i].first;
323 HLSLPackOffsetAttr *Attr = PackOffsetVec[i].second;
324 unsigned Size = calculateLegacyCbufferSize(Context, Var->getType());
325 unsigned Begin = Attr->getOffsetInBytes();
326 unsigned End = Begin + Size;
327 unsigned NextBegin = PackOffsetVec[i + 1].second->getOffsetInBytes();
328 if (End > NextBegin) {
329 VarDecl *NextVar = PackOffsetVec[i + 1].first;
330 S.Diag(NextVar->getLocation(), diag::err_hlsl_packoffset_overlap)
331 << NextVar << Var;
332 IsValid = false;
333 }
334 }
335 BufDecl->setHasValidPackoffset(IsValid);
336}
337
338// Returns true if the array has a zero size = if any of the dimensions is 0
339static bool isZeroSizedArray(const ConstantArrayType *CAT) {
340 while (CAT && !CAT->isZeroSize())
341 CAT = dyn_cast<ConstantArrayType>(
343 return CAT != nullptr;
344}
345
347 const Type *Ty = VD->getType().getTypePtr();
349}
350
351static const HLSLAttributedResourceType *
353 assert(VD->getType()->isHLSLResourceRecordArray() &&
354 "expected array of resource records");
355 const Type *Ty = VD->getType()->getUnqualifiedDesugaredType();
356 while (const ArrayType *AT = dyn_cast<ArrayType>(Ty))
358 return HLSLAttributedResourceType::findHandleTypeOnResource(Ty);
359}
360
361// Returns true if the type is a leaf element type that is not valid to be
362// included in HLSL Buffer, such as a resource class, empty struct, zero-sized
363// array, or a builtin intangible type. Returns false it is a valid leaf element
364// type or if it is a record type that needs to be inspected further.
368 return true;
369 if (const auto *RD = Ty->getAsCXXRecordDecl())
370 return RD->isEmpty();
371 if (Ty->isConstantArrayType() &&
373 return true;
375 return true;
376 return false;
377}
378
379// Returns true if the struct contains at least one element that prevents it
380// from being included inside HLSL Buffer as is, such as an intangible type,
381// empty struct, or zero-sized array. If it does, a new implicit layout struct
382// needs to be created for HLSL Buffer use that will exclude these unwanted
383// declarations (see createHostLayoutStruct function).
385 if (RD->isHLSLIntangible() || RD->isEmpty())
386 return true;
387 // check fields
388 for (const FieldDecl *Field : RD->fields()) {
389 QualType Ty = Field->getType();
391 return true;
392 if (const auto *RD = Ty->getAsCXXRecordDecl();
394 return true;
395 }
396 // check bases
397 for (const CXXBaseSpecifier &Base : RD->bases())
399 Base.getType()->castAsCXXRecordDecl()))
400 return true;
401 return false;
402}
403
405 DeclContext *DC) {
406 CXXRecordDecl *RD = nullptr;
407 for (NamedDecl *Decl :
409 if (CXXRecordDecl *FoundRD = dyn_cast<CXXRecordDecl>(Decl)) {
410 assert(RD == nullptr &&
411 "there should be at most 1 record by a given name in a scope");
412 RD = FoundRD;
413 }
414 }
415 return RD;
416}
417
418// Creates a name for buffer layout struct using the provide name base.
419// If the name must be unique (not previously defined), a suffix is added
420// until a unique name is found.
422 bool MustBeUnique) {
423 ASTContext &AST = S.getASTContext();
424
425 IdentifierInfo *NameBaseII = BaseDecl->getIdentifier();
426 llvm::SmallString<64> Name("__cblayout_");
427 if (NameBaseII) {
428 Name.append(NameBaseII->getName());
429 } else {
430 // anonymous struct
431 Name.append("anon");
432 MustBeUnique = true;
433 }
434
435 size_t NameLength = Name.size();
436 IdentifierInfo *II = &AST.Idents.get(Name, tok::TokenKind::identifier);
437 if (!MustBeUnique)
438 return II;
439
440 unsigned suffix = 0;
441 while (true) {
442 if (suffix != 0) {
443 Name.append("_");
444 Name.append(llvm::Twine(suffix).str());
445 II = &AST.Idents.get(Name, tok::TokenKind::identifier);
446 }
447 if (!findRecordDeclInContext(II, BaseDecl->getDeclContext()))
448 return II;
449 // declaration with that name already exists - increment suffix and try
450 // again until unique name is found
451 suffix++;
452 Name.truncate(NameLength);
453 };
454}
455
456// Creates a field declaration of given name and type for HLSL buffer layout
457// struct. Returns nullptr if the type cannot be use in HLSL Buffer layout.
459 IdentifierInfo *II,
460 CXXRecordDecl *LayoutStruct) {
462 return nullptr;
463
464 if (auto *RD = Ty->getAsCXXRecordDecl()) {
466 RD = createHostLayoutStruct(S, RD);
467 if (!RD)
468 return nullptr;
470 }
471 }
472
473 QualType QT = QualType(Ty, 0);
474 ASTContext &AST = S.getASTContext();
476 auto *Field = FieldDecl::Create(AST, LayoutStruct, SourceLocation(),
477 SourceLocation(), II, QT, TSI, nullptr, false,
479 Field->setAccess(AccessSpecifier::AS_public);
480 return Field;
481}
482
483// Creates host layout struct for a struct included in HLSL Buffer.
484// The layout struct will include only fields that are allowed in HLSL buffer.
485// These fields will be filtered out:
486// - resource classes
487// - empty structs
488// - zero-sized arrays
489// Returns nullptr if the resulting layout struct would be empty.
491 CXXRecordDecl *StructDecl) {
492 assert(requiresImplicitBufferLayoutStructure(StructDecl) &&
493 "struct is already HLSL buffer compatible");
494
495 ASTContext &AST = S.getASTContext();
496 DeclContext *DC = StructDecl->getDeclContext();
497 IdentifierInfo *II = getHostLayoutStructName(S, StructDecl, false);
498
499 // reuse existing if the layout struct if it already exists
500 if (CXXRecordDecl *RD = findRecordDeclInContext(II, DC))
501 return RD;
502
503 CXXRecordDecl *LS =
504 CXXRecordDecl::Create(AST, TagDecl::TagKind::Struct, DC, SourceLocation(),
505 SourceLocation(), II);
506 LS->setImplicit(true);
507 LS->addAttr(PackedAttr::CreateImplicit(AST));
508 LS->startDefinition();
509
510 // copy base struct, create HLSL Buffer compatible version if needed
511 if (unsigned NumBases = StructDecl->getNumBases()) {
512 assert(NumBases == 1 && "HLSL supports only one base type");
513 (void)NumBases;
514 CXXBaseSpecifier Base = *StructDecl->bases_begin();
515 CXXRecordDecl *BaseDecl = Base.getType()->castAsCXXRecordDecl();
517 BaseDecl = createHostLayoutStruct(S, BaseDecl);
518 if (BaseDecl) {
519 TypeSourceInfo *TSI =
521 Base = CXXBaseSpecifier(SourceRange(), false, StructDecl->isClass(),
522 AS_none, TSI, SourceLocation());
523 }
524 }
525 if (BaseDecl) {
526 const CXXBaseSpecifier *BasesArray[1] = {&Base};
527 LS->setBases(BasesArray, 1);
528 }
529 }
530
531 // filter struct fields
532 for (const FieldDecl *FD : StructDecl->fields()) {
533 const Type *Ty = FD->getType()->getUnqualifiedDesugaredType();
534 if (FieldDecl *NewFD =
535 createFieldForHostLayoutStruct(S, Ty, FD->getIdentifier(), LS))
536 LS->addDecl(NewFD);
537 }
538 LS->completeDefinition();
539
540 if (LS->field_empty() && LS->getNumBases() == 0)
541 return nullptr;
542
543 DC->addDecl(LS);
544 return LS;
545}
546
547// Creates host layout struct for HLSL Buffer. The struct will include only
548// fields of types that are allowed in HLSL buffer and it will filter out:
549// - static or groupshared variable declarations
550// - resource classes
551// - empty structs
552// - zero-sized arrays
553// - non-variable declarations
554// The layout struct will be added to the HLSLBufferDecl declarations.
556 ASTContext &AST = S.getASTContext();
557 IdentifierInfo *II = getHostLayoutStructName(S, BufDecl, true);
558
559 CXXRecordDecl *LS =
560 CXXRecordDecl::Create(AST, TagDecl::TagKind::Struct, BufDecl,
562 LS->addAttr(PackedAttr::CreateImplicit(AST));
563 LS->setImplicit(true);
564 LS->startDefinition();
565
566 for (Decl *D : BufDecl->buffer_decls()) {
567 VarDecl *VD = dyn_cast<VarDecl>(D);
568 if (!VD || VD->getStorageClass() == SC_Static ||
570 continue;
571 const Type *Ty = VD->getType()->getUnqualifiedDesugaredType();
572 if (FieldDecl *FD =
574 // add the field decl to the layout struct
575 LS->addDecl(FD);
576 // update address space of the original decl to hlsl_constant
577 QualType NewTy =
579 VD->setType(NewTy);
580 }
581 }
582 LS->completeDefinition();
583 BufDecl->addLayoutStruct(LS);
584}
585
587 uint32_t ImplicitBindingOrderID) {
588 auto *Attr =
589 HLSLResourceBindingAttr::CreateImplicit(S.getASTContext(), "", "0", {});
590 Attr->setBinding(RT, std::nullopt, 0);
591 Attr->setImplicitBindingOrderID(ImplicitBindingOrderID);
592 D->addAttr(Attr);
593}
594
595// Handle end of cbuffer/tbuffer declaration
597 auto *BufDecl = cast<HLSLBufferDecl>(Dcl);
598 BufDecl->setRBraceLoc(RBrace);
599
600 validatePackoffset(SemaRef, BufDecl);
601
603
604 // Handle implicit binding if needed.
605 ResourceBindingAttrs ResourceAttrs(Dcl);
606 if (!ResourceAttrs.isExplicit()) {
607 SemaRef.Diag(Dcl->getLocation(), diag::warn_hlsl_implicit_binding);
608 // Use HLSLResourceBindingAttr to transfer implicit binding order_ID
609 // to codegen. If it does not exist, create an implicit attribute.
610 uint32_t OrderID = getNextImplicitBindingOrderID();
611 if (ResourceAttrs.hasBinding())
612 ResourceAttrs.setImplicitOrderID(OrderID);
613 else
615 BufDecl->isCBuffer() ? RegisterType::CBuffer
616 : RegisterType::SRV,
617 OrderID);
618 }
619
620 SemaRef.PopDeclContext();
621}
622
623HLSLNumThreadsAttr *SemaHLSL::mergeNumThreadsAttr(Decl *D,
624 const AttributeCommonInfo &AL,
625 int X, int Y, int Z) {
626 if (HLSLNumThreadsAttr *NT = D->getAttr<HLSLNumThreadsAttr>()) {
627 if (NT->getX() != X || NT->getY() != Y || NT->getZ() != Z) {
628 Diag(NT->getLocation(), diag::err_hlsl_attribute_param_mismatch) << AL;
629 Diag(AL.getLoc(), diag::note_conflicting_attribute);
630 }
631 return nullptr;
632 }
633 return ::new (getASTContext())
634 HLSLNumThreadsAttr(getASTContext(), AL, X, Y, Z);
635}
636
638 const AttributeCommonInfo &AL,
639 int Min, int Max, int Preferred,
640 int SpelledArgsCount) {
641 if (HLSLWaveSizeAttr *WS = D->getAttr<HLSLWaveSizeAttr>()) {
642 if (WS->getMin() != Min || WS->getMax() != Max ||
643 WS->getPreferred() != Preferred ||
644 WS->getSpelledArgsCount() != SpelledArgsCount) {
645 Diag(WS->getLocation(), diag::err_hlsl_attribute_param_mismatch) << AL;
646 Diag(AL.getLoc(), diag::note_conflicting_attribute);
647 }
648 return nullptr;
649 }
650 HLSLWaveSizeAttr *Result = ::new (getASTContext())
651 HLSLWaveSizeAttr(getASTContext(), AL, Min, Max, Preferred);
652 Result->setSpelledArgsCount(SpelledArgsCount);
653 return Result;
654}
655
656HLSLVkConstantIdAttr *
658 int Id) {
659
661 if (TargetInfo.getTriple().getArch() != llvm::Triple::spirv) {
662 Diag(AL.getLoc(), diag::warn_attribute_ignored) << AL;
663 return nullptr;
664 }
665
666 auto *VD = cast<VarDecl>(D);
667
668 if (getSpecConstBuiltinId(VD->getType()->getUnqualifiedDesugaredType()) ==
670 Diag(VD->getLocation(), diag::err_specialization_const);
671 return nullptr;
672 }
673
674 if (!VD->getType().isConstQualified()) {
675 Diag(VD->getLocation(), diag::err_specialization_const);
676 return nullptr;
677 }
678
679 if (HLSLVkConstantIdAttr *CI = D->getAttr<HLSLVkConstantIdAttr>()) {
680 if (CI->getId() != Id) {
681 Diag(CI->getLocation(), diag::err_hlsl_attribute_param_mismatch) << AL;
682 Diag(AL.getLoc(), diag::note_conflicting_attribute);
683 }
684 return nullptr;
685 }
686
687 HLSLVkConstantIdAttr *Result =
688 ::new (getASTContext()) HLSLVkConstantIdAttr(getASTContext(), AL, Id);
689 return Result;
690}
691
692HLSLShaderAttr *
694 llvm::Triple::EnvironmentType ShaderType) {
695 if (HLSLShaderAttr *NT = D->getAttr<HLSLShaderAttr>()) {
696 if (NT->getType() != ShaderType) {
697 Diag(NT->getLocation(), diag::err_hlsl_attribute_param_mismatch) << AL;
698 Diag(AL.getLoc(), diag::note_conflicting_attribute);
699 }
700 return nullptr;
701 }
702 return HLSLShaderAttr::Create(getASTContext(), ShaderType, AL);
703}
704
705HLSLParamModifierAttr *
707 HLSLParamModifierAttr::Spelling Spelling) {
708 // We can only merge an `in` attribute with an `out` attribute. All other
709 // combinations of duplicated attributes are ill-formed.
710 if (HLSLParamModifierAttr *PA = D->getAttr<HLSLParamModifierAttr>()) {
711 if ((PA->isIn() && Spelling == HLSLParamModifierAttr::Keyword_out) ||
712 (PA->isOut() && Spelling == HLSLParamModifierAttr::Keyword_in)) {
713 D->dropAttr<HLSLParamModifierAttr>();
714 SourceRange AdjustedRange = {PA->getLocation(), AL.getRange().getEnd()};
715 return HLSLParamModifierAttr::Create(
716 getASTContext(), /*MergedSpelling=*/true, AdjustedRange,
717 HLSLParamModifierAttr::Keyword_inout);
718 }
719 Diag(AL.getLoc(), diag::err_hlsl_duplicate_parameter_modifier) << AL;
720 Diag(PA->getLocation(), diag::note_conflicting_attribute);
721 return nullptr;
722 }
723 return HLSLParamModifierAttr::Create(getASTContext(), AL);
724}
725
728
730 return;
731
732 // If we have specified a root signature to override the entry function then
733 // attach it now
734 HLSLRootSignatureDecl *SignatureDecl =
736 if (SignatureDecl) {
737 FD->dropAttr<RootSignatureAttr>();
738 // We could look up the SourceRange of the macro here as well
739 AttributeCommonInfo AL(RootSigOverrideIdent, AttributeScopeInfo(),
740 SourceRange(), ParsedAttr::Form::Microsoft());
741 FD->addAttr(::new (getASTContext()) RootSignatureAttr(
742 getASTContext(), AL, RootSigOverrideIdent, SignatureDecl));
743 }
744
745 llvm::Triple::EnvironmentType Env = TargetInfo.getTriple().getEnvironment();
746 if (HLSLShaderAttr::isValidShaderType(Env) && Env != llvm::Triple::Library) {
747 if (const auto *Shader = FD->getAttr<HLSLShaderAttr>()) {
748 // The entry point is already annotated - check that it matches the
749 // triple.
750 if (Shader->getType() != Env) {
751 Diag(Shader->getLocation(), diag::err_hlsl_entry_shader_attr_mismatch)
752 << Shader;
753 FD->setInvalidDecl();
754 }
755 } else {
756 // Implicitly add the shader attribute if the entry function isn't
757 // explicitly annotated.
758 FD->addAttr(HLSLShaderAttr::CreateImplicit(getASTContext(), Env,
759 FD->getBeginLoc()));
760 }
761 } else {
762 switch (Env) {
763 case llvm::Triple::UnknownEnvironment:
764 case llvm::Triple::Library:
765 break;
766 case llvm::Triple::RootSignature:
767 llvm_unreachable("rootsig environment has no functions");
768 default:
769 llvm_unreachable("Unhandled environment in triple");
770 }
771 }
772}
773
774HLSLSemanticAttr *SemaHLSL::createSemantic(const SemanticInfo &Info,
775 DeclaratorDecl *TargetDecl) {
776 std::string SemanticName = Info.Semantic->getAttrName()->getName().upper();
777
778 if (SemanticName == "SV_DISPATCHTHREADID") {
780 *Info.Semantic, TargetDecl, Info.Index);
781 } else if (SemanticName == "SV_GROUPINDEX") {
782 return createSemanticAttr<HLSLSV_GroupIndexAttr>(*Info.Semantic, TargetDecl,
783 Info.Index);
784 } else if (SemanticName == "SV_GROUPTHREADID") {
786 TargetDecl, Info.Index);
787 } else if (SemanticName == "SV_GROUPID") {
788 return createSemanticAttr<HLSLSV_GroupIDAttr>(*Info.Semantic, TargetDecl,
789 Info.Index);
790 } else if (SemanticName == "SV_POSITION") {
791 return createSemanticAttr<HLSLSV_PositionAttr>(*Info.Semantic, TargetDecl,
792 Info.Index);
793 } else
794 Diag(Info.Semantic->getLoc(), diag::err_hlsl_unknown_semantic)
795 << *Info.Semantic;
796
797 return nullptr;
798}
799
800bool SemaHLSL::determineActiveSemanticOnScalar(FunctionDecl *FD,
802 SemanticInfo &ActiveSemantic) {
803 if (ActiveSemantic.Semantic == nullptr) {
804 ActiveSemantic.Semantic = D->getAttr<HLSLSemanticAttr>();
805 if (ActiveSemantic.Semantic &&
806 ActiveSemantic.Semantic->isSemanticIndexExplicit())
807 ActiveSemantic.Index = ActiveSemantic.Semantic->getSemanticIndex();
808 }
809
810 if (!ActiveSemantic.Semantic) {
811 Diag(D->getLocation(), diag::err_hlsl_missing_semantic_annotation);
812 return false;
813 }
814
815 auto *A = createSemantic(ActiveSemantic, D);
816 if (!A)
817 return false;
818
819 checkSemanticAnnotation(FD, D, A);
820 FD->addAttr(A);
821 return true;
822}
823
824bool SemaHLSL::determineActiveSemantic(FunctionDecl *FD, DeclaratorDecl *D,
825 SemanticInfo &ActiveSemantic) {
826 if (ActiveSemantic.Semantic == nullptr) {
827 ActiveSemantic.Semantic = D->getAttr<HLSLSemanticAttr>();
828 if (ActiveSemantic.Semantic &&
829 ActiveSemantic.Semantic->isSemanticIndexExplicit())
830 ActiveSemantic.Index = ActiveSemantic.Semantic->getSemanticIndex();
831 }
832
833 const Type *T = D->getType()->getUnqualifiedDesugaredType();
834 const RecordType *RT = dyn_cast<RecordType>(T);
835 if (!RT)
836 return determineActiveSemanticOnScalar(FD, D, ActiveSemantic);
837
838 const RecordDecl *RD = RT->getDecl();
839 for (FieldDecl *Field : RD->fields()) {
840 SemanticInfo Info = ActiveSemantic;
841 if (!determineActiveSemantic(FD, Field, Info)) {
842 Diag(Field->getLocation(), diag::note_hlsl_semantic_used_here) << Field;
843 return false;
844 }
845 if (ActiveSemantic.Semantic)
846 ActiveSemantic = Info;
847 }
848
849 return true;
850}
851
853 const auto *ShaderAttr = FD->getAttr<HLSLShaderAttr>();
854 assert(ShaderAttr && "Entry point has no shader attribute");
855 llvm::Triple::EnvironmentType ST = ShaderAttr->getType();
857 VersionTuple Ver = TargetInfo.getTriple().getOSVersion();
858 switch (ST) {
859 case llvm::Triple::Pixel:
860 case llvm::Triple::Vertex:
861 case llvm::Triple::Geometry:
862 case llvm::Triple::Hull:
863 case llvm::Triple::Domain:
864 case llvm::Triple::RayGeneration:
865 case llvm::Triple::Intersection:
866 case llvm::Triple::AnyHit:
867 case llvm::Triple::ClosestHit:
868 case llvm::Triple::Miss:
869 case llvm::Triple::Callable:
870 if (const auto *NT = FD->getAttr<HLSLNumThreadsAttr>()) {
872 {llvm::Triple::Compute,
873 llvm::Triple::Amplification,
874 llvm::Triple::Mesh});
875 FD->setInvalidDecl();
876 }
877 if (const auto *WS = FD->getAttr<HLSLWaveSizeAttr>()) {
879 {llvm::Triple::Compute,
880 llvm::Triple::Amplification,
881 llvm::Triple::Mesh});
882 FD->setInvalidDecl();
883 }
884 break;
885
886 case llvm::Triple::Compute:
887 case llvm::Triple::Amplification:
888 case llvm::Triple::Mesh:
889 if (!FD->hasAttr<HLSLNumThreadsAttr>()) {
890 Diag(FD->getLocation(), diag::err_hlsl_missing_numthreads)
891 << llvm::Triple::getEnvironmentTypeName(ST);
892 FD->setInvalidDecl();
893 }
894 if (const auto *WS = FD->getAttr<HLSLWaveSizeAttr>()) {
895 if (Ver < VersionTuple(6, 6)) {
896 Diag(WS->getLocation(), diag::err_hlsl_attribute_in_wrong_shader_model)
897 << WS << "6.6";
898 FD->setInvalidDecl();
899 } else if (WS->getSpelledArgsCount() > 1 && Ver < VersionTuple(6, 8)) {
900 Diag(
901 WS->getLocation(),
902 diag::err_hlsl_attribute_number_arguments_insufficient_shader_model)
903 << WS << WS->getSpelledArgsCount() << "6.8";
904 FD->setInvalidDecl();
905 }
906 }
907 break;
908 case llvm::Triple::RootSignature:
909 llvm_unreachable("rootsig environment has no function entry point");
910 default:
911 llvm_unreachable("Unhandled environment in triple");
912 }
913
914 for (ParmVarDecl *Param : FD->parameters()) {
915 SemanticInfo ActiveSemantic;
916 ActiveSemantic.Semantic = nullptr;
917 ActiveSemantic.Index = std::nullopt;
918
919 if (!determineActiveSemantic(FD, Param, ActiveSemantic)) {
920 Diag(Param->getLocation(), diag::note_previous_decl) << Param;
921 FD->setInvalidDecl();
922 }
923 }
924 // FIXME: Verify return type semantic annotation.
925}
926
927void SemaHLSL::checkSemanticAnnotation(FunctionDecl *EntryPoint,
928 const Decl *Param,
929 const HLSLSemanticAttr *SemanticAttr) {
930 auto *ShaderAttr = EntryPoint->getAttr<HLSLShaderAttr>();
931 assert(ShaderAttr && "Entry point has no shader attribute");
932 llvm::Triple::EnvironmentType ST = ShaderAttr->getType();
933
934 switch (SemanticAttr->getKind()) {
935 case attr::HLSLSV_DispatchThreadID:
936 case attr::HLSLSV_GroupIndex:
937 case attr::HLSLSV_GroupThreadID:
938 case attr::HLSLSV_GroupID:
939 if (ST == llvm::Triple::Compute)
940 return;
941 DiagnoseAttrStageMismatch(SemanticAttr, ST, {llvm::Triple::Compute});
942 break;
943 case attr::HLSLSV_Position:
944 // TODO(#143523): allow use on other shader types & output once the overall
945 // semantic logic is implemented.
946 if (ST == llvm::Triple::Pixel)
947 return;
948 DiagnoseAttrStageMismatch(SemanticAttr, ST, {llvm::Triple::Pixel});
949 break;
950 default:
951 llvm_unreachable("Unknown SemanticAttr");
952 }
953}
954
956 const Attr *A, llvm::Triple::EnvironmentType Stage,
957 std::initializer_list<llvm::Triple::EnvironmentType> AllowedStages) {
958 SmallVector<StringRef, 8> StageStrings;
959 llvm::transform(AllowedStages, std::back_inserter(StageStrings),
960 [](llvm::Triple::EnvironmentType ST) {
961 return StringRef(
962 HLSLShaderAttr::ConvertEnvironmentTypeToStr(ST));
963 });
964 Diag(A->getLoc(), diag::err_hlsl_attr_unsupported_in_stage)
965 << A->getAttrName() << llvm::Triple::getEnvironmentTypeName(Stage)
966 << (AllowedStages.size() != 1) << join(StageStrings, ", ");
967}
968
969template <CastKind Kind>
970static void castVector(Sema &S, ExprResult &E, QualType &Ty, unsigned Sz) {
971 if (const auto *VTy = Ty->getAs<VectorType>())
972 Ty = VTy->getElementType();
973 Ty = S.getASTContext().getExtVectorType(Ty, Sz);
974 E = S.ImpCastExprToType(E.get(), Ty, Kind);
975}
976
977template <CastKind Kind>
979 E = S.ImpCastExprToType(E.get(), Ty, Kind);
980 return Ty;
981}
982
984 Sema &SemaRef, ExprResult &LHS, ExprResult &RHS, QualType LHSType,
985 QualType RHSType, QualType LElTy, QualType RElTy, bool IsCompAssign) {
986 bool LHSFloat = LElTy->isRealFloatingType();
987 bool RHSFloat = RElTy->isRealFloatingType();
988
989 if (LHSFloat && RHSFloat) {
990 if (IsCompAssign ||
991 SemaRef.getASTContext().getFloatingTypeOrder(LElTy, RElTy) > 0)
992 return castElement<CK_FloatingCast>(SemaRef, RHS, LHSType);
993
994 return castElement<CK_FloatingCast>(SemaRef, LHS, RHSType);
995 }
996
997 if (LHSFloat)
998 return castElement<CK_IntegralToFloating>(SemaRef, RHS, LHSType);
999
1000 assert(RHSFloat);
1001 if (IsCompAssign)
1002 return castElement<clang::CK_FloatingToIntegral>(SemaRef, RHS, LHSType);
1003
1004 return castElement<CK_IntegralToFloating>(SemaRef, LHS, RHSType);
1005}
1006
1008 Sema &SemaRef, ExprResult &LHS, ExprResult &RHS, QualType LHSType,
1009 QualType RHSType, QualType LElTy, QualType RElTy, bool IsCompAssign) {
1010
1011 int IntOrder = SemaRef.Context.getIntegerTypeOrder(LElTy, RElTy);
1012 bool LHSSigned = LElTy->hasSignedIntegerRepresentation();
1013 bool RHSSigned = RElTy->hasSignedIntegerRepresentation();
1014 auto &Ctx = SemaRef.getASTContext();
1015
1016 // If both types have the same signedness, use the higher ranked type.
1017 if (LHSSigned == RHSSigned) {
1018 if (IsCompAssign || IntOrder >= 0)
1019 return castElement<CK_IntegralCast>(SemaRef, RHS, LHSType);
1020
1021 return castElement<CK_IntegralCast>(SemaRef, LHS, RHSType);
1022 }
1023
1024 // If the unsigned type has greater than or equal rank of the signed type, use
1025 // the unsigned type.
1026 if (IntOrder != (LHSSigned ? 1 : -1)) {
1027 if (IsCompAssign || RHSSigned)
1028 return castElement<CK_IntegralCast>(SemaRef, RHS, LHSType);
1029 return castElement<CK_IntegralCast>(SemaRef, LHS, RHSType);
1030 }
1031
1032 // At this point the signed type has higher rank than the unsigned type, which
1033 // means it will be the same size or bigger. If the signed type is bigger, it
1034 // can represent all the values of the unsigned type, so select it.
1035 if (Ctx.getIntWidth(LElTy) != Ctx.getIntWidth(RElTy)) {
1036 if (IsCompAssign || LHSSigned)
1037 return castElement<CK_IntegralCast>(SemaRef, RHS, LHSType);
1038 return castElement<CK_IntegralCast>(SemaRef, LHS, RHSType);
1039 }
1040
1041 // This is a bit of an odd duck case in HLSL. It shouldn't happen, but can due
1042 // to C/C++ leaking through. The place this happens today is long vs long
1043 // long. When arguments are vector<unsigned long, N> and vector<long long, N>,
1044 // the long long has higher rank than long even though they are the same size.
1045
1046 // If this is a compound assignment cast the right hand side to the left hand
1047 // side's type.
1048 if (IsCompAssign)
1049 return castElement<CK_IntegralCast>(SemaRef, RHS, LHSType);
1050
1051 // If this isn't a compound assignment we convert to unsigned long long.
1052 QualType ElTy = Ctx.getCorrespondingUnsignedType(LHSSigned ? LElTy : RElTy);
1053 QualType NewTy = Ctx.getExtVectorType(
1054 ElTy, RHSType->castAs<VectorType>()->getNumElements());
1055 (void)castElement<CK_IntegralCast>(SemaRef, RHS, NewTy);
1056
1057 return castElement<CK_IntegralCast>(SemaRef, LHS, NewTy);
1058}
1059
1061 QualType SrcTy) {
1062 if (DestTy->isRealFloatingType() && SrcTy->isRealFloatingType())
1063 return CK_FloatingCast;
1064 if (DestTy->isIntegralType(Ctx) && SrcTy->isIntegralType(Ctx))
1065 return CK_IntegralCast;
1066 if (DestTy->isRealFloatingType())
1067 return CK_IntegralToFloating;
1068 assert(SrcTy->isRealFloatingType() && DestTy->isIntegralType(Ctx));
1069 return CK_FloatingToIntegral;
1070}
1071
1073 QualType LHSType,
1074 QualType RHSType,
1075 bool IsCompAssign) {
1076 const auto *LVecTy = LHSType->getAs<VectorType>();
1077 const auto *RVecTy = RHSType->getAs<VectorType>();
1078 auto &Ctx = getASTContext();
1079
1080 // If the LHS is not a vector and this is a compound assignment, we truncate
1081 // the argument to a scalar then convert it to the LHS's type.
1082 if (!LVecTy && IsCompAssign) {
1083 QualType RElTy = RHSType->castAs<VectorType>()->getElementType();
1084 RHS = SemaRef.ImpCastExprToType(RHS.get(), RElTy, CK_HLSLVectorTruncation);
1085 RHSType = RHS.get()->getType();
1086 if (Ctx.hasSameUnqualifiedType(LHSType, RHSType))
1087 return LHSType;
1088 RHS = SemaRef.ImpCastExprToType(RHS.get(), LHSType,
1089 getScalarCastKind(Ctx, LHSType, RHSType));
1090 return LHSType;
1091 }
1092
1093 unsigned EndSz = std::numeric_limits<unsigned>::max();
1094 unsigned LSz = 0;
1095 if (LVecTy)
1096 LSz = EndSz = LVecTy->getNumElements();
1097 if (RVecTy)
1098 EndSz = std::min(RVecTy->getNumElements(), EndSz);
1099 assert(EndSz != std::numeric_limits<unsigned>::max() &&
1100 "one of the above should have had a value");
1101
1102 // In a compound assignment, the left operand does not change type, the right
1103 // operand is converted to the type of the left operand.
1104 if (IsCompAssign && LSz != EndSz) {
1105 Diag(LHS.get()->getBeginLoc(),
1106 diag::err_hlsl_vector_compound_assignment_truncation)
1107 << LHSType << RHSType;
1108 return QualType();
1109 }
1110
1111 if (RVecTy && RVecTy->getNumElements() > EndSz)
1112 castVector<CK_HLSLVectorTruncation>(SemaRef, RHS, RHSType, EndSz);
1113 if (!IsCompAssign && LVecTy && LVecTy->getNumElements() > EndSz)
1114 castVector<CK_HLSLVectorTruncation>(SemaRef, LHS, LHSType, EndSz);
1115
1116 if (!RVecTy)
1117 castVector<CK_VectorSplat>(SemaRef, RHS, RHSType, EndSz);
1118 if (!IsCompAssign && !LVecTy)
1119 castVector<CK_VectorSplat>(SemaRef, LHS, LHSType, EndSz);
1120
1121 // If we're at the same type after resizing we can stop here.
1122 if (Ctx.hasSameUnqualifiedType(LHSType, RHSType))
1123 return Ctx.getCommonSugaredType(LHSType, RHSType);
1124
1125 QualType LElTy = LHSType->castAs<VectorType>()->getElementType();
1126 QualType RElTy = RHSType->castAs<VectorType>()->getElementType();
1127
1128 // Handle conversion for floating point vectors.
1129 if (LElTy->isRealFloatingType() || RElTy->isRealFloatingType())
1130 return handleFloatVectorBinOpConversion(SemaRef, LHS, RHS, LHSType, RHSType,
1131 LElTy, RElTy, IsCompAssign);
1132
1133 assert(LElTy->isIntegralType(Ctx) && RElTy->isIntegralType(Ctx) &&
1134 "HLSL Vectors can only contain integer or floating point types");
1135 return handleIntegerVectorBinOpConversion(SemaRef, LHS, RHS, LHSType, RHSType,
1136 LElTy, RElTy, IsCompAssign);
1137}
1138
1140 BinaryOperatorKind Opc) {
1141 assert((Opc == BO_LOr || Opc == BO_LAnd) &&
1142 "Called with non-logical operator");
1144 llvm::raw_svector_ostream OS(Buff);
1145 PrintingPolicy PP(SemaRef.getLangOpts());
1146 StringRef NewFnName = Opc == BO_LOr ? "or" : "and";
1147 OS << NewFnName << "(";
1148 LHS->printPretty(OS, nullptr, PP);
1149 OS << ", ";
1150 RHS->printPretty(OS, nullptr, PP);
1151 OS << ")";
1152 SourceRange FullRange = SourceRange(LHS->getBeginLoc(), RHS->getEndLoc());
1153 SemaRef.Diag(LHS->getBeginLoc(), diag::note_function_suggestion)
1154 << NewFnName << FixItHint::CreateReplacement(FullRange, OS.str());
1155}
1156
1157std::pair<IdentifierInfo *, bool>
1159 llvm::hash_code Hash = llvm::hash_value(Signature);
1160 std::string IdStr = "__hlsl_rootsig_decl_" + std::to_string(Hash);
1161 IdentifierInfo *DeclIdent = &(getASTContext().Idents.get(IdStr));
1162
1163 // Check if we have already found a decl of the same name.
1164 LookupResult R(SemaRef, DeclIdent, SourceLocation(),
1166 bool Found = SemaRef.LookupQualifiedName(R, SemaRef.CurContext);
1167 return {DeclIdent, Found};
1168}
1169
1171 SourceLocation Loc, IdentifierInfo *DeclIdent,
1173
1174 if (handleRootSignatureElements(RootElements))
1175 return;
1176
1178 for (auto &RootSigElement : RootElements)
1179 Elements.push_back(RootSigElement.getElement());
1180
1181 auto *SignatureDecl = HLSLRootSignatureDecl::Create(
1182 SemaRef.getASTContext(), /*DeclContext=*/SemaRef.CurContext, Loc,
1183 DeclIdent, SemaRef.getLangOpts().HLSLRootSigVer, Elements);
1184
1185 SignatureDecl->setImplicit();
1186 SemaRef.PushOnScopeChains(SignatureDecl, SemaRef.getCurScope());
1187}
1188
1191 if (RootSigOverrideIdent) {
1192 LookupResult R(SemaRef, RootSigOverrideIdent, SourceLocation(),
1194 if (SemaRef.LookupQualifiedName(R, DC))
1195 return dyn_cast<HLSLRootSignatureDecl>(R.getFoundDecl());
1196 }
1197
1198 return nullptr;
1199}
1200
1201namespace {
1202
1203struct PerVisibilityBindingChecker {
1204 SemaHLSL *S;
1205 // We need one builder per `llvm::dxbc::ShaderVisibility` value.
1206 std::array<llvm::hlsl::BindingInfoBuilder, 8> Builders;
1207
1208 struct ElemInfo {
1209 const hlsl::RootSignatureElement *Elem;
1210 llvm::dxbc::ShaderVisibility Vis;
1211 bool Diagnosed;
1212 };
1213 llvm::SmallVector<ElemInfo> ElemInfoMap;
1214
1215 PerVisibilityBindingChecker(SemaHLSL *S) : S(S) {}
1216
1217 void trackBinding(llvm::dxbc::ShaderVisibility Visibility,
1218 llvm::dxil::ResourceClass RC, uint32_t Space,
1219 uint32_t LowerBound, uint32_t UpperBound,
1220 const hlsl::RootSignatureElement *Elem) {
1221 uint32_t BuilderIndex = llvm::to_underlying(Visibility);
1222 assert(BuilderIndex < Builders.size() &&
1223 "Not enough builders for visibility type");
1224 Builders[BuilderIndex].trackBinding(RC, Space, LowerBound, UpperBound,
1225 static_cast<const void *>(Elem));
1226
1227 static_assert(llvm::to_underlying(llvm::dxbc::ShaderVisibility::All) == 0,
1228 "'All' visibility must come first");
1229 if (Visibility == llvm::dxbc::ShaderVisibility::All)
1230 for (size_t I = 1, E = Builders.size(); I < E; ++I)
1231 Builders[I].trackBinding(RC, Space, LowerBound, UpperBound,
1232 static_cast<const void *>(Elem));
1233
1234 ElemInfoMap.push_back({Elem, Visibility, false});
1235 }
1236
1237 ElemInfo &getInfo(const hlsl::RootSignatureElement *Elem) {
1238 auto It = llvm::lower_bound(
1239 ElemInfoMap, Elem,
1240 [](const auto &LHS, const auto &RHS) { return LHS.Elem < RHS; });
1241 assert(It->Elem == Elem && "Element not in map");
1242 return *It;
1243 }
1244
1245 bool checkOverlap() {
1246 llvm::sort(ElemInfoMap, [](const auto &LHS, const auto &RHS) {
1247 return LHS.Elem < RHS.Elem;
1248 });
1249
1250 bool HadOverlap = false;
1251
1252 using llvm::hlsl::BindingInfoBuilder;
1253 auto ReportOverlap = [this,
1254 &HadOverlap](const BindingInfoBuilder &Builder,
1255 const llvm::hlsl::Binding &Reported) {
1256 HadOverlap = true;
1257
1258 const auto *Elem =
1259 static_cast<const hlsl::RootSignatureElement *>(Reported.Cookie);
1260 const llvm::hlsl::Binding &Previous = Builder.findOverlapping(Reported);
1261 const auto *PrevElem =
1262 static_cast<const hlsl::RootSignatureElement *>(Previous.Cookie);
1263
1264 ElemInfo &Info = getInfo(Elem);
1265 // We will have already diagnosed this binding if there's overlap in the
1266 // "All" visibility as well as any particular visibility.
1267 if (Info.Diagnosed)
1268 return;
1269 Info.Diagnosed = true;
1270
1271 ElemInfo &PrevInfo = getInfo(PrevElem);
1272 llvm::dxbc::ShaderVisibility CommonVis =
1273 Info.Vis == llvm::dxbc::ShaderVisibility::All ? PrevInfo.Vis
1274 : Info.Vis;
1275
1276 this->S->Diag(Elem->getLocation(), diag::err_hlsl_resource_range_overlap)
1277 << llvm::to_underlying(Reported.RC) << Reported.LowerBound
1278 << Reported.isUnbounded() << Reported.UpperBound
1279 << llvm::to_underlying(Previous.RC) << Previous.LowerBound
1280 << Previous.isUnbounded() << Previous.UpperBound << Reported.Space
1281 << CommonVis;
1282
1283 this->S->Diag(PrevElem->getLocation(),
1284 diag::note_hlsl_resource_range_here);
1285 };
1286
1287 for (BindingInfoBuilder &Builder : Builders)
1288 Builder.calculateBindingInfo(ReportOverlap);
1289
1290 return HadOverlap;
1291 }
1292};
1293
1294static CXXMethodDecl *lookupMethod(Sema &S, CXXRecordDecl *RecordDecl,
1295 StringRef Name, SourceLocation Loc) {
1296 DeclarationName DeclName(&S.getASTContext().Idents.get(Name));
1297 LookupResult Result(S, DeclName, Loc, Sema::LookupMemberName);
1298 if (!S.LookupQualifiedName(Result, static_cast<DeclContext *>(RecordDecl)))
1299 return nullptr;
1300 return cast<CXXMethodDecl>(Result.getFoundDecl());
1301}
1302
1303} // end anonymous namespace
1304
1305static bool hasCounterHandle(const CXXRecordDecl *RD) {
1306 if (RD->field_empty())
1307 return false;
1308 auto It = std::next(RD->field_begin());
1309 if (It == RD->field_end())
1310 return false;
1311 const FieldDecl *SecondField = *It;
1312 if (const auto *ResTy =
1313 SecondField->getType()->getAs<HLSLAttributedResourceType>()) {
1314 return ResTy->getAttrs().IsCounter;
1315 }
1316 return false;
1317}
1318
1321 // Define some common error handling functions
1322 bool HadError = false;
1323 auto ReportError = [this, &HadError](SourceLocation Loc, uint32_t LowerBound,
1324 uint32_t UpperBound) {
1325 HadError = true;
1326 this->Diag(Loc, diag::err_hlsl_invalid_rootsig_value)
1327 << LowerBound << UpperBound;
1328 };
1329
1330 auto ReportFloatError = [this, &HadError](SourceLocation Loc,
1331 float LowerBound,
1332 float UpperBound) {
1333 HadError = true;
1334 this->Diag(Loc, diag::err_hlsl_invalid_rootsig_value)
1335 << llvm::formatv("{0:f}", LowerBound).sstr<6>()
1336 << llvm::formatv("{0:f}", UpperBound).sstr<6>();
1337 };
1338
1339 auto VerifyRegister = [ReportError](SourceLocation Loc, uint32_t Register) {
1340 if (!llvm::hlsl::rootsig::verifyRegisterValue(Register))
1341 ReportError(Loc, 0, 0xfffffffe);
1342 };
1343
1344 auto VerifySpace = [ReportError](SourceLocation Loc, uint32_t Space) {
1345 if (!llvm::hlsl::rootsig::verifyRegisterSpace(Space))
1346 ReportError(Loc, 0, 0xffffffef);
1347 };
1348
1349 const uint32_t Version =
1350 llvm::to_underlying(SemaRef.getLangOpts().HLSLRootSigVer);
1351 const uint32_t VersionEnum = Version - 1;
1352 auto ReportFlagError = [this, &HadError, VersionEnum](SourceLocation Loc) {
1353 HadError = true;
1354 this->Diag(Loc, diag::err_hlsl_invalid_rootsig_flag)
1355 << /*version minor*/ VersionEnum;
1356 };
1357
1358 // Iterate through the elements and do basic validations
1359 for (const hlsl::RootSignatureElement &RootSigElem : Elements) {
1360 SourceLocation Loc = RootSigElem.getLocation();
1361 const llvm::hlsl::rootsig::RootElement &Elem = RootSigElem.getElement();
1362 if (const auto *Descriptor =
1363 std::get_if<llvm::hlsl::rootsig::RootDescriptor>(&Elem)) {
1364 VerifyRegister(Loc, Descriptor->Reg.Number);
1365 VerifySpace(Loc, Descriptor->Space);
1366
1367 if (!llvm::hlsl::rootsig::verifyRootDescriptorFlag(Version,
1368 Descriptor->Flags))
1369 ReportFlagError(Loc);
1370 } else if (const auto *Constants =
1371 std::get_if<llvm::hlsl::rootsig::RootConstants>(&Elem)) {
1372 VerifyRegister(Loc, Constants->Reg.Number);
1373 VerifySpace(Loc, Constants->Space);
1374 } else if (const auto *Sampler =
1375 std::get_if<llvm::hlsl::rootsig::StaticSampler>(&Elem)) {
1376 VerifyRegister(Loc, Sampler->Reg.Number);
1377 VerifySpace(Loc, Sampler->Space);
1378
1379 assert(!std::isnan(Sampler->MaxLOD) && !std::isnan(Sampler->MinLOD) &&
1380 "By construction, parseFloatParam can't produce a NaN from a "
1381 "float_literal token");
1382
1383 if (!llvm::hlsl::rootsig::verifyMaxAnisotropy(Sampler->MaxAnisotropy))
1384 ReportError(Loc, 0, 16);
1385 if (!llvm::hlsl::rootsig::verifyMipLODBias(Sampler->MipLODBias))
1386 ReportFloatError(Loc, -16.f, 15.99f);
1387 } else if (const auto *Clause =
1388 std::get_if<llvm::hlsl::rootsig::DescriptorTableClause>(
1389 &Elem)) {
1390 VerifyRegister(Loc, Clause->Reg.Number);
1391 VerifySpace(Loc, Clause->Space);
1392
1393 if (!llvm::hlsl::rootsig::verifyNumDescriptors(Clause->NumDescriptors)) {
1394 // NumDescriptor could techincally be ~0u but that is reserved for
1395 // unbounded, so the diagnostic will not report that as a valid int
1396 // value
1397 ReportError(Loc, 1, 0xfffffffe);
1398 }
1399
1400 if (!llvm::hlsl::rootsig::verifyDescriptorRangeFlag(Version, Clause->Type,
1401 Clause->Flags))
1402 ReportFlagError(Loc);
1403 }
1404 }
1405
1406 PerVisibilityBindingChecker BindingChecker(this);
1407 SmallVector<std::pair<const llvm::hlsl::rootsig::DescriptorTableClause *,
1409 UnboundClauses;
1410
1411 for (const hlsl::RootSignatureElement &RootSigElem : Elements) {
1412 const llvm::hlsl::rootsig::RootElement &Elem = RootSigElem.getElement();
1413 if (const auto *Descriptor =
1414 std::get_if<llvm::hlsl::rootsig::RootDescriptor>(&Elem)) {
1415 uint32_t LowerBound(Descriptor->Reg.Number);
1416 uint32_t UpperBound(LowerBound); // inclusive range
1417
1418 BindingChecker.trackBinding(
1419 Descriptor->Visibility,
1420 static_cast<llvm::dxil::ResourceClass>(Descriptor->Type),
1421 Descriptor->Space, LowerBound, UpperBound, &RootSigElem);
1422 } else if (const auto *Constants =
1423 std::get_if<llvm::hlsl::rootsig::RootConstants>(&Elem)) {
1424 uint32_t LowerBound(Constants->Reg.Number);
1425 uint32_t UpperBound(LowerBound); // inclusive range
1426
1427 BindingChecker.trackBinding(
1428 Constants->Visibility, llvm::dxil::ResourceClass::CBuffer,
1429 Constants->Space, LowerBound, UpperBound, &RootSigElem);
1430 } else if (const auto *Sampler =
1431 std::get_if<llvm::hlsl::rootsig::StaticSampler>(&Elem)) {
1432 uint32_t LowerBound(Sampler->Reg.Number);
1433 uint32_t UpperBound(LowerBound); // inclusive range
1434
1435 BindingChecker.trackBinding(
1436 Sampler->Visibility, llvm::dxil::ResourceClass::Sampler,
1437 Sampler->Space, LowerBound, UpperBound, &RootSigElem);
1438 } else if (const auto *Clause =
1439 std::get_if<llvm::hlsl::rootsig::DescriptorTableClause>(
1440 &Elem)) {
1441 // We'll process these once we see the table element.
1442 UnboundClauses.emplace_back(Clause, &RootSigElem);
1443 } else if (const auto *Table =
1444 std::get_if<llvm::hlsl::rootsig::DescriptorTable>(&Elem)) {
1445 assert(UnboundClauses.size() == Table->NumClauses &&
1446 "Number of unbound elements must match the number of clauses");
1447 bool HasAnySampler = false;
1448 bool HasAnyNonSampler = false;
1449 uint64_t Offset = 0;
1450 bool IsPrevUnbound = false;
1451 for (const auto &[Clause, ClauseElem] : UnboundClauses) {
1452 SourceLocation Loc = ClauseElem->getLocation();
1453 if (Clause->Type == llvm::dxil::ResourceClass::Sampler)
1454 HasAnySampler = true;
1455 else
1456 HasAnyNonSampler = true;
1457
1458 if (HasAnySampler && HasAnyNonSampler)
1459 Diag(Loc, diag::err_hlsl_invalid_mixed_resources);
1460
1461 // Relevant error will have already been reported above and needs to be
1462 // fixed before we can conduct further analysis, so shortcut error
1463 // return
1464 if (Clause->NumDescriptors == 0)
1465 return true;
1466
1467 bool IsAppending =
1468 Clause->Offset == llvm::hlsl::rootsig::DescriptorTableOffsetAppend;
1469 if (!IsAppending)
1470 Offset = Clause->Offset;
1471
1472 uint64_t RangeBound = llvm::hlsl::rootsig::computeRangeBound(
1473 Offset, Clause->NumDescriptors);
1474
1475 if (IsPrevUnbound && IsAppending)
1476 Diag(Loc, diag::err_hlsl_appending_onto_unbound);
1477 else if (!llvm::hlsl::rootsig::verifyNoOverflowedOffset(RangeBound))
1478 Diag(Loc, diag::err_hlsl_offset_overflow) << Offset << RangeBound;
1479
1480 // Update offset to be 1 past this range's bound
1481 Offset = RangeBound + 1;
1482 IsPrevUnbound = Clause->NumDescriptors ==
1483 llvm::hlsl::rootsig::NumDescriptorsUnbounded;
1484
1485 // Compute the register bounds and track resource binding
1486 uint32_t LowerBound(Clause->Reg.Number);
1487 uint32_t UpperBound = llvm::hlsl::rootsig::computeRangeBound(
1488 LowerBound, Clause->NumDescriptors);
1489
1490 BindingChecker.trackBinding(
1491 Table->Visibility,
1492 static_cast<llvm::dxil::ResourceClass>(Clause->Type), Clause->Space,
1493 LowerBound, UpperBound, ClauseElem);
1494 }
1495 UnboundClauses.clear();
1496 }
1497 }
1498
1499 return BindingChecker.checkOverlap();
1500}
1501
1503 if (AL.getNumArgs() != 1) {
1504 Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1;
1505 return;
1506 }
1507
1509 if (auto *RS = D->getAttr<RootSignatureAttr>()) {
1510 if (RS->getSignatureIdent() != Ident) {
1511 Diag(AL.getLoc(), diag::err_disallowed_duplicate_attribute) << RS;
1512 return;
1513 }
1514
1515 Diag(AL.getLoc(), diag::warn_duplicate_attribute_exact) << RS;
1516 return;
1517 }
1518
1520 if (SemaRef.LookupQualifiedName(R, D->getDeclContext()))
1521 if (auto *SignatureDecl =
1522 dyn_cast<HLSLRootSignatureDecl>(R.getFoundDecl())) {
1523 D->addAttr(::new (getASTContext()) RootSignatureAttr(
1524 getASTContext(), AL, Ident, SignatureDecl));
1525 }
1526}
1527
1529 llvm::VersionTuple SMVersion =
1530 getASTContext().getTargetInfo().getTriple().getOSVersion();
1531 bool IsDXIL = getASTContext().getTargetInfo().getTriple().getArch() ==
1532 llvm::Triple::dxil;
1533
1534 uint32_t ZMax = 1024;
1535 uint32_t ThreadMax = 1024;
1536 if (IsDXIL && SMVersion.getMajor() <= 4) {
1537 ZMax = 1;
1538 ThreadMax = 768;
1539 } else if (IsDXIL && SMVersion.getMajor() == 5) {
1540 ZMax = 64;
1541 ThreadMax = 1024;
1542 }
1543
1544 uint32_t X;
1545 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), X))
1546 return;
1547 if (X > 1024) {
1548 Diag(AL.getArgAsExpr(0)->getExprLoc(),
1549 diag::err_hlsl_numthreads_argument_oor)
1550 << 0 << 1024;
1551 return;
1552 }
1553 uint32_t Y;
1554 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(1), Y))
1555 return;
1556 if (Y > 1024) {
1557 Diag(AL.getArgAsExpr(1)->getExprLoc(),
1558 diag::err_hlsl_numthreads_argument_oor)
1559 << 1 << 1024;
1560 return;
1561 }
1562 uint32_t Z;
1563 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(2), Z))
1564 return;
1565 if (Z > ZMax) {
1566 SemaRef.Diag(AL.getArgAsExpr(2)->getExprLoc(),
1567 diag::err_hlsl_numthreads_argument_oor)
1568 << 2 << ZMax;
1569 return;
1570 }
1571
1572 if (X * Y * Z > ThreadMax) {
1573 Diag(AL.getLoc(), diag::err_hlsl_numthreads_invalid) << ThreadMax;
1574 return;
1575 }
1576
1577 HLSLNumThreadsAttr *NewAttr = mergeNumThreadsAttr(D, AL, X, Y, Z);
1578 if (NewAttr)
1579 D->addAttr(NewAttr);
1580}
1581
1582static bool isValidWaveSizeValue(unsigned Value) {
1583 return llvm::isPowerOf2_32(Value) && Value >= 4 && Value <= 128;
1584}
1585
1587 // validate that the wavesize argument is a power of 2 between 4 and 128
1588 // inclusive
1589 unsigned SpelledArgsCount = AL.getNumArgs();
1590 if (SpelledArgsCount == 0 || SpelledArgsCount > 3)
1591 return;
1592
1593 uint32_t Min;
1594 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), Min))
1595 return;
1596
1597 uint32_t Max = 0;
1598 if (SpelledArgsCount > 1 &&
1599 !SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(1), Max))
1600 return;
1601
1602 uint32_t Preferred = 0;
1603 if (SpelledArgsCount > 2 &&
1604 !SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(2), Preferred))
1605 return;
1606
1607 if (SpelledArgsCount > 2) {
1608 if (!isValidWaveSizeValue(Preferred)) {
1609 Diag(AL.getArgAsExpr(2)->getExprLoc(),
1610 diag::err_attribute_power_of_two_in_range)
1611 << AL << llvm::dxil::MinWaveSize << llvm::dxil::MaxWaveSize
1612 << Preferred;
1613 return;
1614 }
1615 // Preferred not in range.
1616 if (Preferred < Min || Preferred > Max) {
1617 Diag(AL.getArgAsExpr(2)->getExprLoc(),
1618 diag::err_attribute_power_of_two_in_range)
1619 << AL << Min << Max << Preferred;
1620 return;
1621 }
1622 } else if (SpelledArgsCount > 1) {
1623 if (!isValidWaveSizeValue(Max)) {
1624 Diag(AL.getArgAsExpr(1)->getExprLoc(),
1625 diag::err_attribute_power_of_two_in_range)
1626 << AL << llvm::dxil::MinWaveSize << llvm::dxil::MaxWaveSize << Max;
1627 return;
1628 }
1629 if (Max < Min) {
1630 Diag(AL.getLoc(), diag::err_attribute_argument_invalid) << AL << 1;
1631 return;
1632 } else if (Max == Min) {
1633 Diag(AL.getLoc(), diag::warn_attr_min_eq_max) << AL;
1634 }
1635 } else {
1636 if (!isValidWaveSizeValue(Min)) {
1637 Diag(AL.getArgAsExpr(0)->getExprLoc(),
1638 diag::err_attribute_power_of_two_in_range)
1639 << AL << llvm::dxil::MinWaveSize << llvm::dxil::MaxWaveSize << Min;
1640 return;
1641 }
1642 }
1643
1644 HLSLWaveSizeAttr *NewAttr =
1645 mergeWaveSizeAttr(D, AL, Min, Max, Preferred, SpelledArgsCount);
1646 if (NewAttr)
1647 D->addAttr(NewAttr);
1648}
1649
1651 uint32_t ID;
1652 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), ID))
1653 return;
1654 D->addAttr(::new (getASTContext())
1655 HLSLVkExtBuiltinInputAttr(getASTContext(), AL, ID));
1656}
1657
1659 uint32_t Id;
1660 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), Id))
1661 return;
1662 HLSLVkConstantIdAttr *NewAttr = mergeVkConstantIdAttr(D, AL, Id);
1663 if (NewAttr)
1664 D->addAttr(NewAttr);
1665}
1666
1668 uint32_t Binding = 0;
1669 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), Binding))
1670 return;
1671 uint32_t Set = 0;
1672 if (AL.getNumArgs() > 1 &&
1673 !SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(1), Set))
1674 return;
1675
1676 D->addAttr(::new (getASTContext())
1677 HLSLVkBindingAttr(getASTContext(), AL, Binding, Set));
1678}
1679
1681 const auto *VT = T->getAs<VectorType>();
1682
1683 if (!T->hasUnsignedIntegerRepresentation() ||
1684 (VT && VT->getNumElements() > 3)) {
1685 Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type)
1686 << AL << "uint/uint2/uint3";
1687 return false;
1688 }
1689
1690 return true;
1691}
1692
1694 const auto *VT = T->getAs<VectorType>();
1695 if (!T->hasFloatingRepresentation() || (VT && VT->getNumElements() > 4)) {
1696 Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type)
1697 << AL << "float/float1/float2/float3/float4";
1698 return false;
1699 }
1700
1701 return true;
1702}
1703
1705 std::optional<unsigned> Index) {
1706 std::string SemanticName = AL.getAttrName()->getName().upper();
1707
1708 auto *VD = cast<ValueDecl>(D);
1709 QualType ValueType = VD->getType();
1710 if (auto *FD = dyn_cast<FunctionDecl>(D))
1711 ValueType = FD->getReturnType();
1712
1713 bool IsOutput = false;
1714 if (HLSLParamModifierAttr *MA = D->getAttr<HLSLParamModifierAttr>()) {
1715 if (MA->isOut()) {
1716 IsOutput = true;
1717 ValueType = cast<ReferenceType>(ValueType)->getPointeeType();
1718 }
1719 }
1720
1721 Attr *Attribute = nullptr;
1722 if (SemanticName == "SV_DISPATCHTHREADID") {
1723 diagnoseInputIDType(ValueType, AL);
1724 if (IsOutput)
1725 Diag(AL.getLoc(), diag::err_hlsl_semantic_output_not_supported) << AL;
1726 Attribute =
1728 } else if (SemanticName == "SV_GROUPINDEX") {
1729 if (IsOutput)
1730 Diag(AL.getLoc(), diag::err_hlsl_semantic_output_not_supported) << AL;
1731 Attribute = createSemanticAttr<HLSLSV_GroupIndexAttr>(AL, nullptr, Index);
1732 } else if (SemanticName == "SV_GROUPTHREADID") {
1733 diagnoseInputIDType(ValueType, AL);
1734 if (IsOutput)
1735 Diag(AL.getLoc(), diag::err_hlsl_semantic_output_not_supported) << AL;
1736 Attribute =
1738 } else if (SemanticName == "SV_GROUPID") {
1739 diagnoseInputIDType(ValueType, AL);
1740 if (IsOutput)
1741 Diag(AL.getLoc(), diag::err_hlsl_semantic_output_not_supported) << AL;
1742 Attribute = createSemanticAttr<HLSLSV_GroupIDAttr>(AL, nullptr, Index);
1743 } else if (SemanticName == "SV_POSITION") {
1744 const auto *VT = ValueType->getAs<VectorType>();
1745 if (!ValueType->hasFloatingRepresentation() ||
1746 (VT && VT->getNumElements() > 4))
1747 Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type)
1748 << AL << "float/float1/float2/float3/float4";
1749 Attribute = createSemanticAttr<HLSLSV_PositionAttr>(AL, nullptr, Index);
1750 } else
1751 Diag(AL.getLoc(), diag::err_hlsl_unknown_semantic) << AL;
1752
1753 if (!Attribute)
1754 return;
1755 D->addAttr(Attribute);
1756}
1757
1759 uint32_t IndexValue, ExplicitIndex;
1760 SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), IndexValue);
1761 SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(1), ExplicitIndex);
1762 assert(IndexValue > 0 ? ExplicitIndex : true);
1763 std::optional<unsigned> Index =
1764 ExplicitIndex ? std::optional<unsigned>(IndexValue) : std::nullopt;
1765
1766 if (AL.getAttrName()->getName().starts_with_insensitive("SV_"))
1767 diagnoseSystemSemanticAttr(D, AL, Index);
1768 else
1769 Diag(AL.getLoc(), diag::err_hlsl_unknown_semantic) << AL;
1770}
1771
1774 Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_ast_node)
1775 << AL << "shader constant in a constant buffer";
1776 return;
1777 }
1778
1779 uint32_t SubComponent;
1780 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), SubComponent))
1781 return;
1782 uint32_t Component;
1783 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(1), Component))
1784 return;
1785
1786 QualType T = cast<VarDecl>(D)->getType().getCanonicalType();
1787 // Check if T is an array or struct type.
1788 // TODO: mark matrix type as aggregate type.
1789 bool IsAggregateTy = (T->isArrayType() || T->isStructureType());
1790
1791 // Check Component is valid for T.
1792 if (Component) {
1793 unsigned Size = getASTContext().getTypeSize(T);
1794 if (IsAggregateTy || Size > 128) {
1795 Diag(AL.getLoc(), diag::err_hlsl_packoffset_cross_reg_boundary);
1796 return;
1797 } else {
1798 // Make sure Component + sizeof(T) <= 4.
1799 if ((Component * 32 + Size) > 128) {
1800 Diag(AL.getLoc(), diag::err_hlsl_packoffset_cross_reg_boundary);
1801 return;
1802 }
1803 QualType EltTy = T;
1804 if (const auto *VT = T->getAs<VectorType>())
1805 EltTy = VT->getElementType();
1806 unsigned Align = getASTContext().getTypeAlign(EltTy);
1807 if (Align > 32 && Component == 1) {
1808 // NOTE: Component 3 will hit err_hlsl_packoffset_cross_reg_boundary.
1809 // So we only need to check Component 1 here.
1810 Diag(AL.getLoc(), diag::err_hlsl_packoffset_alignment_mismatch)
1811 << Align << EltTy;
1812 return;
1813 }
1814 }
1815 }
1816
1817 D->addAttr(::new (getASTContext()) HLSLPackOffsetAttr(
1818 getASTContext(), AL, SubComponent, Component));
1819}
1820
1822 StringRef Str;
1823 SourceLocation ArgLoc;
1824 if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
1825 return;
1826
1827 llvm::Triple::EnvironmentType ShaderType;
1828 if (!HLSLShaderAttr::ConvertStrToEnvironmentType(Str, ShaderType)) {
1829 Diag(AL.getLoc(), diag::warn_attribute_type_not_supported)
1830 << AL << Str << ArgLoc;
1831 return;
1832 }
1833
1834 // FIXME: check function match the shader stage.
1835
1836 HLSLShaderAttr *NewAttr = mergeShaderAttr(D, AL, ShaderType);
1837 if (NewAttr)
1838 D->addAttr(NewAttr);
1839}
1840
1842 Sema &S, QualType Wrapped, ArrayRef<const Attr *> AttrList,
1843 QualType &ResType, HLSLAttributedResourceLocInfo *LocInfo) {
1844 assert(AttrList.size() && "expected list of resource attributes");
1845
1846 QualType ContainedTy = QualType();
1847 TypeSourceInfo *ContainedTyInfo = nullptr;
1848 SourceLocation LocBegin = AttrList[0]->getRange().getBegin();
1849 SourceLocation LocEnd = AttrList[0]->getRange().getEnd();
1850
1851 HLSLAttributedResourceType::Attributes ResAttrs;
1852
1853 bool HasResourceClass = false;
1854 for (const Attr *A : AttrList) {
1855 if (!A)
1856 continue;
1857 LocEnd = A->getRange().getEnd();
1858 switch (A->getKind()) {
1859 case attr::HLSLResourceClass: {
1860 ResourceClass RC = cast<HLSLResourceClassAttr>(A)->getResourceClass();
1861 if (HasResourceClass) {
1862 S.Diag(A->getLocation(), ResAttrs.ResourceClass == RC
1863 ? diag::warn_duplicate_attribute_exact
1864 : diag::warn_duplicate_attribute)
1865 << A;
1866 return false;
1867 }
1868 ResAttrs.ResourceClass = RC;
1869 HasResourceClass = true;
1870 break;
1871 }
1872 case attr::HLSLROV:
1873 if (ResAttrs.IsROV) {
1874 S.Diag(A->getLocation(), diag::warn_duplicate_attribute_exact) << A;
1875 return false;
1876 }
1877 ResAttrs.IsROV = true;
1878 break;
1879 case attr::HLSLRawBuffer:
1880 if (ResAttrs.RawBuffer) {
1881 S.Diag(A->getLocation(), diag::warn_duplicate_attribute_exact) << A;
1882 return false;
1883 }
1884 ResAttrs.RawBuffer = true;
1885 break;
1886 case attr::HLSLIsCounter:
1887 if (ResAttrs.IsCounter) {
1888 S.Diag(A->getLocation(), diag::warn_duplicate_attribute_exact) << A;
1889 return false;
1890 }
1891 ResAttrs.IsCounter = true;
1892 break;
1893 case attr::HLSLContainedType: {
1894 const HLSLContainedTypeAttr *CTAttr = cast<HLSLContainedTypeAttr>(A);
1895 QualType Ty = CTAttr->getType();
1896 if (!ContainedTy.isNull()) {
1897 S.Diag(A->getLocation(), ContainedTy == Ty
1898 ? diag::warn_duplicate_attribute_exact
1899 : diag::warn_duplicate_attribute)
1900 << A;
1901 return false;
1902 }
1903 ContainedTy = Ty;
1904 ContainedTyInfo = CTAttr->getTypeLoc();
1905 break;
1906 }
1907 default:
1908 llvm_unreachable("unhandled resource attribute type");
1909 }
1910 }
1911
1912 if (!HasResourceClass) {
1913 S.Diag(AttrList.back()->getRange().getEnd(),
1914 diag::err_hlsl_missing_resource_class);
1915 return false;
1916 }
1917
1919 Wrapped, ContainedTy, ResAttrs);
1920
1921 if (LocInfo && ContainedTyInfo) {
1922 LocInfo->Range = SourceRange(LocBegin, LocEnd);
1923 LocInfo->ContainedTyInfo = ContainedTyInfo;
1924 }
1925 return true;
1926}
1927
1928// Validates and creates an HLSL attribute that is applied as type attribute on
1929// HLSL resource. The attributes are collected in HLSLResourcesTypeAttrs and at
1930// the end of the declaration they are applied to the declaration type by
1931// wrapping it in HLSLAttributedResourceType.
1933 // only allow resource type attributes on intangible types
1934 if (!T->isHLSLResourceType()) {
1935 Diag(AL.getLoc(), diag::err_hlsl_attribute_needs_intangible_type)
1936 << AL << getASTContext().HLSLResourceTy;
1937 return false;
1938 }
1939
1940 // validate number of arguments
1941 if (!AL.checkExactlyNumArgs(SemaRef, AL.getMinArgs()))
1942 return false;
1943
1944 Attr *A = nullptr;
1945
1949 {
1950 AttributeCommonInfo::AS_CXX11, 0, false /*IsAlignas*/,
1951 false /*IsRegularKeywordAttribute*/
1952 });
1953
1954 switch (AL.getKind()) {
1955 case ParsedAttr::AT_HLSLResourceClass: {
1956 if (!AL.isArgIdent(0)) {
1957 Diag(AL.getLoc(), diag::err_attribute_argument_type)
1958 << AL << AANT_ArgumentIdentifier;
1959 return false;
1960 }
1961
1962 IdentifierLoc *Loc = AL.getArgAsIdent(0);
1963 StringRef Identifier = Loc->getIdentifierInfo()->getName();
1964 SourceLocation ArgLoc = Loc->getLoc();
1965
1966 // Validate resource class value
1967 ResourceClass RC;
1968 if (!HLSLResourceClassAttr::ConvertStrToResourceClass(Identifier, RC)) {
1969 Diag(ArgLoc, diag::warn_attribute_type_not_supported)
1970 << "ResourceClass" << Identifier;
1971 return false;
1972 }
1973 A = HLSLResourceClassAttr::Create(getASTContext(), RC, ACI);
1974 break;
1975 }
1976
1977 case ParsedAttr::AT_HLSLROV:
1978 A = HLSLROVAttr::Create(getASTContext(), ACI);
1979 break;
1980
1981 case ParsedAttr::AT_HLSLRawBuffer:
1982 A = HLSLRawBufferAttr::Create(getASTContext(), ACI);
1983 break;
1984
1985 case ParsedAttr::AT_HLSLIsCounter:
1986 A = HLSLIsCounterAttr::Create(getASTContext(), ACI);
1987 break;
1988
1989 case ParsedAttr::AT_HLSLContainedType: {
1990 if (AL.getNumArgs() != 1 && !AL.hasParsedType()) {
1991 Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1;
1992 return false;
1993 }
1994
1995 TypeSourceInfo *TSI = nullptr;
1996 QualType QT = SemaRef.GetTypeFromParser(AL.getTypeArg(), &TSI);
1997 assert(TSI && "no type source info for attribute argument");
1998 if (SemaRef.RequireCompleteType(TSI->getTypeLoc().getBeginLoc(), QT,
1999 diag::err_incomplete_type))
2000 return false;
2001 A = HLSLContainedTypeAttr::Create(getASTContext(), TSI, ACI);
2002 break;
2003 }
2004
2005 default:
2006 llvm_unreachable("unhandled HLSL attribute");
2007 }
2008
2009 HLSLResourcesTypeAttrs.emplace_back(A);
2010 return true;
2011}
2012
2013// Combines all resource type attributes and creates HLSLAttributedResourceType.
2015 if (!HLSLResourcesTypeAttrs.size())
2016 return CurrentType;
2017
2018 QualType QT = CurrentType;
2021 HLSLResourcesTypeAttrs, QT, &LocInfo)) {
2022 const HLSLAttributedResourceType *RT =
2024
2025 // Temporarily store TypeLoc information for the new type.
2026 // It will be transferred to HLSLAttributesResourceTypeLoc
2027 // shortly after the type is created by TypeSpecLocFiller which
2028 // will call the TakeLocForHLSLAttribute method below.
2029 LocsForHLSLAttributedResources.insert(std::pair(RT, LocInfo));
2030 }
2031 HLSLResourcesTypeAttrs.clear();
2032 return QT;
2033}
2034
2035// Returns source location for the HLSLAttributedResourceType
2037SemaHLSL::TakeLocForHLSLAttribute(const HLSLAttributedResourceType *RT) {
2038 HLSLAttributedResourceLocInfo LocInfo = {};
2039 auto I = LocsForHLSLAttributedResources.find(RT);
2040 if (I != LocsForHLSLAttributedResources.end()) {
2041 LocInfo = I->second;
2042 LocsForHLSLAttributedResources.erase(I);
2043 return LocInfo;
2044 }
2045 LocInfo.Range = SourceRange();
2046 return LocInfo;
2047}
2048
2049// Walks though the global variable declaration, collects all resource binding
2050// requirements and adds them to Bindings
2051void SemaHLSL::collectResourceBindingsOnUserRecordDecl(const VarDecl *VD,
2052 const RecordType *RT) {
2053 const RecordDecl *RD = RT->getDecl()->getDefinitionOrSelf();
2054 for (FieldDecl *FD : RD->fields()) {
2055 const Type *Ty = FD->getType()->getUnqualifiedDesugaredType();
2056
2057 // Unwrap arrays
2058 // FIXME: Calculate array size while unwrapping
2059 assert(!Ty->isIncompleteArrayType() &&
2060 "incomplete arrays inside user defined types are not supported");
2061 while (Ty->isConstantArrayType()) {
2064 }
2065
2066 if (!Ty->isRecordType())
2067 continue;
2068
2069 if (const HLSLAttributedResourceType *AttrResType =
2070 HLSLAttributedResourceType::findHandleTypeOnResource(Ty)) {
2071 // Add a new DeclBindingInfo to Bindings if it does not already exist
2072 ResourceClass RC = AttrResType->getAttrs().ResourceClass;
2073 DeclBindingInfo *DBI = Bindings.getDeclBindingInfo(VD, RC);
2074 if (!DBI)
2075 Bindings.addDeclBindingInfo(VD, RC);
2076 } else if (const RecordType *RT = dyn_cast<RecordType>(Ty)) {
2077 // Recursively scan embedded struct or class; it would be nice to do this
2078 // without recursion, but tricky to correctly calculate the size of the
2079 // binding, which is something we are probably going to need to do later
2080 // on. Hopefully nesting of structs in structs too many levels is
2081 // unlikely.
2082 collectResourceBindingsOnUserRecordDecl(VD, RT);
2083 }
2084 }
2085}
2086
2087// Diagnose localized register binding errors for a single binding; does not
2088// diagnose resource binding on user record types, that will be done later
2089// in processResourceBindingOnDecl based on the information collected in
2090// collectResourceBindingsOnVarDecl.
2091// Returns false if the register binding is not valid.
2093 Decl *D, RegisterType RegType,
2094 bool SpecifiedSpace) {
2095 int RegTypeNum = static_cast<int>(RegType);
2096
2097 // check if the decl type is groupshared
2098 if (D->hasAttr<HLSLGroupSharedAddressSpaceAttr>()) {
2099 S.Diag(ArgLoc, diag::err_hlsl_binding_type_mismatch) << RegTypeNum;
2100 return false;
2101 }
2102
2103 // Cbuffers and Tbuffers are HLSLBufferDecl types
2104 if (HLSLBufferDecl *CBufferOrTBuffer = dyn_cast<HLSLBufferDecl>(D)) {
2105 ResourceClass RC = CBufferOrTBuffer->isCBuffer() ? ResourceClass::CBuffer
2106 : ResourceClass::SRV;
2107 if (RegType == getRegisterType(RC))
2108 return true;
2109
2110 S.Diag(D->getLocation(), diag::err_hlsl_binding_type_mismatch)
2111 << RegTypeNum;
2112 return false;
2113 }
2114
2115 // Samplers, UAVs, and SRVs are VarDecl types
2116 assert(isa<VarDecl>(D) && "D is expected to be VarDecl or HLSLBufferDecl");
2117 VarDecl *VD = cast<VarDecl>(D);
2118
2119 // Resource
2120 if (const HLSLAttributedResourceType *AttrResType =
2121 HLSLAttributedResourceType::findHandleTypeOnResource(
2122 VD->getType().getTypePtr())) {
2123 if (RegType == getRegisterType(AttrResType))
2124 return true;
2125
2126 S.Diag(D->getLocation(), diag::err_hlsl_binding_type_mismatch)
2127 << RegTypeNum;
2128 return false;
2129 }
2130
2131 const clang::Type *Ty = VD->getType().getTypePtr();
2132 while (Ty->isArrayType())
2134
2135 // Basic types
2136 if (Ty->isArithmeticType() || Ty->isVectorType()) {
2137 bool DeclaredInCOrTBuffer = isa<HLSLBufferDecl>(D->getDeclContext());
2138 if (SpecifiedSpace && !DeclaredInCOrTBuffer)
2139 S.Diag(ArgLoc, diag::err_hlsl_space_on_global_constant);
2140
2141 if (!DeclaredInCOrTBuffer && (Ty->isIntegralType(S.getASTContext()) ||
2142 Ty->isFloatingType() || Ty->isVectorType())) {
2143 // Register annotation on default constant buffer declaration ($Globals)
2144 if (RegType == RegisterType::CBuffer)
2145 S.Diag(ArgLoc, diag::warn_hlsl_deprecated_register_type_b);
2146 else if (RegType != RegisterType::C)
2147 S.Diag(ArgLoc, diag::err_hlsl_binding_type_mismatch) << RegTypeNum;
2148 else
2149 return true;
2150 } else {
2151 if (RegType == RegisterType::C)
2152 S.Diag(ArgLoc, diag::warn_hlsl_register_type_c_packoffset);
2153 else
2154 S.Diag(ArgLoc, diag::err_hlsl_binding_type_mismatch) << RegTypeNum;
2155 }
2156 return false;
2157 }
2158 if (Ty->isRecordType())
2159 // RecordTypes will be diagnosed in processResourceBindingOnDecl
2160 // that is called from ActOnVariableDeclarator
2161 return true;
2162
2163 // Anything else is an error
2164 S.Diag(ArgLoc, diag::err_hlsl_binding_type_mismatch) << RegTypeNum;
2165 return false;
2166}
2167
2169 RegisterType regType) {
2170 // make sure that there are no two register annotations
2171 // applied to the decl with the same register type
2172 bool RegisterTypesDetected[5] = {false};
2173 RegisterTypesDetected[static_cast<int>(regType)] = true;
2174
2175 for (auto it = TheDecl->attr_begin(); it != TheDecl->attr_end(); ++it) {
2176 if (HLSLResourceBindingAttr *attr =
2177 dyn_cast<HLSLResourceBindingAttr>(*it)) {
2178
2179 RegisterType otherRegType = attr->getRegisterType();
2180 if (RegisterTypesDetected[static_cast<int>(otherRegType)]) {
2181 int otherRegTypeNum = static_cast<int>(otherRegType);
2182 S.Diag(TheDecl->getLocation(),
2183 diag::err_hlsl_duplicate_register_annotation)
2184 << otherRegTypeNum;
2185 return false;
2186 }
2187 RegisterTypesDetected[static_cast<int>(otherRegType)] = true;
2188 }
2189 }
2190 return true;
2191}
2192
2194 Decl *D, RegisterType RegType,
2195 bool SpecifiedSpace) {
2196
2197 // exactly one of these two types should be set
2198 assert(((isa<VarDecl>(D) && !isa<HLSLBufferDecl>(D)) ||
2199 (!isa<VarDecl>(D) && isa<HLSLBufferDecl>(D))) &&
2200 "expecting VarDecl or HLSLBufferDecl");
2201
2202 // check if the declaration contains resource matching the register type
2203 if (!DiagnoseLocalRegisterBinding(S, ArgLoc, D, RegType, SpecifiedSpace))
2204 return false;
2205
2206 // next, if multiple register annotations exist, check that none conflict.
2207 return ValidateMultipleRegisterAnnotations(S, D, RegType);
2208}
2209
2211 if (VarDecl *VD = dyn_cast<VarDecl>(TheDecl)) {
2212 QualType Ty = VD->getType();
2213 if (const auto *IAT = dyn_cast<IncompleteArrayType>(Ty))
2214 Ty = IAT->getElementType();
2215 if (SemaRef.RequireCompleteType(TheDecl->getBeginLoc(), Ty,
2216 diag::err_incomplete_type))
2217 return;
2218 }
2219
2220 StringRef Slot = "";
2221 StringRef Space = "";
2222 SourceLocation SlotLoc, SpaceLoc;
2223
2224 if (!AL.isArgIdent(0)) {
2225 Diag(AL.getLoc(), diag::err_attribute_argument_type)
2226 << AL << AANT_ArgumentIdentifier;
2227 return;
2228 }
2229 IdentifierLoc *Loc = AL.getArgAsIdent(0);
2230
2231 if (AL.getNumArgs() == 2) {
2232 Slot = Loc->getIdentifierInfo()->getName();
2233 SlotLoc = Loc->getLoc();
2234 if (!AL.isArgIdent(1)) {
2235 Diag(AL.getLoc(), diag::err_attribute_argument_type)
2236 << AL << AANT_ArgumentIdentifier;
2237 return;
2238 }
2239 Loc = AL.getArgAsIdent(1);
2240 Space = Loc->getIdentifierInfo()->getName();
2241 SpaceLoc = Loc->getLoc();
2242 } else {
2243 StringRef Str = Loc->getIdentifierInfo()->getName();
2244 if (Str.starts_with("space")) {
2245 Space = Str;
2246 SpaceLoc = Loc->getLoc();
2247 } else {
2248 Slot = Str;
2249 SlotLoc = Loc->getLoc();
2250 Space = "space0";
2251 }
2252 }
2253
2254 RegisterType RegType = RegisterType::SRV;
2255 std::optional<unsigned> SlotNum;
2256 unsigned SpaceNum = 0;
2257
2258 // Validate slot
2259 if (!Slot.empty()) {
2260 if (!convertToRegisterType(Slot, &RegType)) {
2261 Diag(SlotLoc, diag::err_hlsl_binding_type_invalid) << Slot.substr(0, 1);
2262 return;
2263 }
2264 if (RegType == RegisterType::I) {
2265 Diag(SlotLoc, diag::warn_hlsl_deprecated_register_type_i);
2266 return;
2267 }
2268 StringRef SlotNumStr = Slot.substr(1);
2269 unsigned N;
2270 if (SlotNumStr.getAsInteger(10, N)) {
2271 Diag(SlotLoc, diag::err_hlsl_unsupported_register_number);
2272 return;
2273 }
2274 SlotNum = N;
2275 }
2276
2277 // Validate space
2278 if (!Space.starts_with("space")) {
2279 Diag(SpaceLoc, diag::err_hlsl_expected_space) << Space;
2280 return;
2281 }
2282 StringRef SpaceNumStr = Space.substr(5);
2283 if (SpaceNumStr.getAsInteger(10, SpaceNum)) {
2284 Diag(SpaceLoc, diag::err_hlsl_expected_space) << Space;
2285 return;
2286 }
2287
2288 // If we have slot, diagnose it is the right register type for the decl
2289 if (SlotNum.has_value())
2290 if (!DiagnoseHLSLRegisterAttribute(SemaRef, SlotLoc, TheDecl, RegType,
2291 !SpaceLoc.isInvalid()))
2292 return;
2293
2294 HLSLResourceBindingAttr *NewAttr =
2295 HLSLResourceBindingAttr::Create(getASTContext(), Slot, Space, AL);
2296 if (NewAttr) {
2297 NewAttr->setBinding(RegType, SlotNum, SpaceNum);
2298 TheDecl->addAttr(NewAttr);
2299 }
2300}
2301
2303 HLSLParamModifierAttr *NewAttr = mergeParamModifierAttr(
2304 D, AL,
2305 static_cast<HLSLParamModifierAttr::Spelling>(AL.getSemanticSpelling()));
2306 if (NewAttr)
2307 D->addAttr(NewAttr);
2308}
2309
2310namespace {
2311
2312/// This class implements HLSL availability diagnostics for default
2313/// and relaxed mode
2314///
2315/// The goal of this diagnostic is to emit an error or warning when an
2316/// unavailable API is found in code that is reachable from the shader
2317/// entry function or from an exported function (when compiling a shader
2318/// library).
2319///
2320/// This is done by traversing the AST of all shader entry point functions
2321/// and of all exported functions, and any functions that are referenced
2322/// from this AST. In other words, any functions that are reachable from
2323/// the entry points.
2324class DiagnoseHLSLAvailability : public DynamicRecursiveASTVisitor {
2325 Sema &SemaRef;
2326
2327 // Stack of functions to be scaned
2329
2330 // Tracks which environments functions have been scanned in.
2331 //
2332 // Maps FunctionDecl to an unsigned number that represents the set of shader
2333 // environments the function has been scanned for.
2334 // The llvm::Triple::EnvironmentType enum values for shader stages guaranteed
2335 // to be numbered from llvm::Triple::Pixel to llvm::Triple::Amplification
2336 // (verified by static_asserts in Triple.cpp), we can use it to index
2337 // individual bits in the set, as long as we shift the values to start with 0
2338 // by subtracting the value of llvm::Triple::Pixel first.
2339 //
2340 // The N'th bit in the set will be set if the function has been scanned
2341 // in shader environment whose llvm::Triple::EnvironmentType integer value
2342 // equals (llvm::Triple::Pixel + N).
2343 //
2344 // For example, if a function has been scanned in compute and pixel stage
2345 // environment, the value will be 0x21 (100001 binary) because:
2346 //
2347 // (int)(llvm::Triple::Pixel - llvm::Triple::Pixel) == 0
2348 // (int)(llvm::Triple::Compute - llvm::Triple::Pixel) == 5
2349 //
2350 // A FunctionDecl is mapped to 0 (or not included in the map) if it has not
2351 // been scanned in any environment.
2352 llvm::DenseMap<const FunctionDecl *, unsigned> ScannedDecls;
2353
2354 // Do not access these directly, use the get/set methods below to make
2355 // sure the values are in sync
2356 llvm::Triple::EnvironmentType CurrentShaderEnvironment;
2357 unsigned CurrentShaderStageBit;
2358
2359 // True if scanning a function that was already scanned in a different
2360 // shader stage context, and therefore we should not report issues that
2361 // depend only on shader model version because they would be duplicate.
2362 bool ReportOnlyShaderStageIssues;
2363
2364 // Helper methods for dealing with current stage context / environment
2365 void SetShaderStageContext(llvm::Triple::EnvironmentType ShaderType) {
2366 static_assert(sizeof(unsigned) >= 4);
2367 assert(HLSLShaderAttr::isValidShaderType(ShaderType));
2368 assert((unsigned)(ShaderType - llvm::Triple::Pixel) < 31 &&
2369 "ShaderType is too big for this bitmap"); // 31 is reserved for
2370 // "unknown"
2371
2372 unsigned bitmapIndex = ShaderType - llvm::Triple::Pixel;
2373 CurrentShaderEnvironment = ShaderType;
2374 CurrentShaderStageBit = (1 << bitmapIndex);
2375 }
2376
2377 void SetUnknownShaderStageContext() {
2378 CurrentShaderEnvironment = llvm::Triple::UnknownEnvironment;
2379 CurrentShaderStageBit = (1 << 31);
2380 }
2381
2382 llvm::Triple::EnvironmentType GetCurrentShaderEnvironment() const {
2383 return CurrentShaderEnvironment;
2384 }
2385
2386 bool InUnknownShaderStageContext() const {
2387 return CurrentShaderEnvironment == llvm::Triple::UnknownEnvironment;
2388 }
2389
2390 // Helper methods for dealing with shader stage bitmap
2391 void AddToScannedFunctions(const FunctionDecl *FD) {
2392 unsigned &ScannedStages = ScannedDecls[FD];
2393 ScannedStages |= CurrentShaderStageBit;
2394 }
2395
2396 unsigned GetScannedStages(const FunctionDecl *FD) { return ScannedDecls[FD]; }
2397
2398 bool WasAlreadyScannedInCurrentStage(const FunctionDecl *FD) {
2399 return WasAlreadyScannedInCurrentStage(GetScannedStages(FD));
2400 }
2401
2402 bool WasAlreadyScannedInCurrentStage(unsigned ScannerStages) {
2403 return ScannerStages & CurrentShaderStageBit;
2404 }
2405
2406 static bool NeverBeenScanned(unsigned ScannedStages) {
2407 return ScannedStages == 0;
2408 }
2409
2410 // Scanning methods
2411 void HandleFunctionOrMethodRef(FunctionDecl *FD, Expr *RefExpr);
2412 void CheckDeclAvailability(NamedDecl *D, const AvailabilityAttr *AA,
2413 SourceRange Range);
2414 const AvailabilityAttr *FindAvailabilityAttr(const Decl *D);
2415 bool HasMatchingEnvironmentOrNone(const AvailabilityAttr *AA);
2416
2417public:
2418 DiagnoseHLSLAvailability(Sema &SemaRef)
2419 : SemaRef(SemaRef),
2420 CurrentShaderEnvironment(llvm::Triple::UnknownEnvironment),
2421 CurrentShaderStageBit(0), ReportOnlyShaderStageIssues(false) {}
2422
2423 // AST traversal methods
2424 void RunOnTranslationUnit(const TranslationUnitDecl *TU);
2425 void RunOnFunction(const FunctionDecl *FD);
2426
2427 bool VisitDeclRefExpr(DeclRefExpr *DRE) override {
2428 FunctionDecl *FD = llvm::dyn_cast<FunctionDecl>(DRE->getDecl());
2429 if (FD)
2430 HandleFunctionOrMethodRef(FD, DRE);
2431 return true;
2432 }
2433
2434 bool VisitMemberExpr(MemberExpr *ME) override {
2435 FunctionDecl *FD = llvm::dyn_cast<FunctionDecl>(ME->getMemberDecl());
2436 if (FD)
2437 HandleFunctionOrMethodRef(FD, ME);
2438 return true;
2439 }
2440};
2441
2442void DiagnoseHLSLAvailability::HandleFunctionOrMethodRef(FunctionDecl *FD,
2443 Expr *RefExpr) {
2444 assert((isa<DeclRefExpr>(RefExpr) || isa<MemberExpr>(RefExpr)) &&
2445 "expected DeclRefExpr or MemberExpr");
2446
2447 // has a definition -> add to stack to be scanned
2448 const FunctionDecl *FDWithBody = nullptr;
2449 if (FD->hasBody(FDWithBody)) {
2450 if (!WasAlreadyScannedInCurrentStage(FDWithBody))
2451 DeclsToScan.push_back(FDWithBody);
2452 return;
2453 }
2454
2455 // no body -> diagnose availability
2456 const AvailabilityAttr *AA = FindAvailabilityAttr(FD);
2457 if (AA)
2458 CheckDeclAvailability(
2459 FD, AA, SourceRange(RefExpr->getBeginLoc(), RefExpr->getEndLoc()));
2460}
2461
2462void DiagnoseHLSLAvailability::RunOnTranslationUnit(
2463 const TranslationUnitDecl *TU) {
2464
2465 // Iterate over all shader entry functions and library exports, and for those
2466 // that have a body (definiton), run diag scan on each, setting appropriate
2467 // shader environment context based on whether it is a shader entry function
2468 // or an exported function. Exported functions can be in namespaces and in
2469 // export declarations so we need to scan those declaration contexts as well.
2471 DeclContextsToScan.push_back(TU);
2472
2473 while (!DeclContextsToScan.empty()) {
2474 const DeclContext *DC = DeclContextsToScan.pop_back_val();
2475 for (auto &D : DC->decls()) {
2476 // do not scan implicit declaration generated by the implementation
2477 if (D->isImplicit())
2478 continue;
2479
2480 // for namespace or export declaration add the context to the list to be
2481 // scanned later
2482 if (llvm::dyn_cast<NamespaceDecl>(D) || llvm::dyn_cast<ExportDecl>(D)) {
2483 DeclContextsToScan.push_back(llvm::dyn_cast<DeclContext>(D));
2484 continue;
2485 }
2486
2487 // skip over other decls or function decls without body
2488 const FunctionDecl *FD = llvm::dyn_cast<FunctionDecl>(D);
2489 if (!FD || !FD->isThisDeclarationADefinition())
2490 continue;
2491
2492 // shader entry point
2493 if (HLSLShaderAttr *ShaderAttr = FD->getAttr<HLSLShaderAttr>()) {
2494 SetShaderStageContext(ShaderAttr->getType());
2495 RunOnFunction(FD);
2496 continue;
2497 }
2498 // exported library function
2499 // FIXME: replace this loop with external linkage check once issue #92071
2500 // is resolved
2501 bool isExport = FD->isInExportDeclContext();
2502 if (!isExport) {
2503 for (const auto *Redecl : FD->redecls()) {
2504 if (Redecl->isInExportDeclContext()) {
2505 isExport = true;
2506 break;
2507 }
2508 }
2509 }
2510 if (isExport) {
2511 SetUnknownShaderStageContext();
2512 RunOnFunction(FD);
2513 continue;
2514 }
2515 }
2516 }
2517}
2518
2519void DiagnoseHLSLAvailability::RunOnFunction(const FunctionDecl *FD) {
2520 assert(DeclsToScan.empty() && "DeclsToScan should be empty");
2521 DeclsToScan.push_back(FD);
2522
2523 while (!DeclsToScan.empty()) {
2524 // Take one decl from the stack and check it by traversing its AST.
2525 // For any CallExpr found during the traversal add it's callee to the top of
2526 // the stack to be processed next. Functions already processed are stored in
2527 // ScannedDecls.
2528 const FunctionDecl *FD = DeclsToScan.pop_back_val();
2529
2530 // Decl was already scanned
2531 const unsigned ScannedStages = GetScannedStages(FD);
2532 if (WasAlreadyScannedInCurrentStage(ScannedStages))
2533 continue;
2534
2535 ReportOnlyShaderStageIssues = !NeverBeenScanned(ScannedStages);
2536
2537 AddToScannedFunctions(FD);
2538 TraverseStmt(FD->getBody());
2539 }
2540}
2541
2542bool DiagnoseHLSLAvailability::HasMatchingEnvironmentOrNone(
2543 const AvailabilityAttr *AA) {
2544 IdentifierInfo *IIEnvironment = AA->getEnvironment();
2545 if (!IIEnvironment)
2546 return true;
2547
2548 llvm::Triple::EnvironmentType CurrentEnv = GetCurrentShaderEnvironment();
2549 if (CurrentEnv == llvm::Triple::UnknownEnvironment)
2550 return false;
2551
2552 llvm::Triple::EnvironmentType AttrEnv =
2553 AvailabilityAttr::getEnvironmentType(IIEnvironment->getName());
2554
2555 return CurrentEnv == AttrEnv;
2556}
2557
2558const AvailabilityAttr *
2559DiagnoseHLSLAvailability::FindAvailabilityAttr(const Decl *D) {
2560 AvailabilityAttr const *PartialMatch = nullptr;
2561 // Check each AvailabilityAttr to find the one for this platform.
2562 // For multiple attributes with the same platform try to find one for this
2563 // environment.
2564 for (const auto *A : D->attrs()) {
2565 if (const auto *Avail = dyn_cast<AvailabilityAttr>(A)) {
2566 StringRef AttrPlatform = Avail->getPlatform()->getName();
2567 StringRef TargetPlatform =
2569
2570 // Match the platform name.
2571 if (AttrPlatform == TargetPlatform) {
2572 // Find the best matching attribute for this environment
2573 if (HasMatchingEnvironmentOrNone(Avail))
2574 return Avail;
2575 PartialMatch = Avail;
2576 }
2577 }
2578 }
2579 return PartialMatch;
2580}
2581
2582// Check availability against target shader model version and current shader
2583// stage and emit diagnostic
2584void DiagnoseHLSLAvailability::CheckDeclAvailability(NamedDecl *D,
2585 const AvailabilityAttr *AA,
2586 SourceRange Range) {
2587
2588 IdentifierInfo *IIEnv = AA->getEnvironment();
2589
2590 if (!IIEnv) {
2591 // The availability attribute does not have environment -> it depends only
2592 // on shader model version and not on specific the shader stage.
2593
2594 // Skip emitting the diagnostics if the diagnostic mode is set to
2595 // strict (-fhlsl-strict-availability) because all relevant diagnostics
2596 // were already emitted in the DiagnoseUnguardedAvailability scan
2597 // (SemaAvailability.cpp).
2598 if (SemaRef.getLangOpts().HLSLStrictAvailability)
2599 return;
2600
2601 // Do not report shader-stage-independent issues if scanning a function
2602 // that was already scanned in a different shader stage context (they would
2603 // be duplicate)
2604 if (ReportOnlyShaderStageIssues)
2605 return;
2606
2607 } else {
2608 // The availability attribute has environment -> we need to know
2609 // the current stage context to property diagnose it.
2610 if (InUnknownShaderStageContext())
2611 return;
2612 }
2613
2614 // Check introduced version and if environment matches
2615 bool EnvironmentMatches = HasMatchingEnvironmentOrNone(AA);
2616 VersionTuple Introduced = AA->getIntroduced();
2617 VersionTuple TargetVersion =
2619
2620 if (TargetVersion >= Introduced && EnvironmentMatches)
2621 return;
2622
2623 // Emit diagnostic message
2624 const TargetInfo &TI = SemaRef.getASTContext().getTargetInfo();
2625 llvm::StringRef PlatformName(
2626 AvailabilityAttr::getPrettyPlatformName(TI.getPlatformName()));
2627
2628 llvm::StringRef CurrentEnvStr =
2629 llvm::Triple::getEnvironmentTypeName(GetCurrentShaderEnvironment());
2630
2631 llvm::StringRef AttrEnvStr =
2632 AA->getEnvironment() ? AA->getEnvironment()->getName() : "";
2633 bool UseEnvironment = !AttrEnvStr.empty();
2634
2635 if (EnvironmentMatches) {
2636 SemaRef.Diag(Range.getBegin(), diag::warn_hlsl_availability)
2637 << Range << D << PlatformName << Introduced.getAsString()
2638 << UseEnvironment << CurrentEnvStr;
2639 } else {
2640 SemaRef.Diag(Range.getBegin(), diag::warn_hlsl_availability_unavailable)
2641 << Range << D;
2642 }
2643
2644 SemaRef.Diag(D->getLocation(), diag::note_partial_availability_specified_here)
2645 << D << PlatformName << Introduced.getAsString()
2646 << SemaRef.Context.getTargetInfo().getPlatformMinVersion().getAsString()
2647 << UseEnvironment << AttrEnvStr << CurrentEnvStr;
2648}
2649
2650} // namespace
2651
2653 // process default CBuffer - create buffer layout struct and invoke codegenCGH
2654 if (!DefaultCBufferDecls.empty()) {
2656 SemaRef.getASTContext(), SemaRef.getCurLexicalContext(),
2657 DefaultCBufferDecls);
2658 addImplicitBindingAttrToDecl(SemaRef, DefaultCBuffer, RegisterType::CBuffer,
2659 getNextImplicitBindingOrderID());
2660 SemaRef.getCurLexicalContext()->addDecl(DefaultCBuffer);
2662
2663 // Set HasValidPackoffset if any of the decls has a register(c#) annotation;
2664 for (const Decl *VD : DefaultCBufferDecls) {
2665 const HLSLResourceBindingAttr *RBA =
2666 VD->getAttr<HLSLResourceBindingAttr>();
2667 if (RBA && RBA->hasRegisterSlot() &&
2668 RBA->getRegisterType() == HLSLResourceBindingAttr::RegisterType::C) {
2669 DefaultCBuffer->setHasValidPackoffset(true);
2670 break;
2671 }
2672 }
2673
2674 DeclGroupRef DG(DefaultCBuffer);
2675 SemaRef.Consumer.HandleTopLevelDecl(DG);
2676 }
2677 diagnoseAvailabilityViolations(TU);
2678}
2679
2680void SemaHLSL::diagnoseAvailabilityViolations(TranslationUnitDecl *TU) {
2681 // Skip running the diagnostics scan if the diagnostic mode is
2682 // strict (-fhlsl-strict-availability) and the target shader stage is known
2683 // because all relevant diagnostics were already emitted in the
2684 // DiagnoseUnguardedAvailability scan (SemaAvailability.cpp).
2686 if (SemaRef.getLangOpts().HLSLStrictAvailability &&
2687 TI.getTriple().getEnvironment() != llvm::Triple::EnvironmentType::Library)
2688 return;
2689
2690 DiagnoseHLSLAvailability(SemaRef).RunOnTranslationUnit(TU);
2691}
2692
2693static bool CheckAllArgsHaveSameType(Sema *S, CallExpr *TheCall) {
2694 assert(TheCall->getNumArgs() > 1);
2695 QualType ArgTy0 = TheCall->getArg(0)->getType();
2696
2697 for (unsigned I = 1, N = TheCall->getNumArgs(); I < N; ++I) {
2699 ArgTy0, TheCall->getArg(I)->getType())) {
2700 S->Diag(TheCall->getBeginLoc(), diag::err_vec_builtin_incompatible_vector)
2701 << TheCall->getDirectCallee() << /*useAllTerminology*/ true
2702 << SourceRange(TheCall->getArg(0)->getBeginLoc(),
2703 TheCall->getArg(N - 1)->getEndLoc());
2704 return true;
2705 }
2706 }
2707 return false;
2708}
2709
2711 QualType ArgType = Arg->getType();
2713 S->Diag(Arg->getBeginLoc(), diag::err_typecheck_convert_incompatible)
2714 << ArgType << ExpectedType << 1 << 0 << 0;
2715 return true;
2716 }
2717 return false;
2718}
2719
2721 Sema *S, CallExpr *TheCall,
2722 llvm::function_ref<bool(Sema *S, SourceLocation Loc, int ArgOrdinal,
2723 clang::QualType PassedType)>
2724 Check) {
2725 for (unsigned I = 0; I < TheCall->getNumArgs(); ++I) {
2726 Expr *Arg = TheCall->getArg(I);
2727 if (Check(S, Arg->getBeginLoc(), I + 1, Arg->getType()))
2728 return true;
2729 }
2730 return false;
2731}
2732
2734 int ArgOrdinal,
2735 clang::QualType PassedType) {
2736 clang::QualType BaseType =
2737 PassedType->isVectorType()
2738 ? PassedType->castAs<clang::VectorType>()->getElementType()
2739 : PassedType;
2740 if (!BaseType->isHalfType() && !BaseType->isFloat32Type())
2741 return S->Diag(Loc, diag::err_builtin_invalid_arg_type)
2742 << ArgOrdinal << /* scalar or vector of */ 5 << /* no int */ 0
2743 << /* half or float */ 2 << PassedType;
2744 return false;
2745}
2746
2747static bool CheckModifiableLValue(Sema *S, CallExpr *TheCall,
2748 unsigned ArgIndex) {
2749 auto *Arg = TheCall->getArg(ArgIndex);
2750 SourceLocation OrigLoc = Arg->getExprLoc();
2751 if (Arg->IgnoreCasts()->isModifiableLvalue(S->Context, &OrigLoc) ==
2753 return false;
2754 S->Diag(OrigLoc, diag::error_hlsl_inout_lvalue) << Arg << 0;
2755 return true;
2756}
2757
2758static bool CheckNoDoubleVectors(Sema *S, SourceLocation Loc, int ArgOrdinal,
2759 clang::QualType PassedType) {
2760 const auto *VecTy = PassedType->getAs<VectorType>();
2761 if (!VecTy)
2762 return false;
2763
2764 if (VecTy->getElementType()->isDoubleType())
2765 return S->Diag(Loc, diag::err_builtin_invalid_arg_type)
2766 << ArgOrdinal << /* scalar */ 1 << /* no int */ 0 << /* fp */ 1
2767 << PassedType;
2768 return false;
2769}
2770
2772 int ArgOrdinal,
2773 clang::QualType PassedType) {
2774 if (!PassedType->hasIntegerRepresentation() &&
2775 !PassedType->hasFloatingRepresentation())
2776 return S->Diag(Loc, diag::err_builtin_invalid_arg_type)
2777 << ArgOrdinal << /* scalar or vector of */ 5 << /* integer */ 1
2778 << /* fp */ 1 << PassedType;
2779 return false;
2780}
2781
2783 int ArgOrdinal,
2784 clang::QualType PassedType) {
2785 if (auto *VecTy = PassedType->getAs<VectorType>())
2786 if (VecTy->getElementType()->isUnsignedIntegerType())
2787 return false;
2788
2789 return S->Diag(Loc, diag::err_builtin_invalid_arg_type)
2790 << ArgOrdinal << /* vector of */ 4 << /* uint */ 3 << /* no fp */ 0
2791 << PassedType;
2792}
2793
2794// checks for unsigned ints of all sizes
2796 int ArgOrdinal,
2797 clang::QualType PassedType) {
2798 if (!PassedType->hasUnsignedIntegerRepresentation())
2799 return S->Diag(Loc, diag::err_builtin_invalid_arg_type)
2800 << ArgOrdinal << /* scalar or vector of */ 5 << /* unsigned int */ 3
2801 << /* no fp */ 0 << PassedType;
2802 return false;
2803}
2804
2806 QualType ReturnType) {
2807 auto *VecTyA = TheCall->getArg(0)->getType()->getAs<VectorType>();
2808 if (VecTyA)
2809 ReturnType =
2810 S->Context.getExtVectorType(ReturnType, VecTyA->getNumElements());
2811
2812 TheCall->setType(ReturnType);
2813}
2814
2815static bool CheckScalarOrVector(Sema *S, CallExpr *TheCall, QualType Scalar,
2816 unsigned ArgIndex) {
2817 assert(TheCall->getNumArgs() >= ArgIndex);
2818 QualType ArgType = TheCall->getArg(ArgIndex)->getType();
2819 auto *VTy = ArgType->getAs<VectorType>();
2820 // not the scalar or vector<scalar>
2821 if (!(S->Context.hasSameUnqualifiedType(ArgType, Scalar) ||
2822 (VTy &&
2823 S->Context.hasSameUnqualifiedType(VTy->getElementType(), Scalar)))) {
2824 S->Diag(TheCall->getArg(0)->getBeginLoc(),
2825 diag::err_typecheck_expect_scalar_or_vector)
2826 << ArgType << Scalar;
2827 return true;
2828 }
2829 return false;
2830}
2831
2832static bool CheckAnyScalarOrVector(Sema *S, CallExpr *TheCall,
2833 unsigned ArgIndex) {
2834 assert(TheCall->getNumArgs() >= ArgIndex);
2835 QualType ArgType = TheCall->getArg(ArgIndex)->getType();
2836 auto *VTy = ArgType->getAs<VectorType>();
2837 // not the scalar or vector<scalar>
2838 if (!(ArgType->isScalarType() ||
2839 (VTy && VTy->getElementType()->isScalarType()))) {
2840 S->Diag(TheCall->getArg(0)->getBeginLoc(),
2841 diag::err_typecheck_expect_any_scalar_or_vector)
2842 << ArgType << 1;
2843 return true;
2844 }
2845 return false;
2846}
2847
2848static bool CheckWaveActive(Sema *S, CallExpr *TheCall) {
2849 QualType BoolType = S->getASTContext().BoolTy;
2850 assert(TheCall->getNumArgs() >= 1);
2851 QualType ArgType = TheCall->getArg(0)->getType();
2852 auto *VTy = ArgType->getAs<VectorType>();
2853 // is the bool or vector<bool>
2854 if (S->Context.hasSameUnqualifiedType(ArgType, BoolType) ||
2855 (VTy &&
2856 S->Context.hasSameUnqualifiedType(VTy->getElementType(), BoolType))) {
2857 S->Diag(TheCall->getArg(0)->getBeginLoc(),
2858 diag::err_typecheck_expect_any_scalar_or_vector)
2859 << ArgType << 0;
2860 return true;
2861 }
2862 return false;
2863}
2864
2865static bool CheckBoolSelect(Sema *S, CallExpr *TheCall) {
2866 assert(TheCall->getNumArgs() == 3);
2867 Expr *Arg1 = TheCall->getArg(1);
2868 Expr *Arg2 = TheCall->getArg(2);
2869 if (!S->Context.hasSameUnqualifiedType(Arg1->getType(), Arg2->getType())) {
2870 S->Diag(TheCall->getBeginLoc(),
2871 diag::err_typecheck_call_different_arg_types)
2872 << Arg1->getType() << Arg2->getType() << Arg1->getSourceRange()
2873 << Arg2->getSourceRange();
2874 return true;
2875 }
2876
2877 TheCall->setType(Arg1->getType());
2878 return false;
2879}
2880
2881static bool CheckVectorSelect(Sema *S, CallExpr *TheCall) {
2882 assert(TheCall->getNumArgs() == 3);
2883 Expr *Arg1 = TheCall->getArg(1);
2884 QualType Arg1Ty = Arg1->getType();
2885 Expr *Arg2 = TheCall->getArg(2);
2886 QualType Arg2Ty = Arg2->getType();
2887
2888 QualType Arg1ScalarTy = Arg1Ty;
2889 if (auto VTy = Arg1ScalarTy->getAs<VectorType>())
2890 Arg1ScalarTy = VTy->getElementType();
2891
2892 QualType Arg2ScalarTy = Arg2Ty;
2893 if (auto VTy = Arg2ScalarTy->getAs<VectorType>())
2894 Arg2ScalarTy = VTy->getElementType();
2895
2896 if (!S->Context.hasSameUnqualifiedType(Arg1ScalarTy, Arg2ScalarTy))
2897 S->Diag(Arg1->getBeginLoc(), diag::err_hlsl_builtin_scalar_vector_mismatch)
2898 << /* second and third */ 1 << TheCall->getCallee() << Arg1Ty << Arg2Ty;
2899
2900 QualType Arg0Ty = TheCall->getArg(0)->getType();
2901 unsigned Arg0Length = Arg0Ty->getAs<VectorType>()->getNumElements();
2902 unsigned Arg1Length = Arg1Ty->isVectorType()
2903 ? Arg1Ty->getAs<VectorType>()->getNumElements()
2904 : 0;
2905 unsigned Arg2Length = Arg2Ty->isVectorType()
2906 ? Arg2Ty->getAs<VectorType>()->getNumElements()
2907 : 0;
2908 if (Arg1Length > 0 && Arg0Length != Arg1Length) {
2909 S->Diag(TheCall->getBeginLoc(),
2910 diag::err_typecheck_vector_lengths_not_equal)
2911 << Arg0Ty << Arg1Ty << TheCall->getArg(0)->getSourceRange()
2912 << Arg1->getSourceRange();
2913 return true;
2914 }
2915
2916 if (Arg2Length > 0 && Arg0Length != Arg2Length) {
2917 S->Diag(TheCall->getBeginLoc(),
2918 diag::err_typecheck_vector_lengths_not_equal)
2919 << Arg0Ty << Arg2Ty << TheCall->getArg(0)->getSourceRange()
2920 << Arg2->getSourceRange();
2921 return true;
2922 }
2923
2924 TheCall->setType(
2925 S->getASTContext().getExtVectorType(Arg1ScalarTy, Arg0Length));
2926 return false;
2927}
2928
2930 Sema *S, CallExpr *TheCall, unsigned ArgIndex,
2931 llvm::function_ref<bool(const HLSLAttributedResourceType *ResType)> Check =
2932 nullptr) {
2933 assert(TheCall->getNumArgs() >= ArgIndex);
2934 QualType ArgType = TheCall->getArg(ArgIndex)->getType();
2935 const HLSLAttributedResourceType *ResTy =
2936 ArgType.getTypePtr()->getAs<HLSLAttributedResourceType>();
2937 if (!ResTy) {
2938 S->Diag(TheCall->getArg(ArgIndex)->getBeginLoc(),
2939 diag::err_typecheck_expect_hlsl_resource)
2940 << ArgType;
2941 return true;
2942 }
2943 if (Check && Check(ResTy)) {
2944 S->Diag(TheCall->getArg(ArgIndex)->getExprLoc(),
2945 diag::err_invalid_hlsl_resource_type)
2946 << ArgType;
2947 return true;
2948 }
2949 return false;
2950}
2951
2952// Note: returning true in this case results in CheckBuiltinFunctionCall
2953// returning an ExprError
2954bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
2955 switch (BuiltinID) {
2956 case Builtin::BI__builtin_hlsl_adduint64: {
2957 if (SemaRef.checkArgCount(TheCall, 2))
2958 return true;
2959
2960 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
2962 return true;
2963
2964 auto *VTy = TheCall->getArg(0)->getType()->getAs<VectorType>();
2965 // ensure arg integers are 32-bits
2966 uint64_t ElementBitCount = getASTContext()
2967 .getTypeSizeInChars(VTy->getElementType())
2968 .getQuantity() *
2969 8;
2970 if (ElementBitCount != 32) {
2971 SemaRef.Diag(TheCall->getBeginLoc(),
2972 diag::err_integer_incorrect_bit_count)
2973 << 32 << ElementBitCount;
2974 return true;
2975 }
2976
2977 // ensure both args are vectors of total bit size of a multiple of 64
2978 int NumElementsArg = VTy->getNumElements();
2979 if (NumElementsArg != 2 && NumElementsArg != 4) {
2980 SemaRef.Diag(TheCall->getBeginLoc(), diag::err_vector_incorrect_bit_count)
2981 << 1 /*a multiple of*/ << 64 << NumElementsArg * ElementBitCount;
2982 return true;
2983 }
2984
2985 // ensure first arg and second arg have the same type
2986 if (CheckAllArgsHaveSameType(&SemaRef, TheCall))
2987 return true;
2988
2989 ExprResult A = TheCall->getArg(0);
2990 QualType ArgTyA = A.get()->getType();
2991 // return type is the same as the input type
2992 TheCall->setType(ArgTyA);
2993 break;
2994 }
2995 case Builtin::BI__builtin_hlsl_resource_getpointer: {
2996 if (SemaRef.checkArgCount(TheCall, 2) ||
2997 CheckResourceHandle(&SemaRef, TheCall, 0) ||
2998 CheckArgTypeMatches(&SemaRef, TheCall->getArg(1),
2999 SemaRef.getASTContext().UnsignedIntTy))
3000 return true;
3001
3002 auto *ResourceTy =
3003 TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
3004 QualType ContainedTy = ResourceTy->getContainedType();
3005 auto ReturnType =
3006 SemaRef.Context.getAddrSpaceQualType(ContainedTy, LangAS::hlsl_device);
3007 ReturnType = SemaRef.Context.getPointerType(ReturnType);
3008 TheCall->setType(ReturnType);
3009 TheCall->setValueKind(VK_LValue);
3010
3011 break;
3012 }
3013 case Builtin::BI__builtin_hlsl_resource_uninitializedhandle: {
3014 if (SemaRef.checkArgCount(TheCall, 1) ||
3015 CheckResourceHandle(&SemaRef, TheCall, 0))
3016 return true;
3017 // use the type of the handle (arg0) as a return type
3018 QualType ResourceTy = TheCall->getArg(0)->getType();
3019 TheCall->setType(ResourceTy);
3020 break;
3021 }
3022 case Builtin::BI__builtin_hlsl_resource_handlefrombinding: {
3023 ASTContext &AST = SemaRef.getASTContext();
3024 if (SemaRef.checkArgCount(TheCall, 6) ||
3025 CheckResourceHandle(&SemaRef, TheCall, 0) ||
3026 CheckArgTypeMatches(&SemaRef, TheCall->getArg(1), AST.UnsignedIntTy) ||
3027 CheckArgTypeMatches(&SemaRef, TheCall->getArg(2), AST.UnsignedIntTy) ||
3028 CheckArgTypeMatches(&SemaRef, TheCall->getArg(3), AST.IntTy) ||
3029 CheckArgTypeMatches(&SemaRef, TheCall->getArg(4), AST.UnsignedIntTy) ||
3030 CheckArgTypeMatches(&SemaRef, TheCall->getArg(5),
3031 AST.getPointerType(AST.CharTy.withConst())))
3032 return true;
3033 // use the type of the handle (arg0) as a return type
3034 QualType ResourceTy = TheCall->getArg(0)->getType();
3035 TheCall->setType(ResourceTy);
3036 break;
3037 }
3038 case Builtin::BI__builtin_hlsl_resource_handlefromimplicitbinding: {
3039 ASTContext &AST = SemaRef.getASTContext();
3040 if (SemaRef.checkArgCount(TheCall, 6) ||
3041 CheckResourceHandle(&SemaRef, TheCall, 0) ||
3042 CheckArgTypeMatches(&SemaRef, TheCall->getArg(1), AST.UnsignedIntTy) ||
3043 CheckArgTypeMatches(&SemaRef, TheCall->getArg(2), AST.UnsignedIntTy) ||
3044 CheckArgTypeMatches(&SemaRef, TheCall->getArg(3), AST.IntTy) ||
3045 CheckArgTypeMatches(&SemaRef, TheCall->getArg(4), AST.UnsignedIntTy) ||
3046 CheckArgTypeMatches(&SemaRef, TheCall->getArg(5),
3047 AST.getPointerType(AST.CharTy.withConst())))
3048 return true;
3049 // use the type of the handle (arg0) as a return type
3050 QualType ResourceTy = TheCall->getArg(0)->getType();
3051 TheCall->setType(ResourceTy);
3052 break;
3053 }
3054 case Builtin::BI__builtin_hlsl_resource_counterhandlefromimplicitbinding: {
3055 ASTContext &AST = SemaRef.getASTContext();
3056 if (SemaRef.checkArgCount(TheCall, 3) ||
3057 CheckResourceHandle(&SemaRef, TheCall, 0) ||
3058 CheckArgTypeMatches(&SemaRef, TheCall->getArg(1), AST.UnsignedIntTy) ||
3059 CheckArgTypeMatches(&SemaRef, TheCall->getArg(2), AST.UnsignedIntTy))
3060 return true;
3061
3062 QualType MainHandleTy = TheCall->getArg(0)->getType();
3063 auto *MainResType = MainHandleTy->getAs<HLSLAttributedResourceType>();
3064 auto MainAttrs = MainResType->getAttrs();
3065 assert(!MainAttrs.IsCounter && "cannot create a counter from a counter");
3066 MainAttrs.IsCounter = true;
3067 QualType CounterHandleTy = AST.getHLSLAttributedResourceType(
3068 MainResType->getWrappedType(), MainResType->getContainedType(),
3069 MainAttrs);
3070 TheCall->setType(CounterHandleTy);
3071 break;
3072 }
3073 case Builtin::BI__builtin_hlsl_resource_getdimensions_x: {
3074 ASTContext &AST = SemaRef.getASTContext();
3075 if (SemaRef.checkArgCount(TheCall, 2) ||
3076 CheckResourceHandle(&SemaRef, TheCall, 0) ||
3077 CheckArgTypeMatches(&SemaRef, TheCall->getArg(1), AST.UnsignedIntTy) ||
3078 CheckModifiableLValue(&SemaRef, TheCall, 1))
3079 return true;
3080 break;
3081 }
3082 case Builtin::BI__builtin_hlsl_resource_getstride: {
3083 ASTContext &AST = SemaRef.getASTContext();
3084 if (SemaRef.checkArgCount(TheCall, 2) ||
3085 CheckResourceHandle(&SemaRef, TheCall, 0) ||
3086 CheckArgTypeMatches(&SemaRef, TheCall->getArg(1), AST.UnsignedIntTy) ||
3087 CheckModifiableLValue(&SemaRef, TheCall, 1))
3088 return true;
3089 break;
3090 }
3091 case Builtin::BI__builtin_hlsl_and:
3092 case Builtin::BI__builtin_hlsl_or: {
3093 if (SemaRef.checkArgCount(TheCall, 2))
3094 return true;
3095 if (CheckScalarOrVector(&SemaRef, TheCall, getASTContext().BoolTy, 0))
3096 return true;
3097 if (CheckAllArgsHaveSameType(&SemaRef, TheCall))
3098 return true;
3099
3100 ExprResult A = TheCall->getArg(0);
3101 QualType ArgTyA = A.get()->getType();
3102 // return type is the same as the input type
3103 TheCall->setType(ArgTyA);
3104 break;
3105 }
3106 case Builtin::BI__builtin_hlsl_all:
3107 case Builtin::BI__builtin_hlsl_any: {
3108 if (SemaRef.checkArgCount(TheCall, 1))
3109 return true;
3110 if (CheckAnyScalarOrVector(&SemaRef, TheCall, 0))
3111 return true;
3112 break;
3113 }
3114 case Builtin::BI__builtin_hlsl_asdouble: {
3115 if (SemaRef.checkArgCount(TheCall, 2))
3116 return true;
3118 &SemaRef, TheCall,
3119 /*only check for uint*/ SemaRef.Context.UnsignedIntTy,
3120 /* arg index */ 0))
3121 return true;
3123 &SemaRef, TheCall,
3124 /*only check for uint*/ SemaRef.Context.UnsignedIntTy,
3125 /* arg index */ 1))
3126 return true;
3127 if (CheckAllArgsHaveSameType(&SemaRef, TheCall))
3128 return true;
3129
3130 SetElementTypeAsReturnType(&SemaRef, TheCall, getASTContext().DoubleTy);
3131 break;
3132 }
3133 case Builtin::BI__builtin_hlsl_elementwise_clamp: {
3134 if (SemaRef.BuiltinElementwiseTernaryMath(
3135 TheCall, /*ArgTyRestr=*/
3137 return true;
3138 break;
3139 }
3140 case Builtin::BI__builtin_hlsl_dot: {
3141 // arg count is checked by BuiltinVectorToScalarMath
3142 if (SemaRef.BuiltinVectorToScalarMath(TheCall))
3143 return true;
3145 return true;
3146 break;
3147 }
3148 case Builtin::BI__builtin_hlsl_elementwise_firstbithigh:
3149 case Builtin::BI__builtin_hlsl_elementwise_firstbitlow: {
3150 if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall))
3151 return true;
3152
3153 const Expr *Arg = TheCall->getArg(0);
3154 QualType ArgTy = Arg->getType();
3155 QualType EltTy = ArgTy;
3156
3157 QualType ResTy = SemaRef.Context.UnsignedIntTy;
3158
3159 if (auto *VecTy = EltTy->getAs<VectorType>()) {
3160 EltTy = VecTy->getElementType();
3161 ResTy = SemaRef.Context.getExtVectorType(ResTy, VecTy->getNumElements());
3162 }
3163
3164 if (!EltTy->isIntegerType()) {
3165 Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
3166 << 1 << /* scalar or vector of */ 5 << /* integer ty */ 1
3167 << /* no fp */ 0 << ArgTy;
3168 return true;
3169 }
3170
3171 TheCall->setType(ResTy);
3172 break;
3173 }
3174 case Builtin::BI__builtin_hlsl_select: {
3175 if (SemaRef.checkArgCount(TheCall, 3))
3176 return true;
3177 if (CheckScalarOrVector(&SemaRef, TheCall, getASTContext().BoolTy, 0))
3178 return true;
3179 QualType ArgTy = TheCall->getArg(0)->getType();
3180 if (ArgTy->isBooleanType() && CheckBoolSelect(&SemaRef, TheCall))
3181 return true;
3182 auto *VTy = ArgTy->getAs<VectorType>();
3183 if (VTy && VTy->getElementType()->isBooleanType() &&
3184 CheckVectorSelect(&SemaRef, TheCall))
3185 return true;
3186 break;
3187 }
3188 case Builtin::BI__builtin_hlsl_elementwise_saturate:
3189 case Builtin::BI__builtin_hlsl_elementwise_rcp: {
3190 if (SemaRef.checkArgCount(TheCall, 1))
3191 return true;
3192 if (!TheCall->getArg(0)
3193 ->getType()
3194 ->hasFloatingRepresentation()) // half or float or double
3195 return SemaRef.Diag(TheCall->getArg(0)->getBeginLoc(),
3196 diag::err_builtin_invalid_arg_type)
3197 << /* ordinal */ 1 << /* scalar or vector */ 5 << /* no int */ 0
3198 << /* fp */ 1 << TheCall->getArg(0)->getType();
3199 if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall))
3200 return true;
3201 break;
3202 }
3203 case Builtin::BI__builtin_hlsl_elementwise_degrees:
3204 case Builtin::BI__builtin_hlsl_elementwise_radians:
3205 case Builtin::BI__builtin_hlsl_elementwise_rsqrt:
3206 case Builtin::BI__builtin_hlsl_elementwise_frac: {
3207 if (SemaRef.checkArgCount(TheCall, 1))
3208 return true;
3209 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
3211 return true;
3212 if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall))
3213 return true;
3214 break;
3215 }
3216 case Builtin::BI__builtin_hlsl_elementwise_isinf:
3217 case Builtin::BI__builtin_hlsl_elementwise_isnan: {
3218 if (SemaRef.checkArgCount(TheCall, 1))
3219 return true;
3220 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
3222 return true;
3223 if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall))
3224 return true;
3226 break;
3227 }
3228 case Builtin::BI__builtin_hlsl_lerp: {
3229 if (SemaRef.checkArgCount(TheCall, 3))
3230 return true;
3231 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
3233 return true;
3234 if (CheckAllArgsHaveSameType(&SemaRef, TheCall))
3235 return true;
3236 if (SemaRef.BuiltinElementwiseTernaryMath(TheCall))
3237 return true;
3238 break;
3239 }
3240 case Builtin::BI__builtin_hlsl_mad: {
3241 if (SemaRef.BuiltinElementwiseTernaryMath(
3242 TheCall, /*ArgTyRestr=*/
3244 return true;
3245 break;
3246 }
3247 case Builtin::BI__builtin_hlsl_normalize: {
3248 if (SemaRef.checkArgCount(TheCall, 1))
3249 return true;
3250 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
3252 return true;
3253 ExprResult A = TheCall->getArg(0);
3254 QualType ArgTyA = A.get()->getType();
3255 // return type is the same as the input type
3256 TheCall->setType(ArgTyA);
3257 break;
3258 }
3259 case Builtin::BI__builtin_hlsl_elementwise_sign: {
3260 if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall))
3261 return true;
3262 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
3264 return true;
3266 break;
3267 }
3268 case Builtin::BI__builtin_hlsl_step: {
3269 if (SemaRef.checkArgCount(TheCall, 2))
3270 return true;
3271 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
3273 return true;
3274
3275 ExprResult A = TheCall->getArg(0);
3276 QualType ArgTyA = A.get()->getType();
3277 // return type is the same as the input type
3278 TheCall->setType(ArgTyA);
3279 break;
3280 }
3281 case Builtin::BI__builtin_hlsl_wave_active_max:
3282 case Builtin::BI__builtin_hlsl_wave_active_sum: {
3283 if (SemaRef.checkArgCount(TheCall, 1))
3284 return true;
3285
3286 // Ensure input expr type is a scalar/vector and the same as the return type
3287 if (CheckAnyScalarOrVector(&SemaRef, TheCall, 0))
3288 return true;
3289 if (CheckWaveActive(&SemaRef, TheCall))
3290 return true;
3291 ExprResult Expr = TheCall->getArg(0);
3292 QualType ArgTyExpr = Expr.get()->getType();
3293 TheCall->setType(ArgTyExpr);
3294 break;
3295 }
3296 // Note these are llvm builtins that we want to catch invalid intrinsic
3297 // generation. Normal handling of these builitns will occur elsewhere.
3298 case Builtin::BI__builtin_elementwise_bitreverse: {
3299 // does not include a check for number of arguments
3300 // because that is done previously
3301 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
3303 return true;
3304 break;
3305 }
3306 case Builtin::BI__builtin_hlsl_wave_read_lane_at: {
3307 if (SemaRef.checkArgCount(TheCall, 2))
3308 return true;
3309
3310 // Ensure index parameter type can be interpreted as a uint
3311 ExprResult Index = TheCall->getArg(1);
3312 QualType ArgTyIndex = Index.get()->getType();
3313 if (!ArgTyIndex->isIntegerType()) {
3314 SemaRef.Diag(TheCall->getArg(1)->getBeginLoc(),
3315 diag::err_typecheck_convert_incompatible)
3316 << ArgTyIndex << SemaRef.Context.UnsignedIntTy << 1 << 0 << 0;
3317 return true;
3318 }
3319
3320 // Ensure input expr type is a scalar/vector and the same as the return type
3321 if (CheckAnyScalarOrVector(&SemaRef, TheCall, 0))
3322 return true;
3323
3324 ExprResult Expr = TheCall->getArg(0);
3325 QualType ArgTyExpr = Expr.get()->getType();
3326 TheCall->setType(ArgTyExpr);
3327 break;
3328 }
3329 case Builtin::BI__builtin_hlsl_wave_get_lane_index: {
3330 if (SemaRef.checkArgCount(TheCall, 0))
3331 return true;
3332 break;
3333 }
3334 case Builtin::BI__builtin_hlsl_elementwise_splitdouble: {
3335 if (SemaRef.checkArgCount(TheCall, 3))
3336 return true;
3337
3338 if (CheckScalarOrVector(&SemaRef, TheCall, SemaRef.Context.DoubleTy, 0) ||
3339 CheckScalarOrVector(&SemaRef, TheCall, SemaRef.Context.UnsignedIntTy,
3340 1) ||
3341 CheckScalarOrVector(&SemaRef, TheCall, SemaRef.Context.UnsignedIntTy,
3342 2))
3343 return true;
3344
3345 if (CheckModifiableLValue(&SemaRef, TheCall, 1) ||
3346 CheckModifiableLValue(&SemaRef, TheCall, 2))
3347 return true;
3348 break;
3349 }
3350 case Builtin::BI__builtin_hlsl_elementwise_clip: {
3351 if (SemaRef.checkArgCount(TheCall, 1))
3352 return true;
3353
3354 if (CheckScalarOrVector(&SemaRef, TheCall, SemaRef.Context.FloatTy, 0))
3355 return true;
3356 break;
3357 }
3358 case Builtin::BI__builtin_elementwise_acos:
3359 case Builtin::BI__builtin_elementwise_asin:
3360 case Builtin::BI__builtin_elementwise_atan:
3361 case Builtin::BI__builtin_elementwise_atan2:
3362 case Builtin::BI__builtin_elementwise_ceil:
3363 case Builtin::BI__builtin_elementwise_cos:
3364 case Builtin::BI__builtin_elementwise_cosh:
3365 case Builtin::BI__builtin_elementwise_exp:
3366 case Builtin::BI__builtin_elementwise_exp2:
3367 case Builtin::BI__builtin_elementwise_exp10:
3368 case Builtin::BI__builtin_elementwise_floor:
3369 case Builtin::BI__builtin_elementwise_fmod:
3370 case Builtin::BI__builtin_elementwise_log:
3371 case Builtin::BI__builtin_elementwise_log2:
3372 case Builtin::BI__builtin_elementwise_log10:
3373 case Builtin::BI__builtin_elementwise_pow:
3374 case Builtin::BI__builtin_elementwise_roundeven:
3375 case Builtin::BI__builtin_elementwise_sin:
3376 case Builtin::BI__builtin_elementwise_sinh:
3377 case Builtin::BI__builtin_elementwise_sqrt:
3378 case Builtin::BI__builtin_elementwise_tan:
3379 case Builtin::BI__builtin_elementwise_tanh:
3380 case Builtin::BI__builtin_elementwise_trunc: {
3381 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
3383 return true;
3384 break;
3385 }
3386 case Builtin::BI__builtin_hlsl_buffer_update_counter: {
3387 auto checkResTy = [](const HLSLAttributedResourceType *ResTy) -> bool {
3388 return !(ResTy->getAttrs().ResourceClass == ResourceClass::UAV &&
3389 ResTy->getAttrs().RawBuffer && ResTy->hasContainedType());
3390 };
3391 if (SemaRef.checkArgCount(TheCall, 2) ||
3392 CheckResourceHandle(&SemaRef, TheCall, 0, checkResTy) ||
3393 CheckArgTypeMatches(&SemaRef, TheCall->getArg(1),
3394 SemaRef.getASTContext().IntTy))
3395 return true;
3396 Expr *OffsetExpr = TheCall->getArg(1);
3397 std::optional<llvm::APSInt> Offset =
3398 OffsetExpr->getIntegerConstantExpr(SemaRef.getASTContext());
3399 if (!Offset.has_value() || std::abs(Offset->getExtValue()) != 1) {
3400 SemaRef.Diag(TheCall->getArg(1)->getBeginLoc(),
3401 diag::err_hlsl_expect_arg_const_int_one_or_neg_one)
3402 << 1;
3403 return true;
3404 }
3405 break;
3406 }
3407 }
3408 return false;
3409}
3410
3414 WorkList.push_back(BaseTy);
3415 while (!WorkList.empty()) {
3416 QualType T = WorkList.pop_back_val();
3417 T = T.getCanonicalType().getUnqualifiedType();
3418 if (const auto *AT = dyn_cast<ConstantArrayType>(T)) {
3419 llvm::SmallVector<QualType, 16> ElementFields;
3420 // Generally I've avoided recursion in this algorithm, but arrays of
3421 // structs could be time-consuming to flatten and churn through on the
3422 // work list. Hopefully nesting arrays of structs containing arrays
3423 // of structs too many levels deep is unlikely.
3424 BuildFlattenedTypeList(AT->getElementType(), ElementFields);
3425 // Repeat the element's field list n times.
3426 for (uint64_t Ct = 0; Ct < AT->getZExtSize(); ++Ct)
3427 llvm::append_range(List, ElementFields);
3428 continue;
3429 }
3430 // Vectors can only have element types that are builtin types, so this can
3431 // add directly to the list instead of to the WorkList.
3432 if (const auto *VT = dyn_cast<VectorType>(T)) {
3433 List.insert(List.end(), VT->getNumElements(), VT->getElementType());
3434 continue;
3435 }
3436 if (const auto *MT = dyn_cast<ConstantMatrixType>(T)) {
3437 List.insert(List.end(), MT->getNumElementsFlattened(),
3438 MT->getElementType());
3439 continue;
3440 }
3441 if (const auto *RD = T->getAsCXXRecordDecl()) {
3442 if (RD->isStandardLayout())
3443 RD = RD->getStandardLayoutBaseWithFields();
3444
3445 // For types that we shouldn't decompose (unions and non-aggregates), just
3446 // add the type itself to the list.
3447 if (RD->isUnion() || !RD->isAggregate()) {
3448 List.push_back(T);
3449 continue;
3450 }
3451
3453 for (const auto *FD : RD->fields())
3454 if (!FD->isUnnamedBitField())
3455 FieldTypes.push_back(FD->getType());
3456 // Reverse the newly added sub-range.
3457 std::reverse(FieldTypes.begin(), FieldTypes.end());
3458 llvm::append_range(WorkList, FieldTypes);
3459
3460 // If this wasn't a standard layout type we may also have some base
3461 // classes to deal with.
3462 if (!RD->isStandardLayout()) {
3463 FieldTypes.clear();
3464 for (const auto &Base : RD->bases())
3465 FieldTypes.push_back(Base.getType());
3466 std::reverse(FieldTypes.begin(), FieldTypes.end());
3467 llvm::append_range(WorkList, FieldTypes);
3468 }
3469 continue;
3470 }
3471 List.push_back(T);
3472 }
3473}
3474
3476 // null and array types are not allowed.
3477 if (QT.isNull() || QT->isArrayType())
3478 return false;
3479
3480 // UDT types are not allowed
3481 if (QT->isRecordType())
3482 return false;
3483
3484 if (QT->isBooleanType() || QT->isEnumeralType())
3485 return false;
3486
3487 // the only other valid builtin types are scalars or vectors
3488 if (QT->isArithmeticType()) {
3489 if (SemaRef.Context.getTypeSize(QT) / 8 > 16)
3490 return false;
3491 return true;
3492 }
3493
3494 if (const VectorType *VT = QT->getAs<VectorType>()) {
3495 int ArraySize = VT->getNumElements();
3496
3497 if (ArraySize > 4)
3498 return false;
3499
3500 QualType ElTy = VT->getElementType();
3501 if (ElTy->isBooleanType())
3502 return false;
3503
3504 if (SemaRef.Context.getTypeSize(QT) / 8 > 16)
3505 return false;
3506 return true;
3507 }
3508
3509 return false;
3510}
3511
3513 if (T1.isNull() || T2.isNull())
3514 return false;
3515
3518
3519 // If both types are the same canonical type, they're obviously compatible.
3520 if (SemaRef.getASTContext().hasSameType(T1, T2))
3521 return true;
3522
3524 BuildFlattenedTypeList(T1, T1Types);
3526 BuildFlattenedTypeList(T2, T2Types);
3527
3528 // Check the flattened type list
3529 return llvm::equal(T1Types, T2Types,
3530 [this](QualType LHS, QualType RHS) -> bool {
3531 return SemaRef.IsLayoutCompatible(LHS, RHS);
3532 });
3533}
3534
3536 FunctionDecl *Old) {
3537 if (New->getNumParams() != Old->getNumParams())
3538 return true;
3539
3540 bool HadError = false;
3541
3542 for (unsigned i = 0, e = New->getNumParams(); i != e; ++i) {
3543 ParmVarDecl *NewParam = New->getParamDecl(i);
3544 ParmVarDecl *OldParam = Old->getParamDecl(i);
3545
3546 // HLSL parameter declarations for inout and out must match between
3547 // declarations. In HLSL inout and out are ambiguous at the call site,
3548 // but have different calling behavior, so you cannot overload a
3549 // method based on a difference between inout and out annotations.
3550 const auto *NDAttr = NewParam->getAttr<HLSLParamModifierAttr>();
3551 unsigned NSpellingIdx = (NDAttr ? NDAttr->getSpellingListIndex() : 0);
3552 const auto *ODAttr = OldParam->getAttr<HLSLParamModifierAttr>();
3553 unsigned OSpellingIdx = (ODAttr ? ODAttr->getSpellingListIndex() : 0);
3554
3555 if (NSpellingIdx != OSpellingIdx) {
3556 SemaRef.Diag(NewParam->getLocation(),
3557 diag::err_hlsl_param_qualifier_mismatch)
3558 << NDAttr << NewParam;
3559 SemaRef.Diag(OldParam->getLocation(), diag::note_previous_declaration_as)
3560 << ODAttr;
3561 HadError = true;
3562 }
3563 }
3564 return HadError;
3565}
3566
3567// Generally follows PerformScalarCast, with cases reordered for
3568// clarity of what types are supported
3570
3571 if (!SrcTy->isScalarType() || !DestTy->isScalarType())
3572 return false;
3573
3574 if (SemaRef.getASTContext().hasSameUnqualifiedType(SrcTy, DestTy))
3575 return true;
3576
3577 switch (SrcTy->getScalarTypeKind()) {
3578 case Type::STK_Bool: // casting from bool is like casting from an integer
3579 case Type::STK_Integral:
3580 switch (DestTy->getScalarTypeKind()) {
3581 case Type::STK_Bool:
3582 case Type::STK_Integral:
3583 case Type::STK_Floating:
3584 return true;
3585 case Type::STK_CPointer:
3589 llvm_unreachable("HLSL doesn't support pointers.");
3592 llvm_unreachable("HLSL doesn't support complex types.");
3594 llvm_unreachable("HLSL doesn't support fixed point types.");
3595 }
3596 llvm_unreachable("Should have returned before this");
3597
3598 case Type::STK_Floating:
3599 switch (DestTy->getScalarTypeKind()) {
3600 case Type::STK_Floating:
3601 case Type::STK_Bool:
3602 case Type::STK_Integral:
3603 return true;
3606 llvm_unreachable("HLSL doesn't support complex types.");
3608 llvm_unreachable("HLSL doesn't support fixed point types.");
3609 case Type::STK_CPointer:
3613 llvm_unreachable("HLSL doesn't support pointers.");
3614 }
3615 llvm_unreachable("Should have returned before this");
3616
3618 case Type::STK_CPointer:
3621 llvm_unreachable("HLSL doesn't support pointers.");
3622
3624 llvm_unreachable("HLSL doesn't support fixed point types.");
3625
3628 llvm_unreachable("HLSL doesn't support complex types.");
3629 }
3630
3631 llvm_unreachable("Unhandled scalar cast");
3632}
3633
3634// Can perform an HLSL Aggregate splat cast if the Dest is an aggregate and the
3635// Src is a scalar or a vector of length 1
3636// Or if Dest is a vector and Src is a vector of length 1
3638
3639 QualType SrcTy = Src->getType();
3640 // Not a valid HLSL Aggregate Splat cast if Dest is a scalar or if this is
3641 // going to be a vector splat from a scalar.
3642 if ((SrcTy->isScalarType() && DestTy->isVectorType()) ||
3643 DestTy->isScalarType())
3644 return false;
3645
3646 const VectorType *SrcVecTy = SrcTy->getAs<VectorType>();
3647
3648 // Src isn't a scalar or a vector of length 1
3649 if (!SrcTy->isScalarType() && !(SrcVecTy && SrcVecTy->getNumElements() == 1))
3650 return false;
3651
3652 if (SrcVecTy)
3653 SrcTy = SrcVecTy->getElementType();
3654
3656 BuildFlattenedTypeList(DestTy, DestTypes);
3657
3658 for (unsigned I = 0, Size = DestTypes.size(); I < Size; ++I) {
3659 if (DestTypes[I]->isUnionType())
3660 return false;
3661 if (!CanPerformScalarCast(SrcTy, DestTypes[I]))
3662 return false;
3663 }
3664 return true;
3665}
3666
3667// Can we perform an HLSL Elementwise cast?
3668// TODO: update this code when matrices are added; see issue #88060
3670
3671 // Don't handle casts where LHS and RHS are any combination of scalar/vector
3672 // There must be an aggregate somewhere
3673 QualType SrcTy = Src->getType();
3674 if (SrcTy->isScalarType()) // always a splat and this cast doesn't handle that
3675 return false;
3676
3677 if (SrcTy->isVectorType() &&
3678 (DestTy->isScalarType() || DestTy->isVectorType()))
3679 return false;
3680
3682 BuildFlattenedTypeList(DestTy, DestTypes);
3684 BuildFlattenedTypeList(SrcTy, SrcTypes);
3685
3686 // Usually the size of SrcTypes must be greater than or equal to the size of
3687 // DestTypes.
3688 if (SrcTypes.size() < DestTypes.size())
3689 return false;
3690
3691 unsigned SrcSize = SrcTypes.size();
3692 unsigned DstSize = DestTypes.size();
3693 unsigned I;
3694 for (I = 0; I < DstSize && I < SrcSize; I++) {
3695 if (SrcTypes[I]->isUnionType() || DestTypes[I]->isUnionType())
3696 return false;
3697 if (!CanPerformScalarCast(SrcTypes[I], DestTypes[I])) {
3698 return false;
3699 }
3700 }
3701
3702 // check the rest of the source type for unions.
3703 for (; I < SrcSize; I++) {
3704 if (SrcTypes[I]->isUnionType())
3705 return false;
3706 }
3707 return true;
3708}
3709
3711 assert(Param->hasAttr<HLSLParamModifierAttr>() &&
3712 "We should not get here without a parameter modifier expression");
3713 const auto *Attr = Param->getAttr<HLSLParamModifierAttr>();
3714 if (Attr->getABI() == ParameterABI::Ordinary)
3715 return ExprResult(Arg);
3716
3717 bool IsInOut = Attr->getABI() == ParameterABI::HLSLInOut;
3718 if (!Arg->isLValue()) {
3719 SemaRef.Diag(Arg->getBeginLoc(), diag::error_hlsl_inout_lvalue)
3720 << Arg << (IsInOut ? 1 : 0);
3721 return ExprError();
3722 }
3723
3724 ASTContext &Ctx = SemaRef.getASTContext();
3725
3726 QualType Ty = Param->getType().getNonLValueExprType(Ctx);
3727
3728 // HLSL allows implicit conversions from scalars to vectors, but not the
3729 // inverse, so we need to disallow `inout` with scalar->vector or
3730 // scalar->matrix conversions.
3731 if (Arg->getType()->isScalarType() != Ty->isScalarType()) {
3732 SemaRef.Diag(Arg->getBeginLoc(), diag::error_hlsl_inout_scalar_extension)
3733 << Arg << (IsInOut ? 1 : 0);
3734 return ExprError();
3735 }
3736
3737 auto *ArgOpV = new (Ctx) OpaqueValueExpr(Param->getBeginLoc(), Arg->getType(),
3738 VK_LValue, OK_Ordinary, Arg);
3739
3740 // Parameters are initialized via copy initialization. This allows for
3741 // overload resolution of argument constructors.
3742 InitializedEntity Entity =
3744 ExprResult Res =
3745 SemaRef.PerformCopyInitialization(Entity, Param->getBeginLoc(), ArgOpV);
3746 if (Res.isInvalid())
3747 return ExprError();
3748 Expr *Base = Res.get();
3749 // After the cast, drop the reference type when creating the exprs.
3750 Ty = Ty.getNonLValueExprType(Ctx);
3751 auto *OpV = new (Ctx)
3752 OpaqueValueExpr(Param->getBeginLoc(), Ty, VK_LValue, OK_Ordinary, Base);
3753
3754 // Writebacks are performed with `=` binary operator, which allows for
3755 // overload resolution on writeback result expressions.
3756 Res = SemaRef.ActOnBinOp(SemaRef.getCurScope(), Param->getBeginLoc(),
3757 tok::equal, ArgOpV, OpV);
3758
3759 if (Res.isInvalid())
3760 return ExprError();
3761 Expr *Writeback = Res.get();
3762 auto *OutExpr =
3763 HLSLOutArgExpr::Create(Ctx, Ty, ArgOpV, OpV, Writeback, IsInOut);
3764
3765 return ExprResult(OutExpr);
3766}
3767
3769 // If HLSL gains support for references, all the cites that use this will need
3770 // to be updated with semantic checking to produce errors for
3771 // pointers/references.
3772 assert(!Ty->isReferenceType() &&
3773 "Pointer and reference types cannot be inout or out parameters");
3774 Ty = SemaRef.getASTContext().getLValueReferenceType(Ty);
3775 Ty.addRestrict();
3776 return Ty;
3777}
3778
3780 QualType QT = VD->getType();
3781 return VD->getDeclContext()->isTranslationUnit() &&
3783 VD->getStorageClass() != SC_Static &&
3784 !VD->hasAttr<HLSLVkConstantIdAttr>() &&
3786}
3787
3789 // The variable already has an address space (groupshared for ex).
3790 if (Decl->getType().hasAddressSpace())
3791 return;
3792
3793 if (Decl->getType()->isDependentType())
3794 return;
3795
3796 QualType Type = Decl->getType();
3797
3798 if (Decl->hasAttr<HLSLVkExtBuiltinInputAttr>()) {
3799 LangAS ImplAS = LangAS::hlsl_input;
3800 Type = SemaRef.getASTContext().getAddrSpaceQualType(Type, ImplAS);
3801 Decl->setType(Type);
3802 return;
3803 }
3804
3805 if (Type->isSamplerT() || Type->isVoidType())
3806 return;
3807
3808 // Resource handles.
3810 return;
3811
3812 // Only static globals belong to the Private address space.
3813 // Non-static globals belongs to the cbuffer.
3814 if (Decl->getStorageClass() != SC_Static && !Decl->isStaticDataMember())
3815 return;
3816
3818 Type = SemaRef.getASTContext().getAddrSpaceQualType(Type, ImplAS);
3819 Decl->setType(Type);
3820}
3821
3823 if (VD->hasGlobalStorage()) {
3824 // make sure the declaration has a complete type
3825 if (SemaRef.RequireCompleteType(
3826 VD->getLocation(),
3827 SemaRef.getASTContext().getBaseElementType(VD->getType()),
3828 diag::err_typecheck_decl_incomplete_type)) {
3829 VD->setInvalidDecl();
3831 return;
3832 }
3833
3834 // Global variables outside a cbuffer block that are not a resource, static,
3835 // groupshared, or an empty array or struct belong to the default constant
3836 // buffer $Globals (to be created at the end of the translation unit).
3838 // update address space to hlsl_constant
3841 VD->setType(NewTy);
3842 DefaultCBufferDecls.push_back(VD);
3843 }
3844
3845 // find all resources bindings on decl
3846 if (VD->getType()->isHLSLIntangibleType())
3847 collectResourceBindingsOnVarDecl(VD);
3848
3850 VD->hasAttr<HLSLVkConstantIdAttr>()) {
3851 // Make the variable for resources static. The global externally visible
3852 // storage is accessed through the handle, which is a member. The variable
3853 // itself is not externally visible.
3855 }
3856
3857 // process explicit bindings
3858 processExplicitBindingsOnDecl(VD);
3859
3860 if (VD->getType()->isHLSLResourceRecordArray()) {
3861 // If the resource array does not have an explicit binding attribute,
3862 // create an implicit one. It will be used to transfer implicit binding
3863 // order_ID to codegen.
3864 ResourceBindingAttrs Binding(VD);
3865 if (!Binding.isExplicit()) {
3866 uint32_t OrderID = getNextImplicitBindingOrderID();
3867 if (Binding.hasBinding())
3868 Binding.setImplicitOrderID(OrderID);
3869 else {
3872 OrderID);
3873 // Re-create the binding object to pick up the new attribute.
3874 Binding = ResourceBindingAttrs(VD);
3875 }
3876 }
3877
3878 // Get to the base type of a potentially multi-dimensional array.
3880
3881 const CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
3882 if (hasCounterHandle(RD)) {
3883 if (!Binding.hasCounterImplicitOrderID()) {
3884 uint32_t OrderID = getNextImplicitBindingOrderID();
3885 Binding.setCounterImplicitOrderID(OrderID);
3886 }
3887 }
3888 }
3889 }
3890
3892}
3893
3894bool SemaHLSL::initGlobalResourceDecl(VarDecl *VD) {
3895 assert(VD->getType()->isHLSLResourceRecord() &&
3896 "expected resource record type");
3897
3899 uint64_t UIntTySize = AST.getTypeSize(AST.UnsignedIntTy);
3900 uint64_t IntTySize = AST.getTypeSize(AST.IntTy);
3901
3902 // Gather resource binding attributes.
3903 ResourceBindingAttrs Binding(VD);
3904
3905 // Find correct initialization method and create its arguments.
3906 QualType ResourceTy = VD->getType();
3907 CXXRecordDecl *ResourceDecl = ResourceTy->getAsCXXRecordDecl();
3908 CXXMethodDecl *CreateMethod = nullptr;
3910
3911 bool HasCounter = hasCounterHandle(ResourceDecl);
3912 const char *CreateMethodName;
3913 if (Binding.isExplicit())
3914 CreateMethodName = HasCounter ? "__createFromBindingWithImplicitCounter"
3915 : "__createFromBinding";
3916 else
3917 CreateMethodName = HasCounter
3918 ? "__createFromImplicitBindingWithImplicitCounter"
3919 : "__createFromImplicitBinding";
3920
3921 CreateMethod =
3922 lookupMethod(SemaRef, ResourceDecl, CreateMethodName, VD->getLocation());
3923
3924 if (!CreateMethod)
3925 // This can happen if someone creates a struct that looks like an HLSL
3926 // resource record but does not have the required static create method.
3927 // No binding will be generated for it.
3928 return false;
3929
3930 if (Binding.isExplicit()) {
3931 IntegerLiteral *RegSlot =
3932 IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, Binding.getSlot()),
3934 Args.push_back(RegSlot);
3935 } else {
3936 uint32_t OrderID = (Binding.hasImplicitOrderID())
3937 ? Binding.getImplicitOrderID()
3938 : getNextImplicitBindingOrderID();
3939 IntegerLiteral *OrderId =
3940 IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, OrderID),
3942 Args.push_back(OrderId);
3943 }
3944
3945 IntegerLiteral *Space =
3946 IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, Binding.getSpace()),
3947 AST.UnsignedIntTy, SourceLocation());
3948 Args.push_back(Space);
3949
3950 IntegerLiteral *RangeSize = IntegerLiteral::Create(
3951 AST, llvm::APInt(IntTySize, 1), AST.IntTy, SourceLocation());
3952 Args.push_back(RangeSize);
3953
3954 IntegerLiteral *Index = IntegerLiteral::Create(
3955 AST, llvm::APInt(UIntTySize, 0), AST.UnsignedIntTy, SourceLocation());
3956 Args.push_back(Index);
3957
3958 StringRef VarName = VD->getName();
3959 StringLiteral *Name = StringLiteral::Create(
3960 AST, VarName, StringLiteralKind::Ordinary, false,
3961 AST.getStringLiteralArrayType(AST.CharTy.withConst(), VarName.size()),
3962 SourceLocation());
3963 ImplicitCastExpr *NameCast = ImplicitCastExpr::Create(
3964 AST, AST.getPointerType(AST.CharTy.withConst()), CK_ArrayToPointerDecay,
3965 Name, nullptr, VK_PRValue, FPOptionsOverride());
3966 Args.push_back(NameCast);
3967
3968 if (HasCounter) {
3969 // Will this be in the correct order?
3970 uint32_t CounterOrderID = getNextImplicitBindingOrderID();
3971 IntegerLiteral *CounterId =
3972 IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, CounterOrderID),
3973 AST.UnsignedIntTy, SourceLocation());
3974 Args.push_back(CounterId);
3975 }
3976
3977 // Make sure the create method template is instantiated and emitted.
3978 if (!CreateMethod->isDefined() && CreateMethod->isTemplateInstantiation())
3979 SemaRef.InstantiateFunctionDefinition(VD->getLocation(), CreateMethod,
3980 true);
3981
3982 // Create CallExpr with a call to the static method and set it as the decl
3983 // initialization.
3984 DeclRefExpr *DRE = DeclRefExpr::Create(
3985 AST, NestedNameSpecifierLoc(), SourceLocation(), CreateMethod, false,
3986 CreateMethod->getNameInfo(), CreateMethod->getType(), VK_PRValue);
3987
3988 auto *ImpCast = ImplicitCastExpr::Create(
3989 AST, AST.getPointerType(CreateMethod->getType()),
3990 CK_FunctionToPointerDecay, DRE, nullptr, VK_PRValue, FPOptionsOverride());
3991
3992 CallExpr *InitExpr =
3993 CallExpr::Create(AST, ImpCast, Args, ResourceTy, VK_PRValue,
3994 SourceLocation(), FPOptionsOverride());
3995 VD->setInit(InitExpr);
3997 SemaRef.CheckCompleteVariableDeclaration(VD);
3998 return true;
3999}
4000
4001bool SemaHLSL::initGlobalResourceArrayDecl(VarDecl *VD) {
4002 assert(VD->getType()->isHLSLResourceRecordArray() &&
4003 "expected array of resource records");
4004
4005 // Individual resources in a resource array are not initialized here. They
4006 // are initialized later on during codegen when the individual resources are
4007 // accessed. Codegen will emit a call to the resource initialization method
4008 // with the specified array index. We need to make sure though that the method
4009 // for the specific resource type is instantiated, so codegen can emit a call
4010 // to it when the array element is accessed.
4011
4012 // Find correct initialization method based on the resource binding
4013 // information.
4014 ASTContext &AST = SemaRef.getASTContext();
4015 QualType ResElementTy = AST.getBaseElementType(VD->getType());
4016 CXXRecordDecl *ResourceDecl = ResElementTy->getAsCXXRecordDecl();
4017 CXXMethodDecl *CreateMethod = nullptr;
4018
4019 bool HasCounter = hasCounterHandle(ResourceDecl);
4020 ResourceBindingAttrs ResourceAttrs(VD);
4021 if (ResourceAttrs.isExplicit())
4022 // Resource has explicit binding.
4023 CreateMethod =
4024 lookupMethod(SemaRef, ResourceDecl,
4025 HasCounter ? "__createFromBindingWithImplicitCounter"
4026 : "__createFromBinding",
4027 VD->getLocation());
4028 else
4029 // Resource has implicit binding.
4030 CreateMethod = lookupMethod(
4031 SemaRef, ResourceDecl,
4032 HasCounter ? "__createFromImplicitBindingWithImplicitCounter"
4033 : "__createFromImplicitBinding",
4034 VD->getLocation());
4035
4036 if (!CreateMethod)
4037 return false;
4038
4039 // Make sure the create method template is instantiated and emitted.
4040 if (!CreateMethod->isDefined() && CreateMethod->isTemplateInstantiation())
4041 SemaRef.InstantiateFunctionDefinition(VD->getLocation(), CreateMethod,
4042 true);
4043 return true;
4044}
4045
4046// Returns true if the initialization has been handled.
4047// Returns false to use default initialization.
4049 // Objects in the hlsl_constant address space are initialized
4050 // externally, so don't synthesize an implicit initializer.
4052 return true;
4053
4054 // Initialize resources at the global scope
4055 if (VD->hasGlobalStorage()) {
4056 const Type *Ty = VD->getType().getTypePtr();
4057 if (Ty->isHLSLResourceRecord())
4058 return initGlobalResourceDecl(VD);
4059 if (Ty->isHLSLResourceRecordArray())
4060 return initGlobalResourceArrayDecl(VD);
4061 }
4062 return false;
4063}
4064
4065// Return true if everything is ok; returns false if there was an error.
4067 Expr *RHSExpr, SourceLocation Loc) {
4068 assert((LHSExpr->getType()->isHLSLResourceRecord() ||
4069 LHSExpr->getType()->isHLSLResourceRecordArray()) &&
4070 "expected LHS to be a resource record or array of resource records");
4071 if (Opc != BO_Assign)
4072 return true;
4073
4074 // If LHS is an array subscript, get the underlying declaration.
4075 Expr *E = LHSExpr;
4076 while (auto *ASE = dyn_cast<ArraySubscriptExpr>(E))
4077 E = ASE->getBase()->IgnoreParenImpCasts();
4078
4079 // Report error if LHS is a resource declared at a global scope.
4080 if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParens())) {
4081 if (VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
4082 if (VD->hasGlobalStorage()) {
4083 // assignment to global resource is not allowed
4084 SemaRef.Diag(Loc, diag::err_hlsl_assign_to_global_resource) << VD;
4085 SemaRef.Diag(VD->getLocation(), diag::note_var_declared_here) << VD;
4086 return false;
4087 }
4088 }
4089 }
4090 return true;
4091}
4092
4093// Walks though the global variable declaration, collects all resource binding
4094// requirements and adds them to Bindings
4095void SemaHLSL::collectResourceBindingsOnVarDecl(VarDecl *VD) {
4096 assert(VD->hasGlobalStorage() && VD->getType()->isHLSLIntangibleType() &&
4097 "expected global variable that contains HLSL resource");
4098
4099 // Cbuffers and Tbuffers are HLSLBufferDecl types
4100 if (const HLSLBufferDecl *CBufferOrTBuffer = dyn_cast<HLSLBufferDecl>(VD)) {
4101 Bindings.addDeclBindingInfo(VD, CBufferOrTBuffer->isCBuffer()
4102 ? ResourceClass::CBuffer
4103 : ResourceClass::SRV);
4104 return;
4105 }
4106
4107 // Unwrap arrays
4108 // FIXME: Calculate array size while unwrapping
4109 const Type *Ty = VD->getType()->getUnqualifiedDesugaredType();
4110 while (Ty->isArrayType()) {
4111 const ArrayType *AT = cast<ArrayType>(Ty);
4113 }
4114
4115 // Resource (or array of resources)
4116 if (const HLSLAttributedResourceType *AttrResType =
4117 HLSLAttributedResourceType::findHandleTypeOnResource(Ty)) {
4118 Bindings.addDeclBindingInfo(VD, AttrResType->getAttrs().ResourceClass);
4119 return;
4120 }
4121
4122 // User defined record type
4123 if (const RecordType *RT = dyn_cast<RecordType>(Ty))
4124 collectResourceBindingsOnUserRecordDecl(VD, RT);
4125}
4126
4127// Walks though the explicit resource binding attributes on the declaration,
4128// and makes sure there is a resource that matched the binding and updates
4129// DeclBindingInfoLists
4130void SemaHLSL::processExplicitBindingsOnDecl(VarDecl *VD) {
4131 assert(VD->hasGlobalStorage() && "expected global variable");
4132
4133 bool HasBinding = false;
4134 for (Attr *A : VD->attrs()) {
4136 HasBinding = true;
4137
4138 HLSLResourceBindingAttr *RBA = dyn_cast<HLSLResourceBindingAttr>(A);
4139 if (!RBA || !RBA->hasRegisterSlot())
4140 continue;
4141 HasBinding = true;
4142
4143 RegisterType RT = RBA->getRegisterType();
4144 assert(RT != RegisterType::I && "invalid or obsolete register type should "
4145 "never have an attribute created");
4146
4147 if (RT == RegisterType::C) {
4148 if (Bindings.hasBindingInfoForDecl(VD))
4149 SemaRef.Diag(VD->getLocation(),
4150 diag::warn_hlsl_user_defined_type_missing_member)
4151 << static_cast<int>(RT);
4152 continue;
4153 }
4154
4155 // Find DeclBindingInfo for this binding and update it, or report error
4156 // if it does not exist (user type does to contain resources with the
4157 // expected resource class).
4159 if (DeclBindingInfo *BI = Bindings.getDeclBindingInfo(VD, RC)) {
4160 // update binding info
4161 BI->setBindingAttribute(RBA, BindingType::Explicit);
4162 } else {
4163 SemaRef.Diag(VD->getLocation(),
4164 diag::warn_hlsl_user_defined_type_missing_member)
4165 << static_cast<int>(RT);
4166 }
4167 }
4168
4169 if (!HasBinding && isResourceRecordTypeOrArrayOf(VD))
4170 SemaRef.Diag(VD->getLocation(), diag::warn_hlsl_implicit_binding);
4171}
4172namespace {
4173class InitListTransformer {
4174 Sema &S;
4175 ASTContext &Ctx;
4176 QualType InitTy;
4177 QualType *DstIt = nullptr;
4178 Expr **ArgIt = nullptr;
4179 // Is wrapping the destination type iterator required? This is only used for
4180 // incomplete array types where we loop over the destination type since we
4181 // don't know the full number of elements from the declaration.
4182 bool Wrap;
4183
4184 bool castInitializer(Expr *E) {
4185 assert(DstIt && "This should always be something!");
4186 if (DstIt == DestTypes.end()) {
4187 if (!Wrap) {
4188 ArgExprs.push_back(E);
4189 // This is odd, but it isn't technically a failure due to conversion, we
4190 // handle mismatched counts of arguments differently.
4191 return true;
4192 }
4193 DstIt = DestTypes.begin();
4194 }
4195 InitializedEntity Entity = InitializedEntity::InitializeParameter(
4196 Ctx, *DstIt, /* Consumed (ObjC) */ false);
4197 ExprResult Res = S.PerformCopyInitialization(Entity, E->getBeginLoc(), E);
4198 if (Res.isInvalid())
4199 return false;
4200 Expr *Init = Res.get();
4201 ArgExprs.push_back(Init);
4202 DstIt++;
4203 return true;
4204 }
4205
4206 bool buildInitializerListImpl(Expr *E) {
4207 // If this is an initialization list, traverse the sub initializers.
4208 if (auto *Init = dyn_cast<InitListExpr>(E)) {
4209 for (auto *SubInit : Init->inits())
4210 if (!buildInitializerListImpl(SubInit))
4211 return false;
4212 return true;
4213 }
4214
4215 // If this is a scalar type, just enqueue the expression.
4216 QualType Ty = E->getType();
4217
4218 if (Ty->isScalarType() || (Ty->isRecordType() && !Ty->isAggregateType()))
4219 return castInitializer(E);
4220
4221 if (auto *VecTy = Ty->getAs<VectorType>()) {
4222 uint64_t Size = VecTy->getNumElements();
4223
4224 QualType SizeTy = Ctx.getSizeType();
4225 uint64_t SizeTySize = Ctx.getTypeSize(SizeTy);
4226 for (uint64_t I = 0; I < Size; ++I) {
4227 auto *Idx = IntegerLiteral::Create(Ctx, llvm::APInt(SizeTySize, I),
4228 SizeTy, SourceLocation());
4229
4231 E, E->getBeginLoc(), Idx, E->getEndLoc());
4232 if (ElExpr.isInvalid())
4233 return false;
4234 if (!castInitializer(ElExpr.get()))
4235 return false;
4236 }
4237 return true;
4238 }
4239 if (auto *MTy = Ty->getAs<ConstantMatrixType>()) {
4240 unsigned Rows = MTy->getNumRows();
4241 unsigned Cols = MTy->getNumColumns();
4242 QualType ElemTy = MTy->getElementType();
4243
4244 for (unsigned C = 0; C < Cols; ++C) {
4245 for (unsigned R = 0; R < Rows; ++R) {
4246 // row index literal
4247 Expr *RowIdx = IntegerLiteral::Create(
4248 Ctx, llvm::APInt(Ctx.getIntWidth(Ctx.IntTy), R), Ctx.IntTy,
4249 E->getBeginLoc());
4250 // column index literal
4251 Expr *ColIdx = IntegerLiteral::Create(
4252 Ctx, llvm::APInt(Ctx.getIntWidth(Ctx.IntTy), C), Ctx.IntTy,
4253 E->getBeginLoc());
4255 E, RowIdx, ColIdx, E->getEndLoc());
4256 if (ElExpr.isInvalid())
4257 return false;
4258 if (!castInitializer(ElExpr.get()))
4259 return false;
4260 ElExpr.get()->setType(ElemTy);
4261 }
4262 }
4263 return true;
4264 }
4265
4266 if (auto *ArrTy = dyn_cast<ConstantArrayType>(Ty.getTypePtr())) {
4267 uint64_t Size = ArrTy->getZExtSize();
4268 QualType SizeTy = Ctx.getSizeType();
4269 uint64_t SizeTySize = Ctx.getTypeSize(SizeTy);
4270 for (uint64_t I = 0; I < Size; ++I) {
4271 auto *Idx = IntegerLiteral::Create(Ctx, llvm::APInt(SizeTySize, I),
4272 SizeTy, SourceLocation());
4274 E, E->getBeginLoc(), Idx, E->getEndLoc());
4275 if (ElExpr.isInvalid())
4276 return false;
4277 if (!buildInitializerListImpl(ElExpr.get()))
4278 return false;
4279 }
4280 return true;
4281 }
4282
4283 if (auto *RD = Ty->getAsCXXRecordDecl()) {
4284 llvm::SmallVector<CXXRecordDecl *> RecordDecls;
4285 RecordDecls.push_back(RD);
4286 while (RecordDecls.back()->getNumBases()) {
4287 CXXRecordDecl *D = RecordDecls.back();
4288 assert(D->getNumBases() == 1 &&
4289 "HLSL doesn't support multiple inheritance");
4290 RecordDecls.push_back(
4292 }
4293 while (!RecordDecls.empty()) {
4294 CXXRecordDecl *RD = RecordDecls.pop_back_val();
4295 for (auto *FD : RD->fields()) {
4296 if (FD->isUnnamedBitField())
4297 continue;
4298 DeclAccessPair Found = DeclAccessPair::make(FD, FD->getAccess());
4299 DeclarationNameInfo NameInfo(FD->getDeclName(), E->getBeginLoc());
4301 E, false, E->getBeginLoc(), CXXScopeSpec(), FD, Found, NameInfo);
4302 if (Res.isInvalid())
4303 return false;
4304 if (!buildInitializerListImpl(Res.get()))
4305 return false;
4306 }
4307 }
4308 }
4309 return true;
4310 }
4311
4312 Expr *generateInitListsImpl(QualType Ty) {
4313 assert(ArgIt != ArgExprs.end() && "Something is off in iteration!");
4314 if (Ty->isScalarType() || (Ty->isRecordType() && !Ty->isAggregateType()))
4315 return *(ArgIt++);
4316
4317 llvm::SmallVector<Expr *> Inits;
4318 Ty = Ty.getDesugaredType(Ctx);
4319 if (Ty->isVectorType() || Ty->isConstantArrayType() ||
4320 Ty->isConstantMatrixType()) {
4321 QualType ElTy;
4322 uint64_t Size = 0;
4323 if (auto *ATy = Ty->getAs<VectorType>()) {
4324 ElTy = ATy->getElementType();
4325 Size = ATy->getNumElements();
4326 } else if (auto *CMTy = Ty->getAs<ConstantMatrixType>()) {
4327 ElTy = CMTy->getElementType();
4328 Size = CMTy->getNumElementsFlattened();
4329 } else {
4330 auto *VTy = cast<ConstantArrayType>(Ty.getTypePtr());
4331 ElTy = VTy->getElementType();
4332 Size = VTy->getZExtSize();
4333 }
4334 for (uint64_t I = 0; I < Size; ++I)
4335 Inits.push_back(generateInitListsImpl(ElTy));
4336 }
4337 if (auto *RD = Ty->getAsCXXRecordDecl()) {
4338 llvm::SmallVector<CXXRecordDecl *> RecordDecls;
4339 RecordDecls.push_back(RD);
4340 while (RecordDecls.back()->getNumBases()) {
4341 CXXRecordDecl *D = RecordDecls.back();
4342 assert(D->getNumBases() == 1 &&
4343 "HLSL doesn't support multiple inheritance");
4344 RecordDecls.push_back(
4346 }
4347 while (!RecordDecls.empty()) {
4348 CXXRecordDecl *RD = RecordDecls.pop_back_val();
4349 for (auto *FD : RD->fields())
4350 if (!FD->isUnnamedBitField())
4351 Inits.push_back(generateInitListsImpl(FD->getType()));
4352 }
4353 }
4354 auto *NewInit = new (Ctx) InitListExpr(Ctx, Inits.front()->getBeginLoc(),
4355 Inits, Inits.back()->getEndLoc());
4356 NewInit->setType(Ty);
4357 return NewInit;
4358 }
4359
4360public:
4361 llvm::SmallVector<QualType, 16> DestTypes;
4362 llvm::SmallVector<Expr *, 16> ArgExprs;
4363 InitListTransformer(Sema &SemaRef, const InitializedEntity &Entity)
4364 : S(SemaRef), Ctx(SemaRef.getASTContext()),
4365 Wrap(Entity.getType()->isIncompleteArrayType()) {
4366 InitTy = Entity.getType().getNonReferenceType();
4367 // When we're generating initializer lists for incomplete array types we
4368 // need to wrap around both when building the initializers and when
4369 // generating the final initializer lists.
4370 if (Wrap) {
4371 assert(InitTy->isIncompleteArrayType());
4372 const IncompleteArrayType *IAT = Ctx.getAsIncompleteArrayType(InitTy);
4373 InitTy = IAT->getElementType();
4374 }
4375 BuildFlattenedTypeList(InitTy, DestTypes);
4376 DstIt = DestTypes.begin();
4377 }
4378
4379 bool buildInitializerList(Expr *E) { return buildInitializerListImpl(E); }
4380
4381 Expr *generateInitLists() {
4382 assert(!ArgExprs.empty() &&
4383 "Call buildInitializerList to generate argument expressions.");
4384 ArgIt = ArgExprs.begin();
4385 if (!Wrap)
4386 return generateInitListsImpl(InitTy);
4387 llvm::SmallVector<Expr *> Inits;
4388 while (ArgIt != ArgExprs.end())
4389 Inits.push_back(generateInitListsImpl(InitTy));
4390
4391 auto *NewInit = new (Ctx) InitListExpr(Ctx, Inits.front()->getBeginLoc(),
4392 Inits, Inits.back()->getEndLoc());
4393 llvm::APInt ArySize(64, Inits.size());
4394 NewInit->setType(Ctx.getConstantArrayType(InitTy, ArySize, nullptr,
4395 ArraySizeModifier::Normal, 0));
4396 return NewInit;
4397 }
4398};
4399} // namespace
4400
4402 InitListExpr *Init) {
4403 // If the initializer is a scalar, just return it.
4404 if (Init->getType()->isScalarType())
4405 return true;
4406 ASTContext &Ctx = SemaRef.getASTContext();
4407 InitListTransformer ILT(SemaRef, Entity);
4408
4409 for (unsigned I = 0; I < Init->getNumInits(); ++I) {
4410 Expr *E = Init->getInit(I);
4411 if (E->HasSideEffects(Ctx)) {
4412 QualType Ty = E->getType();
4413 if (Ty->isRecordType())
4414 E = new (Ctx) MaterializeTemporaryExpr(Ty, E, E->isLValue());
4415 E = new (Ctx) OpaqueValueExpr(E->getBeginLoc(), Ty, E->getValueKind(),
4416 E->getObjectKind(), E);
4417 Init->setInit(I, E);
4418 }
4419 if (!ILT.buildInitializerList(E))
4420 return false;
4421 }
4422 size_t ExpectedSize = ILT.DestTypes.size();
4423 size_t ActualSize = ILT.ArgExprs.size();
4424 if (ExpectedSize == 0 && ActualSize == 0)
4425 return true;
4426
4427 // For incomplete arrays it is completely arbitrary to choose whether we think
4428 // the user intended fewer or more elements. This implementation assumes that
4429 // the user intended more, and errors that there are too few initializers to
4430 // complete the final element.
4431 if (Entity.getType()->isIncompleteArrayType())
4432 ExpectedSize =
4433 ((ActualSize + ExpectedSize - 1) / ExpectedSize) * ExpectedSize;
4434
4435 // An initializer list might be attempting to initialize a reference or
4436 // rvalue-reference. When checking the initializer we should look through
4437 // the reference.
4438 QualType InitTy = Entity.getType().getNonReferenceType();
4439 if (InitTy.hasAddressSpace())
4440 InitTy = SemaRef.getASTContext().removeAddrSpaceQualType(InitTy);
4441 if (ExpectedSize != ActualSize) {
4442 int TooManyOrFew = ActualSize > ExpectedSize ? 1 : 0;
4443 SemaRef.Diag(Init->getBeginLoc(), diag::err_hlsl_incorrect_num_initializers)
4444 << TooManyOrFew << InitTy << ExpectedSize << ActualSize;
4445 return false;
4446 }
4447
4448 // generateInitListsImpl will always return an InitListExpr here, because the
4449 // scalar case is handled above.
4450 auto *NewInit = cast<InitListExpr>(ILT.generateInitLists());
4451 Init->resizeInits(Ctx, NewInit->getNumInits());
4452 for (unsigned I = 0; I < NewInit->getNumInits(); ++I)
4453 Init->updateInit(Ctx, I, NewInit->getInit(I));
4454 return true;
4455}
4456
4458 const HLSLVkConstantIdAttr *ConstIdAttr =
4459 VDecl->getAttr<HLSLVkConstantIdAttr>();
4460 if (!ConstIdAttr)
4461 return true;
4462
4463 ASTContext &Context = SemaRef.getASTContext();
4464
4465 APValue InitValue;
4466 if (!Init->isCXX11ConstantExpr(Context, &InitValue)) {
4467 Diag(VDecl->getLocation(), diag::err_specialization_const);
4468 VDecl->setInvalidDecl();
4469 return false;
4470 }
4471
4472 Builtin::ID BID =
4474
4475 // Argument 1: The ID from the attribute
4476 int ConstantID = ConstIdAttr->getId();
4477 llvm::APInt IDVal(Context.getIntWidth(Context.IntTy), ConstantID);
4478 Expr *IdExpr = IntegerLiteral::Create(Context, IDVal, Context.IntTy,
4479 ConstIdAttr->getLocation());
4480
4481 SmallVector<Expr *, 2> Args = {IdExpr, Init};
4482 Expr *C = SemaRef.BuildBuiltinCallExpr(Init->getExprLoc(), BID, Args);
4483 if (C->getType()->getCanonicalTypeUnqualified() !=
4485 C = SemaRef
4486 .BuildCStyleCastExpr(SourceLocation(),
4487 Context.getTrivialTypeSourceInfo(
4488 Init->getType(), Init->getExprLoc()),
4489 SourceLocation(), C)
4490 .get();
4491 }
4492 Init = C;
4493 return true;
4494}
Defines the clang::ASTContext interface.
Defines enum values for all the target-independent builtin functions.
llvm::dxil::ResourceClass ResourceClass
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
TokenType getType() const
Returns the token's type, e.g.
FormatToken * Previous
The previous token in the unwrapped line.
Defines the clang::IdentifierInfo, clang::IdentifierTable, and clang::Selector interfaces.
#define X(type, name)
Definition Value.h:97
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
llvm::SmallVector< std::pair< const MemRegion *, SVal >, 4 > Bindings
static bool CheckArgTypeMatches(Sema *S, Expr *Arg, QualType ExpectedType)
static void BuildFlattenedTypeList(QualType BaseTy, llvm::SmallVectorImpl< QualType > &List)
static bool CheckUnsignedIntRepresentation(Sema *S, SourceLocation Loc, int ArgOrdinal, clang::QualType PassedType)
static 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:83
static bool CheckWaveActive(Sema *S, CallExpr *TheCall)
static void castVector(Sema &S, ExprResult &E, QualType &Ty, unsigned Sz)
Definition SemaHLSL.cpp:970
static bool CheckBoolSelect(Sema *S, CallExpr *TheCall)
static unsigned calculateLegacyCbufferFieldAlign(const ASTContext &Context, QualType T)
Definition SemaHLSL.cpp:220
static bool isZeroSizedArray(const ConstantArrayType *CAT)
Definition SemaHLSL.cpp:339
static bool DiagnoseHLSLRegisterAttribute(Sema &S, SourceLocation &ArgLoc, Decl *D, RegisterType RegType, bool SpecifiedSpace)
static FieldDecl * createFieldForHostLayoutStruct(Sema &S, const Type *Ty, IdentifierInfo *II, CXXRecordDecl *LayoutStruct)
Definition SemaHLSL.cpp:458
static bool CheckUnsignedIntVecRepresentation(Sema *S, SourceLocation Loc, int ArgOrdinal, clang::QualType PassedType)
static bool isInvalidConstantBufferLeafElementType(const Type *Ty)
Definition SemaHLSL.cpp:365
static Builtin::ID getSpecConstBuiltinId(const Type *Type)
Definition SemaHLSL.cpp:133
static bool CheckFloatingOrIntRepresentation(Sema *S, SourceLocation Loc, int ArgOrdinal, clang::QualType PassedType)
static bool CheckAnyScalarOrVector(Sema *S, CallExpr *TheCall, unsigned ArgIndex)
static IdentifierInfo * getHostLayoutStructName(Sema &S, NamedDecl *BaseDecl, bool MustBeUnique)
Definition SemaHLSL.cpp:421
static void addImplicitBindingAttrToDecl(Sema &S, Decl *D, RegisterType RT, uint32_t ImplicitBindingOrderID)
Definition SemaHLSL.cpp:586
static void SetElementTypeAsReturnType(Sema *S, CallExpr *TheCall, QualType ReturnType)
static bool isResourceRecordTypeOrArrayOf(VarDecl *VD)
Definition SemaHLSL.cpp:346
static unsigned calculateLegacyCbufferSize(const ASTContext &Context, QualType T)
Definition SemaHLSL.cpp:239
static const HLSLAttributedResourceType * getResourceArrayHandleType(VarDecl *VD)
Definition SemaHLSL.cpp:352
static RegisterType getRegisterType(ResourceClass RC)
Definition SemaHLSL.cpp:63
static bool CheckModifiableLValue(Sema *S, CallExpr *TheCall, unsigned ArgIndex)
static QualType castElement(Sema &S, ExprResult &E, QualType Ty)
Definition SemaHLSL.cpp:978
static CXXRecordDecl * findRecordDeclInContext(IdentifierInfo *II, DeclContext *DC)
Definition SemaHLSL.cpp:404
static bool hasCounterHandle(const CXXRecordDecl *RD)
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)
Definition SemaHLSL.cpp:983
static ResourceClass getResourceClass(RegisterType RT)
Definition SemaHLSL.cpp:115
static CXXRecordDecl * createHostLayoutStruct(Sema &S, CXXRecordDecl *StructDecl)
Definition SemaHLSL.cpp:490
static bool CheckScalarOrVector(Sema *S, CallExpr *TheCall, QualType Scalar, unsigned ArgIndex)
void createHostLayoutStructForBuffer(Sema &S, HLSLBufferDecl *BufDecl)
Definition SemaHLSL.cpp:555
static bool requiresImplicitBufferLayoutStructure(const CXXRecordDecl *RD)
Definition SemaHLSL.cpp:384
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:286
HLSLResourceBindingAttr::RegisterType RegisterType
Definition SemaHLSL.cpp:58
static CastKind getScalarCastKind(ASTContext &Ctx, QualType DestTy, QualType SrcTy)
static bool isValidWaveSizeValue(unsigned Value)
static bool IsDefaultBufferConstantDecl(VarDecl *VD)
static bool CheckNoDoubleVectors(Sema *S, SourceLocation Loc, int ArgOrdinal, clang::QualType PassedType)
static bool ValidateMultipleRegisterAnnotations(Sema &S, Decl *TheDecl, RegisterType regType)
static bool DiagnoseLocalRegisterBinding(Sema &S, SourceLocation &ArgLoc, Decl *D, RegisterType RegType, bool SpecifiedSpace)
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
APValue - This class implements a discriminated union of [uninitialized] [APSInt] [APFloat],...
Definition APValue.h:122
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:220
unsigned getIntWidth(QualType T) const
int getIntegerTypeOrder(QualType LHS, QualType RHS) const
Return the highest ranked integer type, see C99 6.3.1.8p1.
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:772
QualType getConstantArrayType(QualType EltTy, const llvm::APInt &ArySize, const Expr *SizeExpr, ArraySizeModifier ASM, unsigned IndexTypeQuals) const
Return the unique reference to the type for a constant array of the specified element type.
QualType getBaseElementType(const ArrayType *VAT) const
Return the innermost element type of an array type.
int getFloatingTypeOrder(QualType LHS, QualType RHS) const
Compare the rank of the two specified floating point types, ignoring the domain of the type (i....
CanQualType BoolTy
TypeSourceInfo * getTrivialTypeSourceInfo(QualType T, SourceLocation Loc=SourceLocation()) const
Allocate a TypeSourceInfo where all locations have been initialized to a given location,...
QualType getStringLiteralArrayType(QualType EltTy, unsigned Length) const
Return a type for a constant array for a string literal of the specified element type and length.
CanQualType CharTy
CanQualType IntTy
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.
CanQualType UnsignedIntTy
QualType 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:891
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:3722
QualType getElementType() const
Definition TypeBase.h:3734
Attr - This represents one attribute.
Definition Attr.h:44
attr::Kind getKind() const
Definition Attr.h:90
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:2129
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:1550
static CXXRecordDecl * Create(const ASTContext &C, TagKind TK, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, CXXRecordDecl *PrevDecl=nullptr)
Definition DeclCXX.cpp:132
void setBases(CXXBaseSpecifier const *const *Bases, unsigned NumBases)
Sets the base classes of this struct or class.
Definition DeclCXX.cpp:184
void completeDefinition() override
Indicates that the definition of this class is now complete.
Definition DeclCXX.cpp:2239
base_class_range bases()
Definition DeclCXX.h:608
unsigned getNumBases() const
Retrieves the number of base classes of this class.
Definition DeclCXX.h:602
base_class_iterator bases_begin()
Definition DeclCXX.h:615
bool isEmpty() const
Determine whether this is an empty class in the sense of (C++11 [meta.unary.prop]).
Definition DeclCXX.h:1186
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition Expr.h:2877
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition Expr.h:3081
SourceLocation getBeginLoc() const
Definition Expr.h:3211
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:1513
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
Definition Expr.h:3060
Expr * getCallee()
Definition Expr.h:3024
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition Expr.h:3068
QualType withConst() const
Retrieves a version of this type with const applied.
const T * getTypePtr() const
Retrieve the underlying type pointer, which refers to a canonical type.
QuantityType getQuantity() const
getQuantity - Get the raw integer representation of this quantity.
Definition CharUnits.h:185
Represents the canonical version of C arrays with a specified constant size.
Definition TypeBase.h:3760
bool isZeroSize() const
Return true if the size is zero.
Definition TypeBase.h:3830
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:1449
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:2185
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:2373
DeclContext * getNonTransparentContext()
A reference to a declared variable, function, enum, etc.
Definition Expr.h:1270
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:484
ValueDecl * getDecl()
Definition Expr.h:1338
Decl - This represents one declaration (or definition), e.g.
Definition DeclBase.h:86
T * getAttr() const
Definition DeclBase.h:573
void addAttr(Attr *A)
attr_iterator attr_end() const
Definition DeclBase.h:542
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
Definition DeclBase.h:593
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:539
SourceLocation getLocation() const
Definition DeclBase.h:439
void setImplicit(bool I=true)
Definition DeclBase.h:594
DeclContext * getDeclContext()
Definition DeclBase.h:448
attr_range attrs() const
Definition DeclBase.h:535
AccessSpecifier getAccess() const
Definition DeclBase.h:507
SourceLocation getBeginLoc() const LLVM_READONLY
Definition DeclBase.h:431
void dropAttr()
Definition DeclBase.h:556
bool hasAttr() const
Definition DeclBase.h:577
The name of a declaration.
Represents a ValueDecl that came out of a declarator.
Definition Decl.h:780
SourceLocation getBeginLoc() const LLVM_READONLY
Definition Decl.h:831
This represents one expression.
Definition Expr.h:112
void setType(QualType t)
Definition Expr.h:145
ExprValueKind getValueKind() const
getValueKind - The value kind that this expression produces.
Definition Expr.h:444
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
Definition Expr.cpp:3085
Expr * IgnoreParens() LLVM_READONLY
Skip past any parentheses which might surround this expression until reaching a fixed point.
Definition Expr.cpp:3081
std::optional< llvm::APSInt > getIntegerConstantExpr(const ASTContext &Ctx) const
isIntegerConstantExpr - Return the value if this expression is a valid integer constant expression.
bool isLValue() const
isLValue - True if this expression is an "l-value" according to the rules of the current language.
Definition Expr.h:284
ExprObjectKind getObjectKind() const
getObjectKind - The object kind that this expression produces.
Definition Expr.h:451
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:3665
void setValueKind(ExprValueKind Cat)
setValueKind - Set the value kind produced by this expression.
Definition Expr.h:461
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Definition Expr.cpp:273
@ MLV_Valid
Definition Expr.h:305
QualType getType() const
Definition Expr.h:144
Represents a member of a struct/union/class.
Definition Decl.h:3160
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:4689
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:2000
const ParmVarDecl * getParamDecl(unsigned i) const
Definition Decl.h:2797
Stmt * getBody(const FunctionDecl *&Definition) const
Retrieve the body (definition) of the function.
Definition Decl.cpp:3268
bool isThisDeclarationADefinition() const
Returns whether this specific declaration of the function is also a definition that does not contain ...
Definition Decl.h:2314
QualType getReturnType() const
Definition Decl.h:2845
ArrayRef< ParmVarDecl * > parameters() const
Definition Decl.h:2774
bool isTemplateInstantiation() const
Determines if the given function was instantiated from a function template.
Definition Decl.cpp:4246
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:3815
DeclarationNameInfo getNameInfo() const
Definition Decl.h:2211
bool hasBody(const FunctionDecl *&Definition) const
Returns true if the function has a body.
Definition Decl.cpp:3188
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:3235
HLSLBufferDecl - Represent a cbuffer or tbuffer declaration.
Definition Decl.h:5176
static HLSLBufferDecl * Create(ASTContext &C, DeclContext *LexicalParent, bool CBuffer, SourceLocation KwLoc, IdentifierInfo *ID, SourceLocation IDLoc, SourceLocation LBrace)
Definition Decl.cpp:5825
void addLayoutStruct(CXXRecordDecl *LS)
Definition Decl.cpp:5865
void setHasValidPackoffset(bool PO)
Definition Decl.h:5221
static HLSLBufferDecl * CreateDefaultCBuffer(ASTContext &C, DeclContext *LexicalParent, ArrayRef< Decl * > DefaultCBufferDecls)
Definition Decl.cpp:5848
buffer_decl_range buffer_decls() const
Definition Decl.h:5251
static HLSLOutArgExpr * Create(const ASTContext &C, QualType Ty, OpaqueValueExpr *Base, OpaqueValueExpr *OpV, Expr *WB, bool IsInOut)
Definition Expr.cpp:5524
static HLSLRootSignatureDecl * Create(ASTContext &C, DeclContext *DC, SourceLocation Loc, IdentifierInfo *ID, llvm::dxbc::RootSignatureVersion Version, ArrayRef< llvm::hlsl::rootsig::RootElement > RootElements)
Definition Decl.cpp:5911
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.
static ImplicitCastExpr * Create(const ASTContext &Context, QualType T, CastKind Kind, Expr *Operand, const CXXCastPath *BasePath, ExprValueKind Cat, FPOptionsOverride FPO)
Definition Expr.cpp:2068
Describes an C or C++ initializer list.
Definition Expr.h:5233
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:971
Represents the results of name lookup.
Definition Lookup.h:147
NamedDecl * getFoundDecl() const
Fetch the unique decl found by this lookup.
Definition Lookup.h:569
Represents a prvalue temporary that is written into memory so that a reference can bind to it.
Definition ExprCXX.h:4922
ValueDecl * getMemberDecl() const
Retrieve the member declaration to which this expression refers.
Definition Expr.h:3381
This represents a decl that may have a name.
Definition Decl.h:274
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
Definition Decl.h:295
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Definition Decl.h:301
DeclarationName getDeclName() const
Get the actual, stored name of the declaration, which may be a special name.
Definition Decl.h:340
OpaqueValueExpr - An expression referring to an opaque object of a fixed type and value class.
Definition Expr.h:1178
Represents a parameter to a function.
Definition Decl.h:1790
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
const ParsedType & getTypeArg() const
Definition ParsedAttr.h:459
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this attribute.
Definition ParsedAttr.h:371
bool isArgIdent(unsigned Arg) const
Definition ParsedAttr.h:385
Expr * getArgAsExpr(unsigned Arg) const
Definition ParsedAttr.h:383
AttributeCommonInfo::Kind getKind() const
Definition ParsedAttr.h:610
A (possibly-)qualified type.
Definition TypeBase.h:937
void addRestrict()
Add the restrict qualifier to this QualType.
Definition TypeBase.h:1172
QualType getNonLValueExprType(const ASTContext &Context) const
Determine the type of a (typically non-lvalue) expression with the specified result type.
Definition Type.cpp:3555
QualType getDesugaredType(const ASTContext &Context) const
Return the specified type with any "sugar" removed from the type.
Definition TypeBase.h:1296
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition TypeBase.h:1004
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Definition TypeBase.h:8278
LangAS getAddressSpace() const
Return the address space of this type.
Definition TypeBase.h:8404
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:8463
QualType getCanonicalType() const
Definition TypeBase.h:8330
QualType getUnqualifiedType() const
Retrieve the unqualified variant of the given type, removing as little sugar as possible.
Definition TypeBase.h:8372
bool hasAddressSpace() const
Check if this type has any address space qualifier.
Definition TypeBase.h:8399
Represents a struct/union/class.
Definition Decl.h:4312
field_iterator field_end() const
Definition Decl.h:4518
field_range fields() const
Definition Decl.h:4515
bool field_empty() const
Definition Decl.h:4523
field_iterator field_begin() const
Definition Decl.cpp:5202
bool hasBindingInfoForDecl(const VarDecl *VD) const
Definition SemaHLSL.cpp:194
DeclBindingInfo * getDeclBindingInfo(const VarDecl *VD, ResourceClass ResClass)
Definition SemaHLSL.cpp:180
DeclBindingInfo * addDeclBindingInfo(const VarDecl *VD, ResourceClass ResClass)
Definition SemaHLSL.cpp:167
Scope - A scope is a transient data structure that is used while parsing the program.
Definition Scope.h:41
SemaBase(Sema &S)
Definition SemaBase.cpp:7
ASTContext & getASTContext() const
Definition SemaBase.cpp:9
Sema & SemaRef
Definition SemaBase.h:40
SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID)
Emit a diagnostic.
Definition SemaBase.cpp:61
ExprResult ActOnOutParamExpr(ParmVarDecl *Param, Expr *Arg)
HLSLRootSignatureDecl * lookupRootSignatureOverrideDecl(DeclContext *DC) const
bool CanPerformElementwiseCast(Expr *Src, QualType DestType)
void DiagnoseAttrStageMismatch(const Attr *A, llvm::Triple::EnvironmentType Stage, std::initializer_list< llvm::Triple::EnvironmentType > AllowedStages)
Definition SemaHLSL.cpp:955
void handleWaveSizeAttr(Decl *D, const ParsedAttr &AL)
HLSLAttributedResourceLocInfo TakeLocForHLSLAttribute(const HLSLAttributedResourceType *RT)
void handleSemanticAttr(Decl *D, const ParsedAttr &AL)
bool CanPerformScalarCast(QualType SrcTy, QualType DestTy)
QualType ProcessResourceTypeAttributes(QualType Wrapped)
void handleShaderAttr(Decl *D, const ParsedAttr &AL)
void CheckEntryPoint(FunctionDecl *FD)
Definition SemaHLSL.cpp:852
void emitLogicalOperatorFixIt(Expr *LHS, Expr *RHS, BinaryOperatorKind Opc)
void ActOnEndOfTranslationUnit(TranslationUnitDecl *TU)
HLSLVkConstantIdAttr * mergeVkConstantIdAttr(Decl *D, const AttributeCommonInfo &AL, int Id)
Definition SemaHLSL.cpp:657
HLSLNumThreadsAttr * mergeNumThreadsAttr(Decl *D, const AttributeCommonInfo &AL, int X, int Y, int Z)
Definition SemaHLSL.cpp:623
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)
bool diagnosePositionType(QualType T, const ParsedAttr &AL)
bool handleInitialization(VarDecl *VDecl, Expr *&Init)
bool diagnoseInputIDType(QualType T, const ParsedAttr &AL)
void handleParamModifierAttr(Decl *D, const ParsedAttr &AL)
bool CheckResourceBinOp(BinaryOperatorKind Opc, Expr *LHSExpr, Expr *RHSExpr, SourceLocation Loc)
bool CanPerformAggregateSplatCast(Expr *Src, QualType DestType)
bool IsScalarizedLayoutCompatible(QualType T1, QualType T2) const
void diagnoseSystemSemanticAttr(Decl *D, const ParsedAttr &AL, std::optional< unsigned > Index)
void handleRootSignatureAttr(Decl *D, const ParsedAttr &AL)
bool CheckCompatibleParameterABI(FunctionDecl *New, FunctionDecl *Old)
QualType handleVectorBinOpConversion(ExprResult &LHS, ExprResult &RHS, QualType LHSType, QualType RHSType, bool IsCompAssign)
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)
T * createSemanticAttr(const AttributeCommonInfo &ACI, NamedDecl *TargetDecl, std::optional< unsigned > Location)
Definition SemaHLSL.h:179
void ActOnTopLevelFunction(FunctionDecl *FD)
Definition SemaHLSL.cpp:726
bool handleResourceTypeAttr(QualType T, const ParsedAttr &AL)
HLSLShaderAttr * mergeShaderAttr(Decl *D, const AttributeCommonInfo &AL, llvm::Triple::EnvironmentType ShaderType)
Definition SemaHLSL.cpp:693
void ActOnFinishBuffer(Decl *Dcl, SourceLocation RBrace)
Definition SemaHLSL.cpp:596
void handleVkBindingAttr(Decl *D, const ParsedAttr &AL)
HLSLParamModifierAttr * mergeParamModifierAttr(Decl *D, const AttributeCommonInfo &AL, HLSLParamModifierAttr::Spelling Spelling)
Definition SemaHLSL.cpp:706
QualType getInoutParameterType(QualType Ty)
SemaHLSL(Sema &S)
Definition SemaHLSL.cpp:198
void handleVkConstantIdAttr(Decl *D, const ParsedAttr &AL)
Decl * ActOnStartBuffer(Scope *BufferScope, bool CBuffer, SourceLocation KwLoc, IdentifierInfo *Ident, SourceLocation IdentLoc, SourceLocation LBrace)
Definition SemaHLSL.cpp:200
HLSLWaveSizeAttr * mergeWaveSizeAttr(Decl *D, const AttributeCommonInfo &AL, int Min, int Max, int Preferred, int SpelledArgsCount)
Definition SemaHLSL.cpp:637
bool handleRootSignatureElements(ArrayRef< hlsl::RootSignatureElement > Elements)
void ActOnFinishRootSignatureDecl(SourceLocation Loc, IdentifierInfo *DeclIdent, ArrayRef< hlsl::RootSignatureElement > Elements)
Creates the Root Signature decl of the parsed Root Signature elements onto the AST and push it onto c...
void ActOnVariableDeclarator(VarDecl *VD)
bool CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall)
Sema - This implements semantic analysis and AST building for C.
Definition Sema.h:854
@ LookupOrdinaryName
Ordinary name lookup, which finds ordinary names (functions, variables, typedefs, etc....
Definition Sema.h:9297
@ LookupMemberName
Member name lookup, which finds the names of class/struct/union members.
Definition Sema.h:9305
ASTContext & Context
Definition Sema.h:1283
ASTContext & getASTContext() const
Definition Sema.h:925
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:755
const LangOptions & getLangOpts() const
Definition Sema.h:918
ExprResult BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow, SourceLocation OpLoc, const CXXScopeSpec &SS, FieldDecl *Field, DeclAccessPair FoundDecl, const DeclarationNameInfo &MemberNameInfo)
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.
A trivial tuple used to represent a source range.
SourceLocation getEnd() const
SourceLocation getEndLoc() const LLVM_READONLY
Definition Stmt.cpp:362
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:338
SourceLocation getBeginLoc() const LLVM_READONLY
Definition Stmt.cpp:350
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:1184
void startDefinition()
Starts the definition of this tag declaration.
Definition Decl.cpp:4895
bool isUnion() const
Definition Decl.h:3922
bool isClass() const
Definition Decl.h:3921
Exposes information about the current target.
Definition TargetInfo.h:226
TargetOptions & getTargetOpts() const
Retrieve the target options.
Definition TargetInfo.h:323
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.
The top declaration context.
Definition Decl.h:105
SourceLocation getBeginLoc() const
Get the begin source location.
Definition TypeLoc.cpp:193
A container of type source information.
Definition TypeBase.h:8249
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:1833
bool isVoidType() const
Definition TypeBase.h:8871
bool isBooleanType() const
Definition TypeBase.h:9001
bool isIncompleteArrayType() const
Definition TypeBase.h:8622
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:8618
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:2066
bool isArrayType() const
Definition TypeBase.h:8614
CXXRecordDecl * castAsCXXRecordDecl() const
Definition Type.h:36
bool isArithmeticType() const
Definition Type.cpp:2337
bool isConstantMatrixType() const
Definition TypeBase.h:8676
bool isHLSLBuiltinIntangibleType() const
Definition TypeBase.h:8816
CanQualType getCanonicalTypeUnqualified() const
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
Definition TypeBase.h:8915
const T * castAs() const
Member-template castAs<specific type>.
Definition TypeBase.h:9158
bool isReferenceType() const
Definition TypeBase.h:8539
bool isHLSLIntangibleType() const
Definition Type.cpp:5375
bool isEnumeralType() const
Definition TypeBase.h:8646
bool isScalarType() const
Definition TypeBase.h:8973
bool isIntegralType(const ASTContext &Ctx) const
Determine whether this type is an integral type.
Definition Type.cpp:2103
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:471
bool hasUnsignedIntegerRepresentation() const
Determine whether this type has an unsigned integer representation of some sort, e....
Definition Type.cpp:2291
bool isAggregateType() const
Determines whether the type is a C++ aggregate type or C aggregate or union type.
Definition Type.cpp:2411
ScalarTypeKind getScalarTypeKind() const
Given that this is a scalar type, classify it.
Definition Type.cpp:2364
bool hasSignedIntegerRepresentation() const
Determine whether this type has an signed integer representation of some sort, e.g....
Definition Type.cpp:2243
bool isHLSLResourceRecord() const
Definition Type.cpp:5362
bool hasFloatingRepresentation() const
Determine whether this type has a floating-point representation of some sort, e.g....
Definition Type.cpp:2312
bool isVectorType() const
Definition TypeBase.h:8654
bool isRealFloatingType() const
Floating point categories.
Definition Type.cpp:2320
bool isHLSLAttributedResourceType() const
Definition TypeBase.h:8828
@ STK_FloatingComplex
Definition TypeBase.h:2764
@ STK_ObjCObjectPointer
Definition TypeBase.h:2758
@ STK_IntegralComplex
Definition TypeBase.h:2763
@ STK_MemberPointer
Definition TypeBase.h:2759
bool isFloatingType() const
Definition Type.cpp:2304
bool isSamplerT() const
Definition TypeBase.h:8749
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9091
const Type * getUnqualifiedDesugaredType() const
Return the specified type with any "sugar" removed from the type, removing any typedefs,...
Definition Type.cpp:653
bool isRecordType() const
Definition TypeBase.h:8642
bool isHLSLResourceRecordArray() const
Definition Type.cpp:5366
void setType(QualType newType)
Definition Decl.h:724
QualType getType() const
Definition Decl.h:723
Represents a variable declaration or definition.
Definition Decl.h:926
void setInitStyle(InitializationStyle Style)
Definition Decl.h:1452
@ CallInit
Call-style initialization (C++98)
Definition Decl.h:934
void setStorageClass(StorageClass SC)
Definition Decl.cpp:2163
bool hasGlobalStorage() const
Returns true for all variables that do not have local storage.
Definition Decl.h:1226
void setInit(Expr *I)
Definition Decl.cpp:2477
StorageClass getStorageClass() const
Returns the storage class as written in the source.
Definition Decl.h:1168
Represents a GCC generic vector type.
Definition TypeBase.h:4175
unsigned getNumElements() const
Definition TypeBase.h:4190
QualType getElementType() const
Definition TypeBase.h:4189
Defines the clang::TargetInfo interface.
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
Definition Address.h:330
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:272
@ OK_Ordinary
An ordinary object is located at an address in memory.
Definition Specifiers.h:151
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:124
@ AS_none
Definition Specifiers.h:127
@ SC_Static
Definition Specifiers.h:252
@ AANT_ArgumentIdentifier
@ Result
The result type of a method or function.
Definition TypeBase.h:905
@ Ordinary
This parameter uses ordinary ABI rules for its type.
Definition Specifiers.h:380
const FunctionProtoType * T
llvm::Expected< QualType > ExpectedType
static bool CheckAllArgsHaveSameType(Sema *S, CallExpr *TheCall)
Definition SemaSPIRV.cpp:32
ExprResult ExprError()
Definition Ownership.h:265
@ Type
The name was classified as a type.
Definition Sema.h:562
LangAS
Defines the address space values used by the address space qualifier of QualType.
bool CreateHLSLAttributedResourceType(Sema &S, QualType Wrapped, ArrayRef< const Attr * > AttrList, QualType &ResType, HLSLAttributedResourceLocInfo *LocInfo=nullptr)
CastKind
CastKind - The kind of operation required for a conversion.
@ VK_PRValue
A pr-value expression (in the C++11 taxonomy) produces a temporary value.
Definition Specifiers.h:135
@ VK_LValue
An l-value expression is a reference to an object with independent storage.
Definition Specifiers.h:139
DynamicRecursiveASTVisitorBase< false > DynamicRecursiveASTVisitor
U cast(CodeGen::Address addr)
Definition Address.h:327
ActionResult< Expr * > ExprResult
Definition Ownership.h:249
Visibility
Describes the different kinds of visibility that a declaration may have.
Definition Visibility.h:34
unsigned long uint64_t
unsigned int uint32_t
hash_code hash_value(const clang::tooling::dependencies::ModuleID &ID)
__DEVICE__ bool isnan(float __x)
__DEVICE__ _Tp abs(const std::complex< _Tp > &__c)
#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:46
const llvm::hlsl::rootsig::RootElement & getElement() const
Definition SemaHLSL.h:45