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 (dyn_cast<HLSLUserSemanticAttr>(Info.Semantic))
779 return createSemanticAttr<HLSLUserSemanticAttr>(*Info.Semantic, TargetDecl,
780 Info.Index);
781
782 if (SemanticName == "SV_DISPATCHTHREADID") {
784 *Info.Semantic, TargetDecl, Info.Index);
785 } else if (SemanticName == "SV_GROUPINDEX") {
786 return createSemanticAttr<HLSLSV_GroupIndexAttr>(*Info.Semantic, TargetDecl,
787 Info.Index);
788 } else if (SemanticName == "SV_GROUPTHREADID") {
790 TargetDecl, Info.Index);
791 } else if (SemanticName == "SV_GROUPID") {
792 return createSemanticAttr<HLSLSV_GroupIDAttr>(*Info.Semantic, TargetDecl,
793 Info.Index);
794 } else if (SemanticName == "SV_POSITION") {
795 return createSemanticAttr<HLSLSV_PositionAttr>(*Info.Semantic, TargetDecl,
796 Info.Index);
797 } else
798 Diag(Info.Semantic->getLoc(), diag::err_hlsl_unknown_semantic)
799 << *Info.Semantic;
800
801 return nullptr;
802}
803
804bool SemaHLSL::determineActiveSemanticOnScalar(
805 FunctionDecl *FD, DeclaratorDecl *D, SemanticInfo &ActiveSemantic,
806 llvm::StringSet<> &ActiveInputSemantics) {
807
808 if (ActiveSemantic.Semantic == nullptr) {
809 ActiveSemantic.Semantic = D->getAttr<HLSLSemanticAttr>();
810 if (ActiveSemantic.Semantic &&
811 ActiveSemantic.Semantic->isSemanticIndexExplicit())
812 ActiveSemantic.Index = ActiveSemantic.Semantic->getSemanticIndex();
813 }
814
815 if (!ActiveSemantic.Semantic) {
816 Diag(D->getLocation(), diag::err_hlsl_missing_semantic_annotation);
817 return false;
818 }
819
820 auto *A = createSemantic(ActiveSemantic, D);
821 if (!A)
822 return false;
823
824 checkSemanticAnnotation(FD, D, A);
825 FD->addAttr(A);
826
827 unsigned Location = ActiveSemantic.Index.value_or(0);
828
829 const ConstantArrayType *AT = dyn_cast<ConstantArrayType>(D->getType());
830 unsigned ElementCount = AT ? AT->getZExtSize() : 1;
831 ActiveSemantic.Index = Location + ElementCount;
832
833 Twine BaseName = Twine(ActiveSemantic.Semantic->getAttrName()->getName());
834 for (unsigned I = 0; I < ElementCount; ++I) {
835 Twine VariableName = BaseName.concat(Twine(Location + I));
836
837 auto [_, Inserted] = ActiveInputSemantics.insert(VariableName.str());
838 if (!Inserted) {
839 Diag(D->getLocation(), diag::err_hlsl_semantic_index_overlap)
840 << VariableName.str();
841 return false;
842 }
843 }
844
845 return true;
846}
847
848bool SemaHLSL::determineActiveSemantic(
849 FunctionDecl *FD, DeclaratorDecl *D, SemanticInfo &ActiveSemantic,
850 llvm::StringSet<> &ActiveInputSemantics) {
851 if (ActiveSemantic.Semantic == nullptr) {
852 ActiveSemantic.Semantic = D->getAttr<HLSLSemanticAttr>();
853 if (ActiveSemantic.Semantic &&
854 ActiveSemantic.Semantic->isSemanticIndexExplicit())
855 ActiveSemantic.Index = ActiveSemantic.Semantic->getSemanticIndex();
856 }
857
858 const Type *T = D->getType()->getUnqualifiedDesugaredType();
859 const RecordType *RT = dyn_cast<RecordType>(T);
860 if (!RT)
861 return determineActiveSemanticOnScalar(FD, D, ActiveSemantic,
862 ActiveInputSemantics);
863
864 const RecordDecl *RD = RT->getDecl();
865 for (FieldDecl *Field : RD->fields()) {
866 SemanticInfo Info = ActiveSemantic;
867 if (!determineActiveSemantic(FD, Field, Info, ActiveInputSemantics)) {
868 Diag(Field->getLocation(), diag::note_hlsl_semantic_used_here) << Field;
869 return false;
870 }
871 if (ActiveSemantic.Semantic)
872 ActiveSemantic = Info;
873 }
874
875 return true;
876}
877
879 const auto *ShaderAttr = FD->getAttr<HLSLShaderAttr>();
880 assert(ShaderAttr && "Entry point has no shader attribute");
881 llvm::Triple::EnvironmentType ST = ShaderAttr->getType();
883 VersionTuple Ver = TargetInfo.getTriple().getOSVersion();
884 switch (ST) {
885 case llvm::Triple::Pixel:
886 case llvm::Triple::Vertex:
887 case llvm::Triple::Geometry:
888 case llvm::Triple::Hull:
889 case llvm::Triple::Domain:
890 case llvm::Triple::RayGeneration:
891 case llvm::Triple::Intersection:
892 case llvm::Triple::AnyHit:
893 case llvm::Triple::ClosestHit:
894 case llvm::Triple::Miss:
895 case llvm::Triple::Callable:
896 if (const auto *NT = FD->getAttr<HLSLNumThreadsAttr>()) {
898 {llvm::Triple::Compute,
899 llvm::Triple::Amplification,
900 llvm::Triple::Mesh});
901 FD->setInvalidDecl();
902 }
903 if (const auto *WS = FD->getAttr<HLSLWaveSizeAttr>()) {
905 {llvm::Triple::Compute,
906 llvm::Triple::Amplification,
907 llvm::Triple::Mesh});
908 FD->setInvalidDecl();
909 }
910 break;
911
912 case llvm::Triple::Compute:
913 case llvm::Triple::Amplification:
914 case llvm::Triple::Mesh:
915 if (!FD->hasAttr<HLSLNumThreadsAttr>()) {
916 Diag(FD->getLocation(), diag::err_hlsl_missing_numthreads)
917 << llvm::Triple::getEnvironmentTypeName(ST);
918 FD->setInvalidDecl();
919 }
920 if (const auto *WS = FD->getAttr<HLSLWaveSizeAttr>()) {
921 if (Ver < VersionTuple(6, 6)) {
922 Diag(WS->getLocation(), diag::err_hlsl_attribute_in_wrong_shader_model)
923 << WS << "6.6";
924 FD->setInvalidDecl();
925 } else if (WS->getSpelledArgsCount() > 1 && Ver < VersionTuple(6, 8)) {
926 Diag(
927 WS->getLocation(),
928 diag::err_hlsl_attribute_number_arguments_insufficient_shader_model)
929 << WS << WS->getSpelledArgsCount() << "6.8";
930 FD->setInvalidDecl();
931 }
932 }
933 break;
934 case llvm::Triple::RootSignature:
935 llvm_unreachable("rootsig environment has no function entry point");
936 default:
937 llvm_unreachable("Unhandled environment in triple");
938 }
939
940 llvm::StringSet<> ActiveInputSemantics;
941 for (ParmVarDecl *Param : FD->parameters()) {
942 SemanticInfo ActiveSemantic;
943 ActiveSemantic.Semantic = nullptr;
944 ActiveSemantic.Index = std::nullopt;
945
946 if (!determineActiveSemantic(FD, Param, ActiveSemantic,
947 ActiveInputSemantics)) {
948 Diag(Param->getLocation(), diag::note_previous_decl) << Param;
949 FD->setInvalidDecl();
950 }
951 }
952 // FIXME: Verify return type semantic annotation.
953}
954
955void SemaHLSL::checkSemanticAnnotation(FunctionDecl *EntryPoint,
956 const Decl *Param,
957 const HLSLSemanticAttr *SemanticAttr) {
958 auto *ShaderAttr = EntryPoint->getAttr<HLSLShaderAttr>();
959 assert(ShaderAttr && "Entry point has no shader attribute");
960 llvm::Triple::EnvironmentType ST = ShaderAttr->getType();
961
962 switch (SemanticAttr->getKind()) {
963 case attr::HLSLSV_DispatchThreadID:
964 case attr::HLSLSV_GroupIndex:
965 case attr::HLSLSV_GroupThreadID:
966 case attr::HLSLSV_GroupID:
967 if (ST == llvm::Triple::Compute)
968 return;
969 DiagnoseAttrStageMismatch(SemanticAttr, ST, {llvm::Triple::Compute});
970 break;
971 case attr::HLSLSV_Position:
972 // TODO(#143523): allow use on other shader types & output once the overall
973 // semantic logic is implemented.
974 if (ST == llvm::Triple::Pixel)
975 return;
976 DiagnoseAttrStageMismatch(SemanticAttr, ST, {llvm::Triple::Pixel});
977 break;
978 case attr::HLSLUserSemantic:
979 return;
980 default:
981 llvm_unreachable("Unknown SemanticAttr");
982 }
983}
984
986 const Attr *A, llvm::Triple::EnvironmentType Stage,
987 std::initializer_list<llvm::Triple::EnvironmentType> AllowedStages) {
988 SmallVector<StringRef, 8> StageStrings;
989 llvm::transform(AllowedStages, std::back_inserter(StageStrings),
990 [](llvm::Triple::EnvironmentType ST) {
991 return StringRef(
992 HLSLShaderAttr::ConvertEnvironmentTypeToStr(ST));
993 });
994 Diag(A->getLoc(), diag::err_hlsl_attr_unsupported_in_stage)
995 << A->getAttrName() << llvm::Triple::getEnvironmentTypeName(Stage)
996 << (AllowedStages.size() != 1) << join(StageStrings, ", ");
997}
998
999template <CastKind Kind>
1000static void castVector(Sema &S, ExprResult &E, QualType &Ty, unsigned Sz) {
1001 if (const auto *VTy = Ty->getAs<VectorType>())
1002 Ty = VTy->getElementType();
1003 Ty = S.getASTContext().getExtVectorType(Ty, Sz);
1004 E = S.ImpCastExprToType(E.get(), Ty, Kind);
1005}
1006
1007template <CastKind Kind>
1009 E = S.ImpCastExprToType(E.get(), Ty, Kind);
1010 return Ty;
1011}
1012
1014 Sema &SemaRef, ExprResult &LHS, ExprResult &RHS, QualType LHSType,
1015 QualType RHSType, QualType LElTy, QualType RElTy, bool IsCompAssign) {
1016 bool LHSFloat = LElTy->isRealFloatingType();
1017 bool RHSFloat = RElTy->isRealFloatingType();
1018
1019 if (LHSFloat && RHSFloat) {
1020 if (IsCompAssign ||
1021 SemaRef.getASTContext().getFloatingTypeOrder(LElTy, RElTy) > 0)
1022 return castElement<CK_FloatingCast>(SemaRef, RHS, LHSType);
1023
1024 return castElement<CK_FloatingCast>(SemaRef, LHS, RHSType);
1025 }
1026
1027 if (LHSFloat)
1028 return castElement<CK_IntegralToFloating>(SemaRef, RHS, LHSType);
1029
1030 assert(RHSFloat);
1031 if (IsCompAssign)
1032 return castElement<clang::CK_FloatingToIntegral>(SemaRef, RHS, LHSType);
1033
1034 return castElement<CK_IntegralToFloating>(SemaRef, LHS, RHSType);
1035}
1036
1038 Sema &SemaRef, ExprResult &LHS, ExprResult &RHS, QualType LHSType,
1039 QualType RHSType, QualType LElTy, QualType RElTy, bool IsCompAssign) {
1040
1041 int IntOrder = SemaRef.Context.getIntegerTypeOrder(LElTy, RElTy);
1042 bool LHSSigned = LElTy->hasSignedIntegerRepresentation();
1043 bool RHSSigned = RElTy->hasSignedIntegerRepresentation();
1044 auto &Ctx = SemaRef.getASTContext();
1045
1046 // If both types have the same signedness, use the higher ranked type.
1047 if (LHSSigned == RHSSigned) {
1048 if (IsCompAssign || IntOrder >= 0)
1049 return castElement<CK_IntegralCast>(SemaRef, RHS, LHSType);
1050
1051 return castElement<CK_IntegralCast>(SemaRef, LHS, RHSType);
1052 }
1053
1054 // If the unsigned type has greater than or equal rank of the signed type, use
1055 // the unsigned type.
1056 if (IntOrder != (LHSSigned ? 1 : -1)) {
1057 if (IsCompAssign || RHSSigned)
1058 return castElement<CK_IntegralCast>(SemaRef, RHS, LHSType);
1059 return castElement<CK_IntegralCast>(SemaRef, LHS, RHSType);
1060 }
1061
1062 // At this point the signed type has higher rank than the unsigned type, which
1063 // means it will be the same size or bigger. If the signed type is bigger, it
1064 // can represent all the values of the unsigned type, so select it.
1065 if (Ctx.getIntWidth(LElTy) != Ctx.getIntWidth(RElTy)) {
1066 if (IsCompAssign || LHSSigned)
1067 return castElement<CK_IntegralCast>(SemaRef, RHS, LHSType);
1068 return castElement<CK_IntegralCast>(SemaRef, LHS, RHSType);
1069 }
1070
1071 // This is a bit of an odd duck case in HLSL. It shouldn't happen, but can due
1072 // to C/C++ leaking through. The place this happens today is long vs long
1073 // long. When arguments are vector<unsigned long, N> and vector<long long, N>,
1074 // the long long has higher rank than long even though they are the same size.
1075
1076 // If this is a compound assignment cast the right hand side to the left hand
1077 // side's type.
1078 if (IsCompAssign)
1079 return castElement<CK_IntegralCast>(SemaRef, RHS, LHSType);
1080
1081 // If this isn't a compound assignment we convert to unsigned long long.
1082 QualType ElTy = Ctx.getCorrespondingUnsignedType(LHSSigned ? LElTy : RElTy);
1083 QualType NewTy = Ctx.getExtVectorType(
1084 ElTy, RHSType->castAs<VectorType>()->getNumElements());
1085 (void)castElement<CK_IntegralCast>(SemaRef, RHS, NewTy);
1086
1087 return castElement<CK_IntegralCast>(SemaRef, LHS, NewTy);
1088}
1089
1091 QualType SrcTy) {
1092 if (DestTy->isRealFloatingType() && SrcTy->isRealFloatingType())
1093 return CK_FloatingCast;
1094 if (DestTy->isIntegralType(Ctx) && SrcTy->isIntegralType(Ctx))
1095 return CK_IntegralCast;
1096 if (DestTy->isRealFloatingType())
1097 return CK_IntegralToFloating;
1098 assert(SrcTy->isRealFloatingType() && DestTy->isIntegralType(Ctx));
1099 return CK_FloatingToIntegral;
1100}
1101
1103 QualType LHSType,
1104 QualType RHSType,
1105 bool IsCompAssign) {
1106 const auto *LVecTy = LHSType->getAs<VectorType>();
1107 const auto *RVecTy = RHSType->getAs<VectorType>();
1108 auto &Ctx = getASTContext();
1109
1110 // If the LHS is not a vector and this is a compound assignment, we truncate
1111 // the argument to a scalar then convert it to the LHS's type.
1112 if (!LVecTy && IsCompAssign) {
1113 QualType RElTy = RHSType->castAs<VectorType>()->getElementType();
1114 RHS = SemaRef.ImpCastExprToType(RHS.get(), RElTy, CK_HLSLVectorTruncation);
1115 RHSType = RHS.get()->getType();
1116 if (Ctx.hasSameUnqualifiedType(LHSType, RHSType))
1117 return LHSType;
1118 RHS = SemaRef.ImpCastExprToType(RHS.get(), LHSType,
1119 getScalarCastKind(Ctx, LHSType, RHSType));
1120 return LHSType;
1121 }
1122
1123 unsigned EndSz = std::numeric_limits<unsigned>::max();
1124 unsigned LSz = 0;
1125 if (LVecTy)
1126 LSz = EndSz = LVecTy->getNumElements();
1127 if (RVecTy)
1128 EndSz = std::min(RVecTy->getNumElements(), EndSz);
1129 assert(EndSz != std::numeric_limits<unsigned>::max() &&
1130 "one of the above should have had a value");
1131
1132 // In a compound assignment, the left operand does not change type, the right
1133 // operand is converted to the type of the left operand.
1134 if (IsCompAssign && LSz != EndSz) {
1135 Diag(LHS.get()->getBeginLoc(),
1136 diag::err_hlsl_vector_compound_assignment_truncation)
1137 << LHSType << RHSType;
1138 return QualType();
1139 }
1140
1141 if (RVecTy && RVecTy->getNumElements() > EndSz)
1142 castVector<CK_HLSLVectorTruncation>(SemaRef, RHS, RHSType, EndSz);
1143 if (!IsCompAssign && LVecTy && LVecTy->getNumElements() > EndSz)
1144 castVector<CK_HLSLVectorTruncation>(SemaRef, LHS, LHSType, EndSz);
1145
1146 if (!RVecTy)
1147 castVector<CK_VectorSplat>(SemaRef, RHS, RHSType, EndSz);
1148 if (!IsCompAssign && !LVecTy)
1149 castVector<CK_VectorSplat>(SemaRef, LHS, LHSType, EndSz);
1150
1151 // If we're at the same type after resizing we can stop here.
1152 if (Ctx.hasSameUnqualifiedType(LHSType, RHSType))
1153 return Ctx.getCommonSugaredType(LHSType, RHSType);
1154
1155 QualType LElTy = LHSType->castAs<VectorType>()->getElementType();
1156 QualType RElTy = RHSType->castAs<VectorType>()->getElementType();
1157
1158 // Handle conversion for floating point vectors.
1159 if (LElTy->isRealFloatingType() || RElTy->isRealFloatingType())
1160 return handleFloatVectorBinOpConversion(SemaRef, LHS, RHS, LHSType, RHSType,
1161 LElTy, RElTy, IsCompAssign);
1162
1163 assert(LElTy->isIntegralType(Ctx) && RElTy->isIntegralType(Ctx) &&
1164 "HLSL Vectors can only contain integer or floating point types");
1165 return handleIntegerVectorBinOpConversion(SemaRef, LHS, RHS, LHSType, RHSType,
1166 LElTy, RElTy, IsCompAssign);
1167}
1168
1170 BinaryOperatorKind Opc) {
1171 assert((Opc == BO_LOr || Opc == BO_LAnd) &&
1172 "Called with non-logical operator");
1174 llvm::raw_svector_ostream OS(Buff);
1175 PrintingPolicy PP(SemaRef.getLangOpts());
1176 StringRef NewFnName = Opc == BO_LOr ? "or" : "and";
1177 OS << NewFnName << "(";
1178 LHS->printPretty(OS, nullptr, PP);
1179 OS << ", ";
1180 RHS->printPretty(OS, nullptr, PP);
1181 OS << ")";
1182 SourceRange FullRange = SourceRange(LHS->getBeginLoc(), RHS->getEndLoc());
1183 SemaRef.Diag(LHS->getBeginLoc(), diag::note_function_suggestion)
1184 << NewFnName << FixItHint::CreateReplacement(FullRange, OS.str());
1185}
1186
1187std::pair<IdentifierInfo *, bool>
1189 llvm::hash_code Hash = llvm::hash_value(Signature);
1190 std::string IdStr = "__hlsl_rootsig_decl_" + std::to_string(Hash);
1191 IdentifierInfo *DeclIdent = &(getASTContext().Idents.get(IdStr));
1192
1193 // Check if we have already found a decl of the same name.
1194 LookupResult R(SemaRef, DeclIdent, SourceLocation(),
1196 bool Found = SemaRef.LookupQualifiedName(R, SemaRef.CurContext);
1197 return {DeclIdent, Found};
1198}
1199
1201 SourceLocation Loc, IdentifierInfo *DeclIdent,
1203
1204 if (handleRootSignatureElements(RootElements))
1205 return;
1206
1208 for (auto &RootSigElement : RootElements)
1209 Elements.push_back(RootSigElement.getElement());
1210
1211 auto *SignatureDecl = HLSLRootSignatureDecl::Create(
1212 SemaRef.getASTContext(), /*DeclContext=*/SemaRef.CurContext, Loc,
1213 DeclIdent, SemaRef.getLangOpts().HLSLRootSigVer, Elements);
1214
1215 SignatureDecl->setImplicit();
1216 SemaRef.PushOnScopeChains(SignatureDecl, SemaRef.getCurScope());
1217}
1218
1221 if (RootSigOverrideIdent) {
1222 LookupResult R(SemaRef, RootSigOverrideIdent, SourceLocation(),
1224 if (SemaRef.LookupQualifiedName(R, DC))
1225 return dyn_cast<HLSLRootSignatureDecl>(R.getFoundDecl());
1226 }
1227
1228 return nullptr;
1229}
1230
1231namespace {
1232
1233struct PerVisibilityBindingChecker {
1234 SemaHLSL *S;
1235 // We need one builder per `llvm::dxbc::ShaderVisibility` value.
1236 std::array<llvm::hlsl::BindingInfoBuilder, 8> Builders;
1237
1238 struct ElemInfo {
1239 const hlsl::RootSignatureElement *Elem;
1240 llvm::dxbc::ShaderVisibility Vis;
1241 bool Diagnosed;
1242 };
1243 llvm::SmallVector<ElemInfo> ElemInfoMap;
1244
1245 PerVisibilityBindingChecker(SemaHLSL *S) : S(S) {}
1246
1247 void trackBinding(llvm::dxbc::ShaderVisibility Visibility,
1248 llvm::dxil::ResourceClass RC, uint32_t Space,
1249 uint32_t LowerBound, uint32_t UpperBound,
1250 const hlsl::RootSignatureElement *Elem) {
1251 uint32_t BuilderIndex = llvm::to_underlying(Visibility);
1252 assert(BuilderIndex < Builders.size() &&
1253 "Not enough builders for visibility type");
1254 Builders[BuilderIndex].trackBinding(RC, Space, LowerBound, UpperBound,
1255 static_cast<const void *>(Elem));
1256
1257 static_assert(llvm::to_underlying(llvm::dxbc::ShaderVisibility::All) == 0,
1258 "'All' visibility must come first");
1259 if (Visibility == llvm::dxbc::ShaderVisibility::All)
1260 for (size_t I = 1, E = Builders.size(); I < E; ++I)
1261 Builders[I].trackBinding(RC, Space, LowerBound, UpperBound,
1262 static_cast<const void *>(Elem));
1263
1264 ElemInfoMap.push_back({Elem, Visibility, false});
1265 }
1266
1267 ElemInfo &getInfo(const hlsl::RootSignatureElement *Elem) {
1268 auto It = llvm::lower_bound(
1269 ElemInfoMap, Elem,
1270 [](const auto &LHS, const auto &RHS) { return LHS.Elem < RHS; });
1271 assert(It->Elem == Elem && "Element not in map");
1272 return *It;
1273 }
1274
1275 bool checkOverlap() {
1276 llvm::sort(ElemInfoMap, [](const auto &LHS, const auto &RHS) {
1277 return LHS.Elem < RHS.Elem;
1278 });
1279
1280 bool HadOverlap = false;
1281
1282 using llvm::hlsl::BindingInfoBuilder;
1283 auto ReportOverlap = [this,
1284 &HadOverlap](const BindingInfoBuilder &Builder,
1285 const llvm::hlsl::Binding &Reported) {
1286 HadOverlap = true;
1287
1288 const auto *Elem =
1289 static_cast<const hlsl::RootSignatureElement *>(Reported.Cookie);
1290 const llvm::hlsl::Binding &Previous = Builder.findOverlapping(Reported);
1291 const auto *PrevElem =
1292 static_cast<const hlsl::RootSignatureElement *>(Previous.Cookie);
1293
1294 ElemInfo &Info = getInfo(Elem);
1295 // We will have already diagnosed this binding if there's overlap in the
1296 // "All" visibility as well as any particular visibility.
1297 if (Info.Diagnosed)
1298 return;
1299 Info.Diagnosed = true;
1300
1301 ElemInfo &PrevInfo = getInfo(PrevElem);
1302 llvm::dxbc::ShaderVisibility CommonVis =
1303 Info.Vis == llvm::dxbc::ShaderVisibility::All ? PrevInfo.Vis
1304 : Info.Vis;
1305
1306 this->S->Diag(Elem->getLocation(), diag::err_hlsl_resource_range_overlap)
1307 << llvm::to_underlying(Reported.RC) << Reported.LowerBound
1308 << Reported.isUnbounded() << Reported.UpperBound
1309 << llvm::to_underlying(Previous.RC) << Previous.LowerBound
1310 << Previous.isUnbounded() << Previous.UpperBound << Reported.Space
1311 << CommonVis;
1312
1313 this->S->Diag(PrevElem->getLocation(),
1314 diag::note_hlsl_resource_range_here);
1315 };
1316
1317 for (BindingInfoBuilder &Builder : Builders)
1318 Builder.calculateBindingInfo(ReportOverlap);
1319
1320 return HadOverlap;
1321 }
1322};
1323
1324static CXXMethodDecl *lookupMethod(Sema &S, CXXRecordDecl *RecordDecl,
1325 StringRef Name, SourceLocation Loc) {
1326 DeclarationName DeclName(&S.getASTContext().Idents.get(Name));
1327 LookupResult Result(S, DeclName, Loc, Sema::LookupMemberName);
1328 if (!S.LookupQualifiedName(Result, static_cast<DeclContext *>(RecordDecl)))
1329 return nullptr;
1330 return cast<CXXMethodDecl>(Result.getFoundDecl());
1331}
1332
1333} // end anonymous namespace
1334
1335static bool hasCounterHandle(const CXXRecordDecl *RD) {
1336 if (RD->field_empty())
1337 return false;
1338 auto It = std::next(RD->field_begin());
1339 if (It == RD->field_end())
1340 return false;
1341 const FieldDecl *SecondField = *It;
1342 if (const auto *ResTy =
1343 SecondField->getType()->getAs<HLSLAttributedResourceType>()) {
1344 return ResTy->getAttrs().IsCounter;
1345 }
1346 return false;
1347}
1348
1351 // Define some common error handling functions
1352 bool HadError = false;
1353 auto ReportError = [this, &HadError](SourceLocation Loc, uint32_t LowerBound,
1354 uint32_t UpperBound) {
1355 HadError = true;
1356 this->Diag(Loc, diag::err_hlsl_invalid_rootsig_value)
1357 << LowerBound << UpperBound;
1358 };
1359
1360 auto ReportFloatError = [this, &HadError](SourceLocation Loc,
1361 float LowerBound,
1362 float UpperBound) {
1363 HadError = true;
1364 this->Diag(Loc, diag::err_hlsl_invalid_rootsig_value)
1365 << llvm::formatv("{0:f}", LowerBound).sstr<6>()
1366 << llvm::formatv("{0:f}", UpperBound).sstr<6>();
1367 };
1368
1369 auto VerifyRegister = [ReportError](SourceLocation Loc, uint32_t Register) {
1370 if (!llvm::hlsl::rootsig::verifyRegisterValue(Register))
1371 ReportError(Loc, 0, 0xfffffffe);
1372 };
1373
1374 auto VerifySpace = [ReportError](SourceLocation Loc, uint32_t Space) {
1375 if (!llvm::hlsl::rootsig::verifyRegisterSpace(Space))
1376 ReportError(Loc, 0, 0xffffffef);
1377 };
1378
1379 const uint32_t Version =
1380 llvm::to_underlying(SemaRef.getLangOpts().HLSLRootSigVer);
1381 const uint32_t VersionEnum = Version - 1;
1382 auto ReportFlagError = [this, &HadError, VersionEnum](SourceLocation Loc) {
1383 HadError = true;
1384 this->Diag(Loc, diag::err_hlsl_invalid_rootsig_flag)
1385 << /*version minor*/ VersionEnum;
1386 };
1387
1388 // Iterate through the elements and do basic validations
1389 for (const hlsl::RootSignatureElement &RootSigElem : Elements) {
1390 SourceLocation Loc = RootSigElem.getLocation();
1391 const llvm::hlsl::rootsig::RootElement &Elem = RootSigElem.getElement();
1392 if (const auto *Descriptor =
1393 std::get_if<llvm::hlsl::rootsig::RootDescriptor>(&Elem)) {
1394 VerifyRegister(Loc, Descriptor->Reg.Number);
1395 VerifySpace(Loc, Descriptor->Space);
1396
1397 if (!llvm::hlsl::rootsig::verifyRootDescriptorFlag(Version,
1398 Descriptor->Flags))
1399 ReportFlagError(Loc);
1400 } else if (const auto *Constants =
1401 std::get_if<llvm::hlsl::rootsig::RootConstants>(&Elem)) {
1402 VerifyRegister(Loc, Constants->Reg.Number);
1403 VerifySpace(Loc, Constants->Space);
1404 } else if (const auto *Sampler =
1405 std::get_if<llvm::hlsl::rootsig::StaticSampler>(&Elem)) {
1406 VerifyRegister(Loc, Sampler->Reg.Number);
1407 VerifySpace(Loc, Sampler->Space);
1408
1409 assert(!std::isnan(Sampler->MaxLOD) && !std::isnan(Sampler->MinLOD) &&
1410 "By construction, parseFloatParam can't produce a NaN from a "
1411 "float_literal token");
1412
1413 if (!llvm::hlsl::rootsig::verifyMaxAnisotropy(Sampler->MaxAnisotropy))
1414 ReportError(Loc, 0, 16);
1415 if (!llvm::hlsl::rootsig::verifyMipLODBias(Sampler->MipLODBias))
1416 ReportFloatError(Loc, -16.f, 15.99f);
1417 } else if (const auto *Clause =
1418 std::get_if<llvm::hlsl::rootsig::DescriptorTableClause>(
1419 &Elem)) {
1420 VerifyRegister(Loc, Clause->Reg.Number);
1421 VerifySpace(Loc, Clause->Space);
1422
1423 if (!llvm::hlsl::rootsig::verifyNumDescriptors(Clause->NumDescriptors)) {
1424 // NumDescriptor could techincally be ~0u but that is reserved for
1425 // unbounded, so the diagnostic will not report that as a valid int
1426 // value
1427 ReportError(Loc, 1, 0xfffffffe);
1428 }
1429
1430 if (!llvm::hlsl::rootsig::verifyDescriptorRangeFlag(Version, Clause->Type,
1431 Clause->Flags))
1432 ReportFlagError(Loc);
1433 }
1434 }
1435
1436 PerVisibilityBindingChecker BindingChecker(this);
1437 SmallVector<std::pair<const llvm::hlsl::rootsig::DescriptorTableClause *,
1439 UnboundClauses;
1440
1441 for (const hlsl::RootSignatureElement &RootSigElem : Elements) {
1442 const llvm::hlsl::rootsig::RootElement &Elem = RootSigElem.getElement();
1443 if (const auto *Descriptor =
1444 std::get_if<llvm::hlsl::rootsig::RootDescriptor>(&Elem)) {
1445 uint32_t LowerBound(Descriptor->Reg.Number);
1446 uint32_t UpperBound(LowerBound); // inclusive range
1447
1448 BindingChecker.trackBinding(
1449 Descriptor->Visibility,
1450 static_cast<llvm::dxil::ResourceClass>(Descriptor->Type),
1451 Descriptor->Space, LowerBound, UpperBound, &RootSigElem);
1452 } else if (const auto *Constants =
1453 std::get_if<llvm::hlsl::rootsig::RootConstants>(&Elem)) {
1454 uint32_t LowerBound(Constants->Reg.Number);
1455 uint32_t UpperBound(LowerBound); // inclusive range
1456
1457 BindingChecker.trackBinding(
1458 Constants->Visibility, llvm::dxil::ResourceClass::CBuffer,
1459 Constants->Space, LowerBound, UpperBound, &RootSigElem);
1460 } else if (const auto *Sampler =
1461 std::get_if<llvm::hlsl::rootsig::StaticSampler>(&Elem)) {
1462 uint32_t LowerBound(Sampler->Reg.Number);
1463 uint32_t UpperBound(LowerBound); // inclusive range
1464
1465 BindingChecker.trackBinding(
1466 Sampler->Visibility, llvm::dxil::ResourceClass::Sampler,
1467 Sampler->Space, LowerBound, UpperBound, &RootSigElem);
1468 } else if (const auto *Clause =
1469 std::get_if<llvm::hlsl::rootsig::DescriptorTableClause>(
1470 &Elem)) {
1471 // We'll process these once we see the table element.
1472 UnboundClauses.emplace_back(Clause, &RootSigElem);
1473 } else if (const auto *Table =
1474 std::get_if<llvm::hlsl::rootsig::DescriptorTable>(&Elem)) {
1475 assert(UnboundClauses.size() == Table->NumClauses &&
1476 "Number of unbound elements must match the number of clauses");
1477 bool HasAnySampler = false;
1478 bool HasAnyNonSampler = false;
1479 uint64_t Offset = 0;
1480 bool IsPrevUnbound = false;
1481 for (const auto &[Clause, ClauseElem] : UnboundClauses) {
1482 SourceLocation Loc = ClauseElem->getLocation();
1483 if (Clause->Type == llvm::dxil::ResourceClass::Sampler)
1484 HasAnySampler = true;
1485 else
1486 HasAnyNonSampler = true;
1487
1488 if (HasAnySampler && HasAnyNonSampler)
1489 Diag(Loc, diag::err_hlsl_invalid_mixed_resources);
1490
1491 // Relevant error will have already been reported above and needs to be
1492 // fixed before we can conduct further analysis, so shortcut error
1493 // return
1494 if (Clause->NumDescriptors == 0)
1495 return true;
1496
1497 bool IsAppending =
1498 Clause->Offset == llvm::hlsl::rootsig::DescriptorTableOffsetAppend;
1499 if (!IsAppending)
1500 Offset = Clause->Offset;
1501
1502 uint64_t RangeBound = llvm::hlsl::rootsig::computeRangeBound(
1503 Offset, Clause->NumDescriptors);
1504
1505 if (IsPrevUnbound && IsAppending)
1506 Diag(Loc, diag::err_hlsl_appending_onto_unbound);
1507 else if (!llvm::hlsl::rootsig::verifyNoOverflowedOffset(RangeBound))
1508 Diag(Loc, diag::err_hlsl_offset_overflow) << Offset << RangeBound;
1509
1510 // Update offset to be 1 past this range's bound
1511 Offset = RangeBound + 1;
1512 IsPrevUnbound = Clause->NumDescriptors ==
1513 llvm::hlsl::rootsig::NumDescriptorsUnbounded;
1514
1515 // Compute the register bounds and track resource binding
1516 uint32_t LowerBound(Clause->Reg.Number);
1517 uint32_t UpperBound = llvm::hlsl::rootsig::computeRangeBound(
1518 LowerBound, Clause->NumDescriptors);
1519
1520 BindingChecker.trackBinding(
1521 Table->Visibility,
1522 static_cast<llvm::dxil::ResourceClass>(Clause->Type), Clause->Space,
1523 LowerBound, UpperBound, ClauseElem);
1524 }
1525 UnboundClauses.clear();
1526 }
1527 }
1528
1529 return BindingChecker.checkOverlap();
1530}
1531
1533 if (AL.getNumArgs() != 1) {
1534 Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1;
1535 return;
1536 }
1537
1539 if (auto *RS = D->getAttr<RootSignatureAttr>()) {
1540 if (RS->getSignatureIdent() != Ident) {
1541 Diag(AL.getLoc(), diag::err_disallowed_duplicate_attribute) << RS;
1542 return;
1543 }
1544
1545 Diag(AL.getLoc(), diag::warn_duplicate_attribute_exact) << RS;
1546 return;
1547 }
1548
1550 if (SemaRef.LookupQualifiedName(R, D->getDeclContext()))
1551 if (auto *SignatureDecl =
1552 dyn_cast<HLSLRootSignatureDecl>(R.getFoundDecl())) {
1553 D->addAttr(::new (getASTContext()) RootSignatureAttr(
1554 getASTContext(), AL, Ident, SignatureDecl));
1555 }
1556}
1557
1559 llvm::VersionTuple SMVersion =
1560 getASTContext().getTargetInfo().getTriple().getOSVersion();
1561 bool IsDXIL = getASTContext().getTargetInfo().getTriple().getArch() ==
1562 llvm::Triple::dxil;
1563
1564 uint32_t ZMax = 1024;
1565 uint32_t ThreadMax = 1024;
1566 if (IsDXIL && SMVersion.getMajor() <= 4) {
1567 ZMax = 1;
1568 ThreadMax = 768;
1569 } else if (IsDXIL && SMVersion.getMajor() == 5) {
1570 ZMax = 64;
1571 ThreadMax = 1024;
1572 }
1573
1574 uint32_t X;
1575 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), X))
1576 return;
1577 if (X > 1024) {
1578 Diag(AL.getArgAsExpr(0)->getExprLoc(),
1579 diag::err_hlsl_numthreads_argument_oor)
1580 << 0 << 1024;
1581 return;
1582 }
1583 uint32_t Y;
1584 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(1), Y))
1585 return;
1586 if (Y > 1024) {
1587 Diag(AL.getArgAsExpr(1)->getExprLoc(),
1588 diag::err_hlsl_numthreads_argument_oor)
1589 << 1 << 1024;
1590 return;
1591 }
1592 uint32_t Z;
1593 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(2), Z))
1594 return;
1595 if (Z > ZMax) {
1596 SemaRef.Diag(AL.getArgAsExpr(2)->getExprLoc(),
1597 diag::err_hlsl_numthreads_argument_oor)
1598 << 2 << ZMax;
1599 return;
1600 }
1601
1602 if (X * Y * Z > ThreadMax) {
1603 Diag(AL.getLoc(), diag::err_hlsl_numthreads_invalid) << ThreadMax;
1604 return;
1605 }
1606
1607 HLSLNumThreadsAttr *NewAttr = mergeNumThreadsAttr(D, AL, X, Y, Z);
1608 if (NewAttr)
1609 D->addAttr(NewAttr);
1610}
1611
1612static bool isValidWaveSizeValue(unsigned Value) {
1613 return llvm::isPowerOf2_32(Value) && Value >= 4 && Value <= 128;
1614}
1615
1617 // validate that the wavesize argument is a power of 2 between 4 and 128
1618 // inclusive
1619 unsigned SpelledArgsCount = AL.getNumArgs();
1620 if (SpelledArgsCount == 0 || SpelledArgsCount > 3)
1621 return;
1622
1623 uint32_t Min;
1624 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), Min))
1625 return;
1626
1627 uint32_t Max = 0;
1628 if (SpelledArgsCount > 1 &&
1629 !SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(1), Max))
1630 return;
1631
1632 uint32_t Preferred = 0;
1633 if (SpelledArgsCount > 2 &&
1634 !SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(2), Preferred))
1635 return;
1636
1637 if (SpelledArgsCount > 2) {
1638 if (!isValidWaveSizeValue(Preferred)) {
1639 Diag(AL.getArgAsExpr(2)->getExprLoc(),
1640 diag::err_attribute_power_of_two_in_range)
1641 << AL << llvm::dxil::MinWaveSize << llvm::dxil::MaxWaveSize
1642 << Preferred;
1643 return;
1644 }
1645 // Preferred not in range.
1646 if (Preferred < Min || Preferred > Max) {
1647 Diag(AL.getArgAsExpr(2)->getExprLoc(),
1648 diag::err_attribute_power_of_two_in_range)
1649 << AL << Min << Max << Preferred;
1650 return;
1651 }
1652 } else if (SpelledArgsCount > 1) {
1653 if (!isValidWaveSizeValue(Max)) {
1654 Diag(AL.getArgAsExpr(1)->getExprLoc(),
1655 diag::err_attribute_power_of_two_in_range)
1656 << AL << llvm::dxil::MinWaveSize << llvm::dxil::MaxWaveSize << Max;
1657 return;
1658 }
1659 if (Max < Min) {
1660 Diag(AL.getLoc(), diag::err_attribute_argument_invalid) << AL << 1;
1661 return;
1662 } else if (Max == Min) {
1663 Diag(AL.getLoc(), diag::warn_attr_min_eq_max) << AL;
1664 }
1665 } else {
1666 if (!isValidWaveSizeValue(Min)) {
1667 Diag(AL.getArgAsExpr(0)->getExprLoc(),
1668 diag::err_attribute_power_of_two_in_range)
1669 << AL << llvm::dxil::MinWaveSize << llvm::dxil::MaxWaveSize << Min;
1670 return;
1671 }
1672 }
1673
1674 HLSLWaveSizeAttr *NewAttr =
1675 mergeWaveSizeAttr(D, AL, Min, Max, Preferred, SpelledArgsCount);
1676 if (NewAttr)
1677 D->addAttr(NewAttr);
1678}
1679
1681 uint32_t ID;
1682 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), ID))
1683 return;
1684 D->addAttr(::new (getASTContext())
1685 HLSLVkExtBuiltinInputAttr(getASTContext(), AL, ID));
1686}
1687
1689 uint32_t Id;
1690 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), Id))
1691 return;
1692 HLSLVkConstantIdAttr *NewAttr = mergeVkConstantIdAttr(D, AL, Id);
1693 if (NewAttr)
1694 D->addAttr(NewAttr);
1695}
1696
1698 uint32_t Binding = 0;
1699 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), Binding))
1700 return;
1701 uint32_t Set = 0;
1702 if (AL.getNumArgs() > 1 &&
1703 !SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(1), Set))
1704 return;
1705
1706 D->addAttr(::new (getASTContext())
1707 HLSLVkBindingAttr(getASTContext(), AL, Binding, Set));
1708}
1709
1711 const auto *VT = T->getAs<VectorType>();
1712
1713 if (!T->hasUnsignedIntegerRepresentation() ||
1714 (VT && VT->getNumElements() > 3)) {
1715 Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type)
1716 << AL << "uint/uint2/uint3";
1717 return false;
1718 }
1719
1720 return true;
1721}
1722
1724 const auto *VT = T->getAs<VectorType>();
1725 if (!T->hasFloatingRepresentation() || (VT && VT->getNumElements() > 4)) {
1726 Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type)
1727 << AL << "float/float1/float2/float3/float4";
1728 return false;
1729 }
1730
1731 return true;
1732}
1733
1735 std::optional<unsigned> Index) {
1736 std::string SemanticName = AL.getAttrName()->getName().upper();
1737
1738 auto *VD = cast<ValueDecl>(D);
1739 QualType ValueType = VD->getType();
1740 if (auto *FD = dyn_cast<FunctionDecl>(D))
1741 ValueType = FD->getReturnType();
1742
1743 bool IsOutput = false;
1744 if (HLSLParamModifierAttr *MA = D->getAttr<HLSLParamModifierAttr>()) {
1745 if (MA->isOut()) {
1746 IsOutput = true;
1747 ValueType = cast<ReferenceType>(ValueType)->getPointeeType();
1748 }
1749 }
1750
1751 Attr *Attribute = nullptr;
1752 if (SemanticName == "SV_DISPATCHTHREADID") {
1753 diagnoseInputIDType(ValueType, AL);
1754 if (IsOutput)
1755 Diag(AL.getLoc(), diag::err_hlsl_semantic_output_not_supported) << AL;
1756 Attribute =
1758 } else if (SemanticName == "SV_GROUPINDEX") {
1759 if (IsOutput)
1760 Diag(AL.getLoc(), diag::err_hlsl_semantic_output_not_supported) << AL;
1761 Attribute = createSemanticAttr<HLSLSV_GroupIndexAttr>(AL, nullptr, Index);
1762 } else if (SemanticName == "SV_GROUPTHREADID") {
1763 diagnoseInputIDType(ValueType, AL);
1764 if (IsOutput)
1765 Diag(AL.getLoc(), diag::err_hlsl_semantic_output_not_supported) << AL;
1766 Attribute =
1768 } else if (SemanticName == "SV_GROUPID") {
1769 diagnoseInputIDType(ValueType, AL);
1770 if (IsOutput)
1771 Diag(AL.getLoc(), diag::err_hlsl_semantic_output_not_supported) << AL;
1772 Attribute = createSemanticAttr<HLSLSV_GroupIDAttr>(AL, nullptr, Index);
1773 } else if (SemanticName == "SV_POSITION") {
1774 const auto *VT = ValueType->getAs<VectorType>();
1775 if (!ValueType->hasFloatingRepresentation() ||
1776 (VT && VT->getNumElements() > 4))
1777 Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type)
1778 << AL << "float/float1/float2/float3/float4";
1779 Attribute = createSemanticAttr<HLSLSV_PositionAttr>(AL, nullptr, Index);
1780 } else
1781 Diag(AL.getLoc(), diag::err_hlsl_unknown_semantic) << AL;
1782
1783 if (!Attribute)
1784 return;
1785 D->addAttr(Attribute);
1786}
1787
1789 uint32_t IndexValue, ExplicitIndex;
1790 SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), IndexValue);
1791 SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(1), ExplicitIndex);
1792 assert(IndexValue > 0 ? ExplicitIndex : true);
1793 std::optional<unsigned> Index =
1794 ExplicitIndex ? std::optional<unsigned>(IndexValue) : std::nullopt;
1795
1796 if (AL.getAttrName()->getName().starts_with_insensitive("SV_"))
1797 diagnoseSystemSemanticAttr(D, AL, Index);
1798 else
1799 D->addAttr(createSemanticAttr<HLSLUserSemanticAttr>(AL, nullptr, Index));
1800}
1801
1804 Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_ast_node)
1805 << AL << "shader constant in a constant buffer";
1806 return;
1807 }
1808
1809 uint32_t SubComponent;
1810 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), SubComponent))
1811 return;
1812 uint32_t Component;
1813 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(1), Component))
1814 return;
1815
1816 QualType T = cast<VarDecl>(D)->getType().getCanonicalType();
1817 // Check if T is an array or struct type.
1818 // TODO: mark matrix type as aggregate type.
1819 bool IsAggregateTy = (T->isArrayType() || T->isStructureType());
1820
1821 // Check Component is valid for T.
1822 if (Component) {
1823 unsigned Size = getASTContext().getTypeSize(T);
1824 if (IsAggregateTy || Size > 128) {
1825 Diag(AL.getLoc(), diag::err_hlsl_packoffset_cross_reg_boundary);
1826 return;
1827 } else {
1828 // Make sure Component + sizeof(T) <= 4.
1829 if ((Component * 32 + Size) > 128) {
1830 Diag(AL.getLoc(), diag::err_hlsl_packoffset_cross_reg_boundary);
1831 return;
1832 }
1833 QualType EltTy = T;
1834 if (const auto *VT = T->getAs<VectorType>())
1835 EltTy = VT->getElementType();
1836 unsigned Align = getASTContext().getTypeAlign(EltTy);
1837 if (Align > 32 && Component == 1) {
1838 // NOTE: Component 3 will hit err_hlsl_packoffset_cross_reg_boundary.
1839 // So we only need to check Component 1 here.
1840 Diag(AL.getLoc(), diag::err_hlsl_packoffset_alignment_mismatch)
1841 << Align << EltTy;
1842 return;
1843 }
1844 }
1845 }
1846
1847 D->addAttr(::new (getASTContext()) HLSLPackOffsetAttr(
1848 getASTContext(), AL, SubComponent, Component));
1849}
1850
1852 StringRef Str;
1853 SourceLocation ArgLoc;
1854 if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
1855 return;
1856
1857 llvm::Triple::EnvironmentType ShaderType;
1858 if (!HLSLShaderAttr::ConvertStrToEnvironmentType(Str, ShaderType)) {
1859 Diag(AL.getLoc(), diag::warn_attribute_type_not_supported)
1860 << AL << Str << ArgLoc;
1861 return;
1862 }
1863
1864 // FIXME: check function match the shader stage.
1865
1866 HLSLShaderAttr *NewAttr = mergeShaderAttr(D, AL, ShaderType);
1867 if (NewAttr)
1868 D->addAttr(NewAttr);
1869}
1870
1872 Sema &S, QualType Wrapped, ArrayRef<const Attr *> AttrList,
1873 QualType &ResType, HLSLAttributedResourceLocInfo *LocInfo) {
1874 assert(AttrList.size() && "expected list of resource attributes");
1875
1876 QualType ContainedTy = QualType();
1877 TypeSourceInfo *ContainedTyInfo = nullptr;
1878 SourceLocation LocBegin = AttrList[0]->getRange().getBegin();
1879 SourceLocation LocEnd = AttrList[0]->getRange().getEnd();
1880
1881 HLSLAttributedResourceType::Attributes ResAttrs;
1882
1883 bool HasResourceClass = false;
1884 for (const Attr *A : AttrList) {
1885 if (!A)
1886 continue;
1887 LocEnd = A->getRange().getEnd();
1888 switch (A->getKind()) {
1889 case attr::HLSLResourceClass: {
1890 ResourceClass RC = cast<HLSLResourceClassAttr>(A)->getResourceClass();
1891 if (HasResourceClass) {
1892 S.Diag(A->getLocation(), ResAttrs.ResourceClass == RC
1893 ? diag::warn_duplicate_attribute_exact
1894 : diag::warn_duplicate_attribute)
1895 << A;
1896 return false;
1897 }
1898 ResAttrs.ResourceClass = RC;
1899 HasResourceClass = true;
1900 break;
1901 }
1902 case attr::HLSLROV:
1903 if (ResAttrs.IsROV) {
1904 S.Diag(A->getLocation(), diag::warn_duplicate_attribute_exact) << A;
1905 return false;
1906 }
1907 ResAttrs.IsROV = true;
1908 break;
1909 case attr::HLSLRawBuffer:
1910 if (ResAttrs.RawBuffer) {
1911 S.Diag(A->getLocation(), diag::warn_duplicate_attribute_exact) << A;
1912 return false;
1913 }
1914 ResAttrs.RawBuffer = true;
1915 break;
1916 case attr::HLSLIsCounter:
1917 if (ResAttrs.IsCounter) {
1918 S.Diag(A->getLocation(), diag::warn_duplicate_attribute_exact) << A;
1919 return false;
1920 }
1921 ResAttrs.IsCounter = true;
1922 break;
1923 case attr::HLSLContainedType: {
1924 const HLSLContainedTypeAttr *CTAttr = cast<HLSLContainedTypeAttr>(A);
1925 QualType Ty = CTAttr->getType();
1926 if (!ContainedTy.isNull()) {
1927 S.Diag(A->getLocation(), ContainedTy == Ty
1928 ? diag::warn_duplicate_attribute_exact
1929 : diag::warn_duplicate_attribute)
1930 << A;
1931 return false;
1932 }
1933 ContainedTy = Ty;
1934 ContainedTyInfo = CTAttr->getTypeLoc();
1935 break;
1936 }
1937 default:
1938 llvm_unreachable("unhandled resource attribute type");
1939 }
1940 }
1941
1942 if (!HasResourceClass) {
1943 S.Diag(AttrList.back()->getRange().getEnd(),
1944 diag::err_hlsl_missing_resource_class);
1945 return false;
1946 }
1947
1949 Wrapped, ContainedTy, ResAttrs);
1950
1951 if (LocInfo && ContainedTyInfo) {
1952 LocInfo->Range = SourceRange(LocBegin, LocEnd);
1953 LocInfo->ContainedTyInfo = ContainedTyInfo;
1954 }
1955 return true;
1956}
1957
1958// Validates and creates an HLSL attribute that is applied as type attribute on
1959// HLSL resource. The attributes are collected in HLSLResourcesTypeAttrs and at
1960// the end of the declaration they are applied to the declaration type by
1961// wrapping it in HLSLAttributedResourceType.
1963 // only allow resource type attributes on intangible types
1964 if (!T->isHLSLResourceType()) {
1965 Diag(AL.getLoc(), diag::err_hlsl_attribute_needs_intangible_type)
1966 << AL << getASTContext().HLSLResourceTy;
1967 return false;
1968 }
1969
1970 // validate number of arguments
1971 if (!AL.checkExactlyNumArgs(SemaRef, AL.getMinArgs()))
1972 return false;
1973
1974 Attr *A = nullptr;
1975
1979 {
1980 AttributeCommonInfo::AS_CXX11, 0, false /*IsAlignas*/,
1981 false /*IsRegularKeywordAttribute*/
1982 });
1983
1984 switch (AL.getKind()) {
1985 case ParsedAttr::AT_HLSLResourceClass: {
1986 if (!AL.isArgIdent(0)) {
1987 Diag(AL.getLoc(), diag::err_attribute_argument_type)
1988 << AL << AANT_ArgumentIdentifier;
1989 return false;
1990 }
1991
1992 IdentifierLoc *Loc = AL.getArgAsIdent(0);
1993 StringRef Identifier = Loc->getIdentifierInfo()->getName();
1994 SourceLocation ArgLoc = Loc->getLoc();
1995
1996 // Validate resource class value
1997 ResourceClass RC;
1998 if (!HLSLResourceClassAttr::ConvertStrToResourceClass(Identifier, RC)) {
1999 Diag(ArgLoc, diag::warn_attribute_type_not_supported)
2000 << "ResourceClass" << Identifier;
2001 return false;
2002 }
2003 A = HLSLResourceClassAttr::Create(getASTContext(), RC, ACI);
2004 break;
2005 }
2006
2007 case ParsedAttr::AT_HLSLROV:
2008 A = HLSLROVAttr::Create(getASTContext(), ACI);
2009 break;
2010
2011 case ParsedAttr::AT_HLSLRawBuffer:
2012 A = HLSLRawBufferAttr::Create(getASTContext(), ACI);
2013 break;
2014
2015 case ParsedAttr::AT_HLSLIsCounter:
2016 A = HLSLIsCounterAttr::Create(getASTContext(), ACI);
2017 break;
2018
2019 case ParsedAttr::AT_HLSLContainedType: {
2020 if (AL.getNumArgs() != 1 && !AL.hasParsedType()) {
2021 Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1;
2022 return false;
2023 }
2024
2025 TypeSourceInfo *TSI = nullptr;
2026 QualType QT = SemaRef.GetTypeFromParser(AL.getTypeArg(), &TSI);
2027 assert(TSI && "no type source info for attribute argument");
2028 if (SemaRef.RequireCompleteType(TSI->getTypeLoc().getBeginLoc(), QT,
2029 diag::err_incomplete_type))
2030 return false;
2031 A = HLSLContainedTypeAttr::Create(getASTContext(), TSI, ACI);
2032 break;
2033 }
2034
2035 default:
2036 llvm_unreachable("unhandled HLSL attribute");
2037 }
2038
2039 HLSLResourcesTypeAttrs.emplace_back(A);
2040 return true;
2041}
2042
2043// Combines all resource type attributes and creates HLSLAttributedResourceType.
2045 if (!HLSLResourcesTypeAttrs.size())
2046 return CurrentType;
2047
2048 QualType QT = CurrentType;
2051 HLSLResourcesTypeAttrs, QT, &LocInfo)) {
2052 const HLSLAttributedResourceType *RT =
2054
2055 // Temporarily store TypeLoc information for the new type.
2056 // It will be transferred to HLSLAttributesResourceTypeLoc
2057 // shortly after the type is created by TypeSpecLocFiller which
2058 // will call the TakeLocForHLSLAttribute method below.
2059 LocsForHLSLAttributedResources.insert(std::pair(RT, LocInfo));
2060 }
2061 HLSLResourcesTypeAttrs.clear();
2062 return QT;
2063}
2064
2065// Returns source location for the HLSLAttributedResourceType
2067SemaHLSL::TakeLocForHLSLAttribute(const HLSLAttributedResourceType *RT) {
2068 HLSLAttributedResourceLocInfo LocInfo = {};
2069 auto I = LocsForHLSLAttributedResources.find(RT);
2070 if (I != LocsForHLSLAttributedResources.end()) {
2071 LocInfo = I->second;
2072 LocsForHLSLAttributedResources.erase(I);
2073 return LocInfo;
2074 }
2075 LocInfo.Range = SourceRange();
2076 return LocInfo;
2077}
2078
2079// Walks though the global variable declaration, collects all resource binding
2080// requirements and adds them to Bindings
2081void SemaHLSL::collectResourceBindingsOnUserRecordDecl(const VarDecl *VD,
2082 const RecordType *RT) {
2083 const RecordDecl *RD = RT->getDecl()->getDefinitionOrSelf();
2084 for (FieldDecl *FD : RD->fields()) {
2085 const Type *Ty = FD->getType()->getUnqualifiedDesugaredType();
2086
2087 // Unwrap arrays
2088 // FIXME: Calculate array size while unwrapping
2089 assert(!Ty->isIncompleteArrayType() &&
2090 "incomplete arrays inside user defined types are not supported");
2091 while (Ty->isConstantArrayType()) {
2094 }
2095
2096 if (!Ty->isRecordType())
2097 continue;
2098
2099 if (const HLSLAttributedResourceType *AttrResType =
2100 HLSLAttributedResourceType::findHandleTypeOnResource(Ty)) {
2101 // Add a new DeclBindingInfo to Bindings if it does not already exist
2102 ResourceClass RC = AttrResType->getAttrs().ResourceClass;
2103 DeclBindingInfo *DBI = Bindings.getDeclBindingInfo(VD, RC);
2104 if (!DBI)
2105 Bindings.addDeclBindingInfo(VD, RC);
2106 } else if (const RecordType *RT = dyn_cast<RecordType>(Ty)) {
2107 // Recursively scan embedded struct or class; it would be nice to do this
2108 // without recursion, but tricky to correctly calculate the size of the
2109 // binding, which is something we are probably going to need to do later
2110 // on. Hopefully nesting of structs in structs too many levels is
2111 // unlikely.
2112 collectResourceBindingsOnUserRecordDecl(VD, RT);
2113 }
2114 }
2115}
2116
2117// Diagnose localized register binding errors for a single binding; does not
2118// diagnose resource binding on user record types, that will be done later
2119// in processResourceBindingOnDecl based on the information collected in
2120// collectResourceBindingsOnVarDecl.
2121// Returns false if the register binding is not valid.
2123 Decl *D, RegisterType RegType,
2124 bool SpecifiedSpace) {
2125 int RegTypeNum = static_cast<int>(RegType);
2126
2127 // check if the decl type is groupshared
2128 if (D->hasAttr<HLSLGroupSharedAddressSpaceAttr>()) {
2129 S.Diag(ArgLoc, diag::err_hlsl_binding_type_mismatch) << RegTypeNum;
2130 return false;
2131 }
2132
2133 // Cbuffers and Tbuffers are HLSLBufferDecl types
2134 if (HLSLBufferDecl *CBufferOrTBuffer = dyn_cast<HLSLBufferDecl>(D)) {
2135 ResourceClass RC = CBufferOrTBuffer->isCBuffer() ? ResourceClass::CBuffer
2136 : ResourceClass::SRV;
2137 if (RegType == getRegisterType(RC))
2138 return true;
2139
2140 S.Diag(D->getLocation(), diag::err_hlsl_binding_type_mismatch)
2141 << RegTypeNum;
2142 return false;
2143 }
2144
2145 // Samplers, UAVs, and SRVs are VarDecl types
2146 assert(isa<VarDecl>(D) && "D is expected to be VarDecl or HLSLBufferDecl");
2147 VarDecl *VD = cast<VarDecl>(D);
2148
2149 // Resource
2150 if (const HLSLAttributedResourceType *AttrResType =
2151 HLSLAttributedResourceType::findHandleTypeOnResource(
2152 VD->getType().getTypePtr())) {
2153 if (RegType == getRegisterType(AttrResType))
2154 return true;
2155
2156 S.Diag(D->getLocation(), diag::err_hlsl_binding_type_mismatch)
2157 << RegTypeNum;
2158 return false;
2159 }
2160
2161 const clang::Type *Ty = VD->getType().getTypePtr();
2162 while (Ty->isArrayType())
2164
2165 // Basic types
2166 if (Ty->isArithmeticType() || Ty->isVectorType()) {
2167 bool DeclaredInCOrTBuffer = isa<HLSLBufferDecl>(D->getDeclContext());
2168 if (SpecifiedSpace && !DeclaredInCOrTBuffer)
2169 S.Diag(ArgLoc, diag::err_hlsl_space_on_global_constant);
2170
2171 if (!DeclaredInCOrTBuffer && (Ty->isIntegralType(S.getASTContext()) ||
2172 Ty->isFloatingType() || Ty->isVectorType())) {
2173 // Register annotation on default constant buffer declaration ($Globals)
2174 if (RegType == RegisterType::CBuffer)
2175 S.Diag(ArgLoc, diag::warn_hlsl_deprecated_register_type_b);
2176 else if (RegType != RegisterType::C)
2177 S.Diag(ArgLoc, diag::err_hlsl_binding_type_mismatch) << RegTypeNum;
2178 else
2179 return true;
2180 } else {
2181 if (RegType == RegisterType::C)
2182 S.Diag(ArgLoc, diag::warn_hlsl_register_type_c_packoffset);
2183 else
2184 S.Diag(ArgLoc, diag::err_hlsl_binding_type_mismatch) << RegTypeNum;
2185 }
2186 return false;
2187 }
2188 if (Ty->isRecordType())
2189 // RecordTypes will be diagnosed in processResourceBindingOnDecl
2190 // that is called from ActOnVariableDeclarator
2191 return true;
2192
2193 // Anything else is an error
2194 S.Diag(ArgLoc, diag::err_hlsl_binding_type_mismatch) << RegTypeNum;
2195 return false;
2196}
2197
2199 RegisterType regType) {
2200 // make sure that there are no two register annotations
2201 // applied to the decl with the same register type
2202 bool RegisterTypesDetected[5] = {false};
2203 RegisterTypesDetected[static_cast<int>(regType)] = true;
2204
2205 for (auto it = TheDecl->attr_begin(); it != TheDecl->attr_end(); ++it) {
2206 if (HLSLResourceBindingAttr *attr =
2207 dyn_cast<HLSLResourceBindingAttr>(*it)) {
2208
2209 RegisterType otherRegType = attr->getRegisterType();
2210 if (RegisterTypesDetected[static_cast<int>(otherRegType)]) {
2211 int otherRegTypeNum = static_cast<int>(otherRegType);
2212 S.Diag(TheDecl->getLocation(),
2213 diag::err_hlsl_duplicate_register_annotation)
2214 << otherRegTypeNum;
2215 return false;
2216 }
2217 RegisterTypesDetected[static_cast<int>(otherRegType)] = true;
2218 }
2219 }
2220 return true;
2221}
2222
2224 Decl *D, RegisterType RegType,
2225 bool SpecifiedSpace) {
2226
2227 // exactly one of these two types should be set
2228 assert(((isa<VarDecl>(D) && !isa<HLSLBufferDecl>(D)) ||
2229 (!isa<VarDecl>(D) && isa<HLSLBufferDecl>(D))) &&
2230 "expecting VarDecl or HLSLBufferDecl");
2231
2232 // check if the declaration contains resource matching the register type
2233 if (!DiagnoseLocalRegisterBinding(S, ArgLoc, D, RegType, SpecifiedSpace))
2234 return false;
2235
2236 // next, if multiple register annotations exist, check that none conflict.
2237 return ValidateMultipleRegisterAnnotations(S, D, RegType);
2238}
2239
2241 if (VarDecl *VD = dyn_cast<VarDecl>(TheDecl)) {
2242 QualType Ty = VD->getType();
2243 if (const auto *IAT = dyn_cast<IncompleteArrayType>(Ty))
2244 Ty = IAT->getElementType();
2245 if (SemaRef.RequireCompleteType(TheDecl->getBeginLoc(), Ty,
2246 diag::err_incomplete_type))
2247 return;
2248 }
2249
2250 StringRef Slot = "";
2251 StringRef Space = "";
2252 SourceLocation SlotLoc, SpaceLoc;
2253
2254 if (!AL.isArgIdent(0)) {
2255 Diag(AL.getLoc(), diag::err_attribute_argument_type)
2256 << AL << AANT_ArgumentIdentifier;
2257 return;
2258 }
2259 IdentifierLoc *Loc = AL.getArgAsIdent(0);
2260
2261 if (AL.getNumArgs() == 2) {
2262 Slot = Loc->getIdentifierInfo()->getName();
2263 SlotLoc = Loc->getLoc();
2264 if (!AL.isArgIdent(1)) {
2265 Diag(AL.getLoc(), diag::err_attribute_argument_type)
2266 << AL << AANT_ArgumentIdentifier;
2267 return;
2268 }
2269 Loc = AL.getArgAsIdent(1);
2270 Space = Loc->getIdentifierInfo()->getName();
2271 SpaceLoc = Loc->getLoc();
2272 } else {
2273 StringRef Str = Loc->getIdentifierInfo()->getName();
2274 if (Str.starts_with("space")) {
2275 Space = Str;
2276 SpaceLoc = Loc->getLoc();
2277 } else {
2278 Slot = Str;
2279 SlotLoc = Loc->getLoc();
2280 Space = "space0";
2281 }
2282 }
2283
2284 RegisterType RegType = RegisterType::SRV;
2285 std::optional<unsigned> SlotNum;
2286 unsigned SpaceNum = 0;
2287
2288 // Validate slot
2289 if (!Slot.empty()) {
2290 if (!convertToRegisterType(Slot, &RegType)) {
2291 Diag(SlotLoc, diag::err_hlsl_binding_type_invalid) << Slot.substr(0, 1);
2292 return;
2293 }
2294 if (RegType == RegisterType::I) {
2295 Diag(SlotLoc, diag::warn_hlsl_deprecated_register_type_i);
2296 return;
2297 }
2298 StringRef SlotNumStr = Slot.substr(1);
2299 unsigned N;
2300 if (SlotNumStr.getAsInteger(10, N)) {
2301 Diag(SlotLoc, diag::err_hlsl_unsupported_register_number);
2302 return;
2303 }
2304 SlotNum = N;
2305 }
2306
2307 // Validate space
2308 if (!Space.starts_with("space")) {
2309 Diag(SpaceLoc, diag::err_hlsl_expected_space) << Space;
2310 return;
2311 }
2312 StringRef SpaceNumStr = Space.substr(5);
2313 if (SpaceNumStr.getAsInteger(10, SpaceNum)) {
2314 Diag(SpaceLoc, diag::err_hlsl_expected_space) << Space;
2315 return;
2316 }
2317
2318 // If we have slot, diagnose it is the right register type for the decl
2319 if (SlotNum.has_value())
2320 if (!DiagnoseHLSLRegisterAttribute(SemaRef, SlotLoc, TheDecl, RegType,
2321 !SpaceLoc.isInvalid()))
2322 return;
2323
2324 HLSLResourceBindingAttr *NewAttr =
2325 HLSLResourceBindingAttr::Create(getASTContext(), Slot, Space, AL);
2326 if (NewAttr) {
2327 NewAttr->setBinding(RegType, SlotNum, SpaceNum);
2328 TheDecl->addAttr(NewAttr);
2329 }
2330}
2331
2333 HLSLParamModifierAttr *NewAttr = mergeParamModifierAttr(
2334 D, AL,
2335 static_cast<HLSLParamModifierAttr::Spelling>(AL.getSemanticSpelling()));
2336 if (NewAttr)
2337 D->addAttr(NewAttr);
2338}
2339
2340namespace {
2341
2342/// This class implements HLSL availability diagnostics for default
2343/// and relaxed mode
2344///
2345/// The goal of this diagnostic is to emit an error or warning when an
2346/// unavailable API is found in code that is reachable from the shader
2347/// entry function or from an exported function (when compiling a shader
2348/// library).
2349///
2350/// This is done by traversing the AST of all shader entry point functions
2351/// and of all exported functions, and any functions that are referenced
2352/// from this AST. In other words, any functions that are reachable from
2353/// the entry points.
2354class DiagnoseHLSLAvailability : public DynamicRecursiveASTVisitor {
2355 Sema &SemaRef;
2356
2357 // Stack of functions to be scaned
2359
2360 // Tracks which environments functions have been scanned in.
2361 //
2362 // Maps FunctionDecl to an unsigned number that represents the set of shader
2363 // environments the function has been scanned for.
2364 // The llvm::Triple::EnvironmentType enum values for shader stages guaranteed
2365 // to be numbered from llvm::Triple::Pixel to llvm::Triple::Amplification
2366 // (verified by static_asserts in Triple.cpp), we can use it to index
2367 // individual bits in the set, as long as we shift the values to start with 0
2368 // by subtracting the value of llvm::Triple::Pixel first.
2369 //
2370 // The N'th bit in the set will be set if the function has been scanned
2371 // in shader environment whose llvm::Triple::EnvironmentType integer value
2372 // equals (llvm::Triple::Pixel + N).
2373 //
2374 // For example, if a function has been scanned in compute and pixel stage
2375 // environment, the value will be 0x21 (100001 binary) because:
2376 //
2377 // (int)(llvm::Triple::Pixel - llvm::Triple::Pixel) == 0
2378 // (int)(llvm::Triple::Compute - llvm::Triple::Pixel) == 5
2379 //
2380 // A FunctionDecl is mapped to 0 (or not included in the map) if it has not
2381 // been scanned in any environment.
2382 llvm::DenseMap<const FunctionDecl *, unsigned> ScannedDecls;
2383
2384 // Do not access these directly, use the get/set methods below to make
2385 // sure the values are in sync
2386 llvm::Triple::EnvironmentType CurrentShaderEnvironment;
2387 unsigned CurrentShaderStageBit;
2388
2389 // True if scanning a function that was already scanned in a different
2390 // shader stage context, and therefore we should not report issues that
2391 // depend only on shader model version because they would be duplicate.
2392 bool ReportOnlyShaderStageIssues;
2393
2394 // Helper methods for dealing with current stage context / environment
2395 void SetShaderStageContext(llvm::Triple::EnvironmentType ShaderType) {
2396 static_assert(sizeof(unsigned) >= 4);
2397 assert(HLSLShaderAttr::isValidShaderType(ShaderType));
2398 assert((unsigned)(ShaderType - llvm::Triple::Pixel) < 31 &&
2399 "ShaderType is too big for this bitmap"); // 31 is reserved for
2400 // "unknown"
2401
2402 unsigned bitmapIndex = ShaderType - llvm::Triple::Pixel;
2403 CurrentShaderEnvironment = ShaderType;
2404 CurrentShaderStageBit = (1 << bitmapIndex);
2405 }
2406
2407 void SetUnknownShaderStageContext() {
2408 CurrentShaderEnvironment = llvm::Triple::UnknownEnvironment;
2409 CurrentShaderStageBit = (1 << 31);
2410 }
2411
2412 llvm::Triple::EnvironmentType GetCurrentShaderEnvironment() const {
2413 return CurrentShaderEnvironment;
2414 }
2415
2416 bool InUnknownShaderStageContext() const {
2417 return CurrentShaderEnvironment == llvm::Triple::UnknownEnvironment;
2418 }
2419
2420 // Helper methods for dealing with shader stage bitmap
2421 void AddToScannedFunctions(const FunctionDecl *FD) {
2422 unsigned &ScannedStages = ScannedDecls[FD];
2423 ScannedStages |= CurrentShaderStageBit;
2424 }
2425
2426 unsigned GetScannedStages(const FunctionDecl *FD) { return ScannedDecls[FD]; }
2427
2428 bool WasAlreadyScannedInCurrentStage(const FunctionDecl *FD) {
2429 return WasAlreadyScannedInCurrentStage(GetScannedStages(FD));
2430 }
2431
2432 bool WasAlreadyScannedInCurrentStage(unsigned ScannerStages) {
2433 return ScannerStages & CurrentShaderStageBit;
2434 }
2435
2436 static bool NeverBeenScanned(unsigned ScannedStages) {
2437 return ScannedStages == 0;
2438 }
2439
2440 // Scanning methods
2441 void HandleFunctionOrMethodRef(FunctionDecl *FD, Expr *RefExpr);
2442 void CheckDeclAvailability(NamedDecl *D, const AvailabilityAttr *AA,
2443 SourceRange Range);
2444 const AvailabilityAttr *FindAvailabilityAttr(const Decl *D);
2445 bool HasMatchingEnvironmentOrNone(const AvailabilityAttr *AA);
2446
2447public:
2448 DiagnoseHLSLAvailability(Sema &SemaRef)
2449 : SemaRef(SemaRef),
2450 CurrentShaderEnvironment(llvm::Triple::UnknownEnvironment),
2451 CurrentShaderStageBit(0), ReportOnlyShaderStageIssues(false) {}
2452
2453 // AST traversal methods
2454 void RunOnTranslationUnit(const TranslationUnitDecl *TU);
2455 void RunOnFunction(const FunctionDecl *FD);
2456
2457 bool VisitDeclRefExpr(DeclRefExpr *DRE) override {
2458 FunctionDecl *FD = llvm::dyn_cast<FunctionDecl>(DRE->getDecl());
2459 if (FD)
2460 HandleFunctionOrMethodRef(FD, DRE);
2461 return true;
2462 }
2463
2464 bool VisitMemberExpr(MemberExpr *ME) override {
2465 FunctionDecl *FD = llvm::dyn_cast<FunctionDecl>(ME->getMemberDecl());
2466 if (FD)
2467 HandleFunctionOrMethodRef(FD, ME);
2468 return true;
2469 }
2470};
2471
2472void DiagnoseHLSLAvailability::HandleFunctionOrMethodRef(FunctionDecl *FD,
2473 Expr *RefExpr) {
2474 assert((isa<DeclRefExpr>(RefExpr) || isa<MemberExpr>(RefExpr)) &&
2475 "expected DeclRefExpr or MemberExpr");
2476
2477 // has a definition -> add to stack to be scanned
2478 const FunctionDecl *FDWithBody = nullptr;
2479 if (FD->hasBody(FDWithBody)) {
2480 if (!WasAlreadyScannedInCurrentStage(FDWithBody))
2481 DeclsToScan.push_back(FDWithBody);
2482 return;
2483 }
2484
2485 // no body -> diagnose availability
2486 const AvailabilityAttr *AA = FindAvailabilityAttr(FD);
2487 if (AA)
2488 CheckDeclAvailability(
2489 FD, AA, SourceRange(RefExpr->getBeginLoc(), RefExpr->getEndLoc()));
2490}
2491
2492void DiagnoseHLSLAvailability::RunOnTranslationUnit(
2493 const TranslationUnitDecl *TU) {
2494
2495 // Iterate over all shader entry functions and library exports, and for those
2496 // that have a body (definiton), run diag scan on each, setting appropriate
2497 // shader environment context based on whether it is a shader entry function
2498 // or an exported function. Exported functions can be in namespaces and in
2499 // export declarations so we need to scan those declaration contexts as well.
2501 DeclContextsToScan.push_back(TU);
2502
2503 while (!DeclContextsToScan.empty()) {
2504 const DeclContext *DC = DeclContextsToScan.pop_back_val();
2505 for (auto &D : DC->decls()) {
2506 // do not scan implicit declaration generated by the implementation
2507 if (D->isImplicit())
2508 continue;
2509
2510 // for namespace or export declaration add the context to the list to be
2511 // scanned later
2512 if (llvm::dyn_cast<NamespaceDecl>(D) || llvm::dyn_cast<ExportDecl>(D)) {
2513 DeclContextsToScan.push_back(llvm::dyn_cast<DeclContext>(D));
2514 continue;
2515 }
2516
2517 // skip over other decls or function decls without body
2518 const FunctionDecl *FD = llvm::dyn_cast<FunctionDecl>(D);
2519 if (!FD || !FD->isThisDeclarationADefinition())
2520 continue;
2521
2522 // shader entry point
2523 if (HLSLShaderAttr *ShaderAttr = FD->getAttr<HLSLShaderAttr>()) {
2524 SetShaderStageContext(ShaderAttr->getType());
2525 RunOnFunction(FD);
2526 continue;
2527 }
2528 // exported library function
2529 // FIXME: replace this loop with external linkage check once issue #92071
2530 // is resolved
2531 bool isExport = FD->isInExportDeclContext();
2532 if (!isExport) {
2533 for (const auto *Redecl : FD->redecls()) {
2534 if (Redecl->isInExportDeclContext()) {
2535 isExport = true;
2536 break;
2537 }
2538 }
2539 }
2540 if (isExport) {
2541 SetUnknownShaderStageContext();
2542 RunOnFunction(FD);
2543 continue;
2544 }
2545 }
2546 }
2547}
2548
2549void DiagnoseHLSLAvailability::RunOnFunction(const FunctionDecl *FD) {
2550 assert(DeclsToScan.empty() && "DeclsToScan should be empty");
2551 DeclsToScan.push_back(FD);
2552
2553 while (!DeclsToScan.empty()) {
2554 // Take one decl from the stack and check it by traversing its AST.
2555 // For any CallExpr found during the traversal add it's callee to the top of
2556 // the stack to be processed next. Functions already processed are stored in
2557 // ScannedDecls.
2558 const FunctionDecl *FD = DeclsToScan.pop_back_val();
2559
2560 // Decl was already scanned
2561 const unsigned ScannedStages = GetScannedStages(FD);
2562 if (WasAlreadyScannedInCurrentStage(ScannedStages))
2563 continue;
2564
2565 ReportOnlyShaderStageIssues = !NeverBeenScanned(ScannedStages);
2566
2567 AddToScannedFunctions(FD);
2568 TraverseStmt(FD->getBody());
2569 }
2570}
2571
2572bool DiagnoseHLSLAvailability::HasMatchingEnvironmentOrNone(
2573 const AvailabilityAttr *AA) {
2574 IdentifierInfo *IIEnvironment = AA->getEnvironment();
2575 if (!IIEnvironment)
2576 return true;
2577
2578 llvm::Triple::EnvironmentType CurrentEnv = GetCurrentShaderEnvironment();
2579 if (CurrentEnv == llvm::Triple::UnknownEnvironment)
2580 return false;
2581
2582 llvm::Triple::EnvironmentType AttrEnv =
2583 AvailabilityAttr::getEnvironmentType(IIEnvironment->getName());
2584
2585 return CurrentEnv == AttrEnv;
2586}
2587
2588const AvailabilityAttr *
2589DiagnoseHLSLAvailability::FindAvailabilityAttr(const Decl *D) {
2590 AvailabilityAttr const *PartialMatch = nullptr;
2591 // Check each AvailabilityAttr to find the one for this platform.
2592 // For multiple attributes with the same platform try to find one for this
2593 // environment.
2594 for (const auto *A : D->attrs()) {
2595 if (const auto *Avail = dyn_cast<AvailabilityAttr>(A)) {
2596 StringRef AttrPlatform = Avail->getPlatform()->getName();
2597 StringRef TargetPlatform =
2599
2600 // Match the platform name.
2601 if (AttrPlatform == TargetPlatform) {
2602 // Find the best matching attribute for this environment
2603 if (HasMatchingEnvironmentOrNone(Avail))
2604 return Avail;
2605 PartialMatch = Avail;
2606 }
2607 }
2608 }
2609 return PartialMatch;
2610}
2611
2612// Check availability against target shader model version and current shader
2613// stage and emit diagnostic
2614void DiagnoseHLSLAvailability::CheckDeclAvailability(NamedDecl *D,
2615 const AvailabilityAttr *AA,
2616 SourceRange Range) {
2617
2618 IdentifierInfo *IIEnv = AA->getEnvironment();
2619
2620 if (!IIEnv) {
2621 // The availability attribute does not have environment -> it depends only
2622 // on shader model version and not on specific the shader stage.
2623
2624 // Skip emitting the diagnostics if the diagnostic mode is set to
2625 // strict (-fhlsl-strict-availability) because all relevant diagnostics
2626 // were already emitted in the DiagnoseUnguardedAvailability scan
2627 // (SemaAvailability.cpp).
2628 if (SemaRef.getLangOpts().HLSLStrictAvailability)
2629 return;
2630
2631 // Do not report shader-stage-independent issues if scanning a function
2632 // that was already scanned in a different shader stage context (they would
2633 // be duplicate)
2634 if (ReportOnlyShaderStageIssues)
2635 return;
2636
2637 } else {
2638 // The availability attribute has environment -> we need to know
2639 // the current stage context to property diagnose it.
2640 if (InUnknownShaderStageContext())
2641 return;
2642 }
2643
2644 // Check introduced version and if environment matches
2645 bool EnvironmentMatches = HasMatchingEnvironmentOrNone(AA);
2646 VersionTuple Introduced = AA->getIntroduced();
2647 VersionTuple TargetVersion =
2649
2650 if (TargetVersion >= Introduced && EnvironmentMatches)
2651 return;
2652
2653 // Emit diagnostic message
2654 const TargetInfo &TI = SemaRef.getASTContext().getTargetInfo();
2655 llvm::StringRef PlatformName(
2656 AvailabilityAttr::getPrettyPlatformName(TI.getPlatformName()));
2657
2658 llvm::StringRef CurrentEnvStr =
2659 llvm::Triple::getEnvironmentTypeName(GetCurrentShaderEnvironment());
2660
2661 llvm::StringRef AttrEnvStr =
2662 AA->getEnvironment() ? AA->getEnvironment()->getName() : "";
2663 bool UseEnvironment = !AttrEnvStr.empty();
2664
2665 if (EnvironmentMatches) {
2666 SemaRef.Diag(Range.getBegin(), diag::warn_hlsl_availability)
2667 << Range << D << PlatformName << Introduced.getAsString()
2668 << UseEnvironment << CurrentEnvStr;
2669 } else {
2670 SemaRef.Diag(Range.getBegin(), diag::warn_hlsl_availability_unavailable)
2671 << Range << D;
2672 }
2673
2674 SemaRef.Diag(D->getLocation(), diag::note_partial_availability_specified_here)
2675 << D << PlatformName << Introduced.getAsString()
2676 << SemaRef.Context.getTargetInfo().getPlatformMinVersion().getAsString()
2677 << UseEnvironment << AttrEnvStr << CurrentEnvStr;
2678}
2679
2680} // namespace
2681
2683 // process default CBuffer - create buffer layout struct and invoke codegenCGH
2684 if (!DefaultCBufferDecls.empty()) {
2686 SemaRef.getASTContext(), SemaRef.getCurLexicalContext(),
2687 DefaultCBufferDecls);
2688 addImplicitBindingAttrToDecl(SemaRef, DefaultCBuffer, RegisterType::CBuffer,
2689 getNextImplicitBindingOrderID());
2690 SemaRef.getCurLexicalContext()->addDecl(DefaultCBuffer);
2692
2693 // Set HasValidPackoffset if any of the decls has a register(c#) annotation;
2694 for (const Decl *VD : DefaultCBufferDecls) {
2695 const HLSLResourceBindingAttr *RBA =
2696 VD->getAttr<HLSLResourceBindingAttr>();
2697 if (RBA && RBA->hasRegisterSlot() &&
2698 RBA->getRegisterType() == HLSLResourceBindingAttr::RegisterType::C) {
2699 DefaultCBuffer->setHasValidPackoffset(true);
2700 break;
2701 }
2702 }
2703
2704 DeclGroupRef DG(DefaultCBuffer);
2705 SemaRef.Consumer.HandleTopLevelDecl(DG);
2706 }
2707 diagnoseAvailabilityViolations(TU);
2708}
2709
2710void SemaHLSL::diagnoseAvailabilityViolations(TranslationUnitDecl *TU) {
2711 // Skip running the diagnostics scan if the diagnostic mode is
2712 // strict (-fhlsl-strict-availability) and the target shader stage is known
2713 // because all relevant diagnostics were already emitted in the
2714 // DiagnoseUnguardedAvailability scan (SemaAvailability.cpp).
2716 if (SemaRef.getLangOpts().HLSLStrictAvailability &&
2717 TI.getTriple().getEnvironment() != llvm::Triple::EnvironmentType::Library)
2718 return;
2719
2720 DiagnoseHLSLAvailability(SemaRef).RunOnTranslationUnit(TU);
2721}
2722
2723static bool CheckAllArgsHaveSameType(Sema *S, CallExpr *TheCall) {
2724 assert(TheCall->getNumArgs() > 1);
2725 QualType ArgTy0 = TheCall->getArg(0)->getType();
2726
2727 for (unsigned I = 1, N = TheCall->getNumArgs(); I < N; ++I) {
2729 ArgTy0, TheCall->getArg(I)->getType())) {
2730 S->Diag(TheCall->getBeginLoc(), diag::err_vec_builtin_incompatible_vector)
2731 << TheCall->getDirectCallee() << /*useAllTerminology*/ true
2732 << SourceRange(TheCall->getArg(0)->getBeginLoc(),
2733 TheCall->getArg(N - 1)->getEndLoc());
2734 return true;
2735 }
2736 }
2737 return false;
2738}
2739
2741 QualType ArgType = Arg->getType();
2743 S->Diag(Arg->getBeginLoc(), diag::err_typecheck_convert_incompatible)
2744 << ArgType << ExpectedType << 1 << 0 << 0;
2745 return true;
2746 }
2747 return false;
2748}
2749
2751 Sema *S, CallExpr *TheCall,
2752 llvm::function_ref<bool(Sema *S, SourceLocation Loc, int ArgOrdinal,
2753 clang::QualType PassedType)>
2754 Check) {
2755 for (unsigned I = 0; I < TheCall->getNumArgs(); ++I) {
2756 Expr *Arg = TheCall->getArg(I);
2757 if (Check(S, Arg->getBeginLoc(), I + 1, Arg->getType()))
2758 return true;
2759 }
2760 return false;
2761}
2762
2764 int ArgOrdinal,
2765 clang::QualType PassedType) {
2766 clang::QualType BaseType =
2767 PassedType->isVectorType()
2768 ? PassedType->castAs<clang::VectorType>()->getElementType()
2769 : PassedType;
2770 if (!BaseType->isHalfType() && !BaseType->isFloat32Type())
2771 return S->Diag(Loc, diag::err_builtin_invalid_arg_type)
2772 << ArgOrdinal << /* scalar or vector of */ 5 << /* no int */ 0
2773 << /* half or float */ 2 << PassedType;
2774 return false;
2775}
2776
2777static bool CheckModifiableLValue(Sema *S, CallExpr *TheCall,
2778 unsigned ArgIndex) {
2779 auto *Arg = TheCall->getArg(ArgIndex);
2780 SourceLocation OrigLoc = Arg->getExprLoc();
2781 if (Arg->IgnoreCasts()->isModifiableLvalue(S->Context, &OrigLoc) ==
2783 return false;
2784 S->Diag(OrigLoc, diag::error_hlsl_inout_lvalue) << Arg << 0;
2785 return true;
2786}
2787
2788static bool CheckNoDoubleVectors(Sema *S, SourceLocation Loc, int ArgOrdinal,
2789 clang::QualType PassedType) {
2790 const auto *VecTy = PassedType->getAs<VectorType>();
2791 if (!VecTy)
2792 return false;
2793
2794 if (VecTy->getElementType()->isDoubleType())
2795 return S->Diag(Loc, diag::err_builtin_invalid_arg_type)
2796 << ArgOrdinal << /* scalar */ 1 << /* no int */ 0 << /* fp */ 1
2797 << PassedType;
2798 return false;
2799}
2800
2802 int ArgOrdinal,
2803 clang::QualType PassedType) {
2804 if (!PassedType->hasIntegerRepresentation() &&
2805 !PassedType->hasFloatingRepresentation())
2806 return S->Diag(Loc, diag::err_builtin_invalid_arg_type)
2807 << ArgOrdinal << /* scalar or vector of */ 5 << /* integer */ 1
2808 << /* fp */ 1 << PassedType;
2809 return false;
2810}
2811
2813 int ArgOrdinal,
2814 clang::QualType PassedType) {
2815 if (auto *VecTy = PassedType->getAs<VectorType>())
2816 if (VecTy->getElementType()->isUnsignedIntegerType())
2817 return false;
2818
2819 return S->Diag(Loc, diag::err_builtin_invalid_arg_type)
2820 << ArgOrdinal << /* vector of */ 4 << /* uint */ 3 << /* no fp */ 0
2821 << PassedType;
2822}
2823
2824// checks for unsigned ints of all sizes
2826 int ArgOrdinal,
2827 clang::QualType PassedType) {
2828 if (!PassedType->hasUnsignedIntegerRepresentation())
2829 return S->Diag(Loc, diag::err_builtin_invalid_arg_type)
2830 << ArgOrdinal << /* scalar or vector of */ 5 << /* unsigned int */ 3
2831 << /* no fp */ 0 << PassedType;
2832 return false;
2833}
2834
2835static bool CheckExpectedBitWidth(Sema *S, CallExpr *TheCall,
2836 unsigned ArgOrdinal, unsigned Width) {
2837 QualType ArgTy = TheCall->getArg(0)->getType();
2838 if (auto *VTy = ArgTy->getAs<VectorType>())
2839 ArgTy = VTy->getElementType();
2840 // ensure arg type has expected bit width
2841 uint64_t ElementBitCount =
2843 if (ElementBitCount != Width) {
2844 S->Diag(TheCall->getArg(0)->getBeginLoc(),
2845 diag::err_integer_incorrect_bit_count)
2846 << Width << ElementBitCount;
2847 return true;
2848 }
2849 return false;
2850}
2851
2853 QualType ReturnType) {
2854 auto *VecTyA = TheCall->getArg(0)->getType()->getAs<VectorType>();
2855 if (VecTyA)
2856 ReturnType =
2857 S->Context.getExtVectorType(ReturnType, VecTyA->getNumElements());
2858
2859 TheCall->setType(ReturnType);
2860}
2861
2862static bool CheckScalarOrVector(Sema *S, CallExpr *TheCall, QualType Scalar,
2863 unsigned ArgIndex) {
2864 assert(TheCall->getNumArgs() >= ArgIndex);
2865 QualType ArgType = TheCall->getArg(ArgIndex)->getType();
2866 auto *VTy = ArgType->getAs<VectorType>();
2867 // not the scalar or vector<scalar>
2868 if (!(S->Context.hasSameUnqualifiedType(ArgType, Scalar) ||
2869 (VTy &&
2870 S->Context.hasSameUnqualifiedType(VTy->getElementType(), Scalar)))) {
2871 S->Diag(TheCall->getArg(0)->getBeginLoc(),
2872 diag::err_typecheck_expect_scalar_or_vector)
2873 << ArgType << Scalar;
2874 return true;
2875 }
2876 return false;
2877}
2878
2879static bool CheckAnyScalarOrVector(Sema *S, CallExpr *TheCall,
2880 unsigned ArgIndex) {
2881 assert(TheCall->getNumArgs() >= ArgIndex);
2882 QualType ArgType = TheCall->getArg(ArgIndex)->getType();
2883 auto *VTy = ArgType->getAs<VectorType>();
2884 // not the scalar or vector<scalar>
2885 if (!(ArgType->isScalarType() ||
2886 (VTy && VTy->getElementType()->isScalarType()))) {
2887 S->Diag(TheCall->getArg(0)->getBeginLoc(),
2888 diag::err_typecheck_expect_any_scalar_or_vector)
2889 << ArgType << 1;
2890 return true;
2891 }
2892 return false;
2893}
2894
2895static bool CheckWaveActive(Sema *S, CallExpr *TheCall) {
2896 QualType BoolType = S->getASTContext().BoolTy;
2897 assert(TheCall->getNumArgs() >= 1);
2898 QualType ArgType = TheCall->getArg(0)->getType();
2899 auto *VTy = ArgType->getAs<VectorType>();
2900 // is the bool or vector<bool>
2901 if (S->Context.hasSameUnqualifiedType(ArgType, BoolType) ||
2902 (VTy &&
2903 S->Context.hasSameUnqualifiedType(VTy->getElementType(), BoolType))) {
2904 S->Diag(TheCall->getArg(0)->getBeginLoc(),
2905 diag::err_typecheck_expect_any_scalar_or_vector)
2906 << ArgType << 0;
2907 return true;
2908 }
2909 return false;
2910}
2911
2912static bool CheckBoolSelect(Sema *S, CallExpr *TheCall) {
2913 assert(TheCall->getNumArgs() == 3);
2914 Expr *Arg1 = TheCall->getArg(1);
2915 Expr *Arg2 = TheCall->getArg(2);
2916 if (!S->Context.hasSameUnqualifiedType(Arg1->getType(), Arg2->getType())) {
2917 S->Diag(TheCall->getBeginLoc(),
2918 diag::err_typecheck_call_different_arg_types)
2919 << Arg1->getType() << Arg2->getType() << Arg1->getSourceRange()
2920 << Arg2->getSourceRange();
2921 return true;
2922 }
2923
2924 TheCall->setType(Arg1->getType());
2925 return false;
2926}
2927
2928static bool CheckVectorSelect(Sema *S, CallExpr *TheCall) {
2929 assert(TheCall->getNumArgs() == 3);
2930 Expr *Arg1 = TheCall->getArg(1);
2931 QualType Arg1Ty = Arg1->getType();
2932 Expr *Arg2 = TheCall->getArg(2);
2933 QualType Arg2Ty = Arg2->getType();
2934
2935 QualType Arg1ScalarTy = Arg1Ty;
2936 if (auto VTy = Arg1ScalarTy->getAs<VectorType>())
2937 Arg1ScalarTy = VTy->getElementType();
2938
2939 QualType Arg2ScalarTy = Arg2Ty;
2940 if (auto VTy = Arg2ScalarTy->getAs<VectorType>())
2941 Arg2ScalarTy = VTy->getElementType();
2942
2943 if (!S->Context.hasSameUnqualifiedType(Arg1ScalarTy, Arg2ScalarTy))
2944 S->Diag(Arg1->getBeginLoc(), diag::err_hlsl_builtin_scalar_vector_mismatch)
2945 << /* second and third */ 1 << TheCall->getCallee() << Arg1Ty << Arg2Ty;
2946
2947 QualType Arg0Ty = TheCall->getArg(0)->getType();
2948 unsigned Arg0Length = Arg0Ty->getAs<VectorType>()->getNumElements();
2949 unsigned Arg1Length = Arg1Ty->isVectorType()
2950 ? Arg1Ty->getAs<VectorType>()->getNumElements()
2951 : 0;
2952 unsigned Arg2Length = Arg2Ty->isVectorType()
2953 ? Arg2Ty->getAs<VectorType>()->getNumElements()
2954 : 0;
2955 if (Arg1Length > 0 && Arg0Length != Arg1Length) {
2956 S->Diag(TheCall->getBeginLoc(),
2957 diag::err_typecheck_vector_lengths_not_equal)
2958 << Arg0Ty << Arg1Ty << TheCall->getArg(0)->getSourceRange()
2959 << Arg1->getSourceRange();
2960 return true;
2961 }
2962
2963 if (Arg2Length > 0 && Arg0Length != Arg2Length) {
2964 S->Diag(TheCall->getBeginLoc(),
2965 diag::err_typecheck_vector_lengths_not_equal)
2966 << Arg0Ty << Arg2Ty << TheCall->getArg(0)->getSourceRange()
2967 << Arg2->getSourceRange();
2968 return true;
2969 }
2970
2971 TheCall->setType(
2972 S->getASTContext().getExtVectorType(Arg1ScalarTy, Arg0Length));
2973 return false;
2974}
2975
2977 Sema *S, CallExpr *TheCall, unsigned ArgIndex,
2978 llvm::function_ref<bool(const HLSLAttributedResourceType *ResType)> Check =
2979 nullptr) {
2980 assert(TheCall->getNumArgs() >= ArgIndex);
2981 QualType ArgType = TheCall->getArg(ArgIndex)->getType();
2982 const HLSLAttributedResourceType *ResTy =
2983 ArgType.getTypePtr()->getAs<HLSLAttributedResourceType>();
2984 if (!ResTy) {
2985 S->Diag(TheCall->getArg(ArgIndex)->getBeginLoc(),
2986 diag::err_typecheck_expect_hlsl_resource)
2987 << ArgType;
2988 return true;
2989 }
2990 if (Check && Check(ResTy)) {
2991 S->Diag(TheCall->getArg(ArgIndex)->getExprLoc(),
2992 diag::err_invalid_hlsl_resource_type)
2993 << ArgType;
2994 return true;
2995 }
2996 return false;
2997}
2998
2999// Note: returning true in this case results in CheckBuiltinFunctionCall
3000// returning an ExprError
3001bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
3002 switch (BuiltinID) {
3003 case Builtin::BI__builtin_hlsl_adduint64: {
3004 if (SemaRef.checkArgCount(TheCall, 2))
3005 return true;
3006
3007 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
3009 return true;
3010
3011 // ensure arg integers are 32-bits
3012 if (CheckExpectedBitWidth(&SemaRef, TheCall, 0, 32))
3013 return true;
3014
3015 // ensure both args are vectors of total bit size of a multiple of 64
3016 auto *VTy = TheCall->getArg(0)->getType()->getAs<VectorType>();
3017 int NumElementsArg = VTy->getNumElements();
3018 if (NumElementsArg != 2 && NumElementsArg != 4) {
3019 SemaRef.Diag(TheCall->getBeginLoc(), diag::err_vector_incorrect_bit_count)
3020 << 1 /*a multiple of*/ << 64 << NumElementsArg * 32;
3021 return true;
3022 }
3023
3024 // ensure first arg and second arg have the same type
3025 if (CheckAllArgsHaveSameType(&SemaRef, TheCall))
3026 return true;
3027
3028 ExprResult A = TheCall->getArg(0);
3029 QualType ArgTyA = A.get()->getType();
3030 // return type is the same as the input type
3031 TheCall->setType(ArgTyA);
3032 break;
3033 }
3034 case Builtin::BI__builtin_hlsl_resource_getpointer: {
3035 if (SemaRef.checkArgCount(TheCall, 2) ||
3036 CheckResourceHandle(&SemaRef, TheCall, 0) ||
3037 CheckArgTypeMatches(&SemaRef, TheCall->getArg(1),
3038 SemaRef.getASTContext().UnsignedIntTy))
3039 return true;
3040
3041 auto *ResourceTy =
3042 TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
3043 QualType ContainedTy = ResourceTy->getContainedType();
3044 auto ReturnType =
3045 SemaRef.Context.getAddrSpaceQualType(ContainedTy, LangAS::hlsl_device);
3046 ReturnType = SemaRef.Context.getPointerType(ReturnType);
3047 TheCall->setType(ReturnType);
3048 TheCall->setValueKind(VK_LValue);
3049
3050 break;
3051 }
3052 case Builtin::BI__builtin_hlsl_resource_uninitializedhandle: {
3053 if (SemaRef.checkArgCount(TheCall, 1) ||
3054 CheckResourceHandle(&SemaRef, TheCall, 0))
3055 return true;
3056 // use the type of the handle (arg0) as a return type
3057 QualType ResourceTy = TheCall->getArg(0)->getType();
3058 TheCall->setType(ResourceTy);
3059 break;
3060 }
3061 case Builtin::BI__builtin_hlsl_resource_handlefrombinding: {
3062 ASTContext &AST = SemaRef.getASTContext();
3063 if (SemaRef.checkArgCount(TheCall, 6) ||
3064 CheckResourceHandle(&SemaRef, TheCall, 0) ||
3065 CheckArgTypeMatches(&SemaRef, TheCall->getArg(1), AST.UnsignedIntTy) ||
3066 CheckArgTypeMatches(&SemaRef, TheCall->getArg(2), AST.UnsignedIntTy) ||
3067 CheckArgTypeMatches(&SemaRef, TheCall->getArg(3), AST.IntTy) ||
3068 CheckArgTypeMatches(&SemaRef, TheCall->getArg(4), AST.UnsignedIntTy) ||
3069 CheckArgTypeMatches(&SemaRef, TheCall->getArg(5),
3070 AST.getPointerType(AST.CharTy.withConst())))
3071 return true;
3072 // use the type of the handle (arg0) as a return type
3073 QualType ResourceTy = TheCall->getArg(0)->getType();
3074 TheCall->setType(ResourceTy);
3075 break;
3076 }
3077 case Builtin::BI__builtin_hlsl_resource_handlefromimplicitbinding: {
3078 ASTContext &AST = SemaRef.getASTContext();
3079 if (SemaRef.checkArgCount(TheCall, 6) ||
3080 CheckResourceHandle(&SemaRef, TheCall, 0) ||
3081 CheckArgTypeMatches(&SemaRef, TheCall->getArg(1), AST.UnsignedIntTy) ||
3082 CheckArgTypeMatches(&SemaRef, TheCall->getArg(2), AST.UnsignedIntTy) ||
3083 CheckArgTypeMatches(&SemaRef, TheCall->getArg(3), AST.IntTy) ||
3084 CheckArgTypeMatches(&SemaRef, TheCall->getArg(4), AST.UnsignedIntTy) ||
3085 CheckArgTypeMatches(&SemaRef, TheCall->getArg(5),
3086 AST.getPointerType(AST.CharTy.withConst())))
3087 return true;
3088 // use the type of the handle (arg0) as a return type
3089 QualType ResourceTy = TheCall->getArg(0)->getType();
3090 TheCall->setType(ResourceTy);
3091 break;
3092 }
3093 case Builtin::BI__builtin_hlsl_resource_counterhandlefromimplicitbinding: {
3094 ASTContext &AST = SemaRef.getASTContext();
3095 if (SemaRef.checkArgCount(TheCall, 3) ||
3096 CheckResourceHandle(&SemaRef, TheCall, 0) ||
3097 CheckArgTypeMatches(&SemaRef, TheCall->getArg(1), AST.UnsignedIntTy) ||
3098 CheckArgTypeMatches(&SemaRef, TheCall->getArg(2), AST.UnsignedIntTy))
3099 return true;
3100
3101 QualType MainHandleTy = TheCall->getArg(0)->getType();
3102 auto *MainResType = MainHandleTy->getAs<HLSLAttributedResourceType>();
3103 auto MainAttrs = MainResType->getAttrs();
3104 assert(!MainAttrs.IsCounter && "cannot create a counter from a counter");
3105 MainAttrs.IsCounter = true;
3106 QualType CounterHandleTy = AST.getHLSLAttributedResourceType(
3107 MainResType->getWrappedType(), MainResType->getContainedType(),
3108 MainAttrs);
3109 TheCall->setType(CounterHandleTy);
3110 break;
3111 }
3112 case Builtin::BI__builtin_hlsl_resource_getdimensions_x: {
3113 ASTContext &AST = SemaRef.getASTContext();
3114 if (SemaRef.checkArgCount(TheCall, 2) ||
3115 CheckResourceHandle(&SemaRef, TheCall, 0) ||
3116 CheckArgTypeMatches(&SemaRef, TheCall->getArg(1), AST.UnsignedIntTy) ||
3117 CheckModifiableLValue(&SemaRef, TheCall, 1))
3118 return true;
3119 break;
3120 }
3121 case Builtin::BI__builtin_hlsl_resource_getstride: {
3122 ASTContext &AST = SemaRef.getASTContext();
3123 if (SemaRef.checkArgCount(TheCall, 2) ||
3124 CheckResourceHandle(&SemaRef, TheCall, 0) ||
3125 CheckArgTypeMatches(&SemaRef, TheCall->getArg(1), AST.UnsignedIntTy) ||
3126 CheckModifiableLValue(&SemaRef, TheCall, 1))
3127 return true;
3128 break;
3129 }
3130 case Builtin::BI__builtin_hlsl_and:
3131 case Builtin::BI__builtin_hlsl_or: {
3132 if (SemaRef.checkArgCount(TheCall, 2))
3133 return true;
3134 if (CheckScalarOrVector(&SemaRef, TheCall, getASTContext().BoolTy, 0))
3135 return true;
3136 if (CheckAllArgsHaveSameType(&SemaRef, TheCall))
3137 return true;
3138
3139 ExprResult A = TheCall->getArg(0);
3140 QualType ArgTyA = A.get()->getType();
3141 // return type is the same as the input type
3142 TheCall->setType(ArgTyA);
3143 break;
3144 }
3145 case Builtin::BI__builtin_hlsl_all:
3146 case Builtin::BI__builtin_hlsl_any: {
3147 if (SemaRef.checkArgCount(TheCall, 1))
3148 return true;
3149 if (CheckAnyScalarOrVector(&SemaRef, TheCall, 0))
3150 return true;
3151 break;
3152 }
3153 case Builtin::BI__builtin_hlsl_asdouble: {
3154 if (SemaRef.checkArgCount(TheCall, 2))
3155 return true;
3157 &SemaRef, TheCall,
3158 /*only check for uint*/ SemaRef.Context.UnsignedIntTy,
3159 /* arg index */ 0))
3160 return true;
3162 &SemaRef, TheCall,
3163 /*only check for uint*/ SemaRef.Context.UnsignedIntTy,
3164 /* arg index */ 1))
3165 return true;
3166 if (CheckAllArgsHaveSameType(&SemaRef, TheCall))
3167 return true;
3168
3169 SetElementTypeAsReturnType(&SemaRef, TheCall, getASTContext().DoubleTy);
3170 break;
3171 }
3172 case Builtin::BI__builtin_hlsl_elementwise_clamp: {
3173 if (SemaRef.BuiltinElementwiseTernaryMath(
3174 TheCall, /*ArgTyRestr=*/
3176 return true;
3177 break;
3178 }
3179 case Builtin::BI__builtin_hlsl_dot: {
3180 // arg count is checked by BuiltinVectorToScalarMath
3181 if (SemaRef.BuiltinVectorToScalarMath(TheCall))
3182 return true;
3184 return true;
3185 break;
3186 }
3187 case Builtin::BI__builtin_hlsl_elementwise_firstbithigh:
3188 case Builtin::BI__builtin_hlsl_elementwise_firstbitlow: {
3189 if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall))
3190 return true;
3191
3192 const Expr *Arg = TheCall->getArg(0);
3193 QualType ArgTy = Arg->getType();
3194 QualType EltTy = ArgTy;
3195
3196 QualType ResTy = SemaRef.Context.UnsignedIntTy;
3197
3198 if (auto *VecTy = EltTy->getAs<VectorType>()) {
3199 EltTy = VecTy->getElementType();
3200 ResTy = SemaRef.Context.getExtVectorType(ResTy, VecTy->getNumElements());
3201 }
3202
3203 if (!EltTy->isIntegerType()) {
3204 Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
3205 << 1 << /* scalar or vector of */ 5 << /* integer ty */ 1
3206 << /* no fp */ 0 << ArgTy;
3207 return true;
3208 }
3209
3210 TheCall->setType(ResTy);
3211 break;
3212 }
3213 case Builtin::BI__builtin_hlsl_select: {
3214 if (SemaRef.checkArgCount(TheCall, 3))
3215 return true;
3216 if (CheckScalarOrVector(&SemaRef, TheCall, getASTContext().BoolTy, 0))
3217 return true;
3218 QualType ArgTy = TheCall->getArg(0)->getType();
3219 if (ArgTy->isBooleanType() && CheckBoolSelect(&SemaRef, TheCall))
3220 return true;
3221 auto *VTy = ArgTy->getAs<VectorType>();
3222 if (VTy && VTy->getElementType()->isBooleanType() &&
3223 CheckVectorSelect(&SemaRef, TheCall))
3224 return true;
3225 break;
3226 }
3227 case Builtin::BI__builtin_hlsl_elementwise_saturate:
3228 case Builtin::BI__builtin_hlsl_elementwise_rcp: {
3229 if (SemaRef.checkArgCount(TheCall, 1))
3230 return true;
3231 if (!TheCall->getArg(0)
3232 ->getType()
3233 ->hasFloatingRepresentation()) // half or float or double
3234 return SemaRef.Diag(TheCall->getArg(0)->getBeginLoc(),
3235 diag::err_builtin_invalid_arg_type)
3236 << /* ordinal */ 1 << /* scalar or vector */ 5 << /* no int */ 0
3237 << /* fp */ 1 << TheCall->getArg(0)->getType();
3238 if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall))
3239 return true;
3240 break;
3241 }
3242 case Builtin::BI__builtin_hlsl_elementwise_degrees:
3243 case Builtin::BI__builtin_hlsl_elementwise_radians:
3244 case Builtin::BI__builtin_hlsl_elementwise_rsqrt:
3245 case Builtin::BI__builtin_hlsl_elementwise_frac: {
3246 if (SemaRef.checkArgCount(TheCall, 1))
3247 return true;
3248 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
3250 return true;
3251 if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall))
3252 return true;
3253 break;
3254 }
3255 case Builtin::BI__builtin_hlsl_elementwise_isinf:
3256 case Builtin::BI__builtin_hlsl_elementwise_isnan: {
3257 if (SemaRef.checkArgCount(TheCall, 1))
3258 return true;
3259 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
3261 return true;
3262 if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall))
3263 return true;
3265 break;
3266 }
3267 case Builtin::BI__builtin_hlsl_lerp: {
3268 if (SemaRef.checkArgCount(TheCall, 3))
3269 return true;
3270 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
3272 return true;
3273 if (CheckAllArgsHaveSameType(&SemaRef, TheCall))
3274 return true;
3275 if (SemaRef.BuiltinElementwiseTernaryMath(TheCall))
3276 return true;
3277 break;
3278 }
3279 case Builtin::BI__builtin_hlsl_mad: {
3280 if (SemaRef.BuiltinElementwiseTernaryMath(
3281 TheCall, /*ArgTyRestr=*/
3283 return true;
3284 break;
3285 }
3286 case Builtin::BI__builtin_hlsl_normalize: {
3287 if (SemaRef.checkArgCount(TheCall, 1))
3288 return true;
3289 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
3291 return true;
3292 ExprResult A = TheCall->getArg(0);
3293 QualType ArgTyA = A.get()->getType();
3294 // return type is the same as the input type
3295 TheCall->setType(ArgTyA);
3296 break;
3297 }
3298 case Builtin::BI__builtin_hlsl_elementwise_sign: {
3299 if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall))
3300 return true;
3301 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
3303 return true;
3305 break;
3306 }
3307 case Builtin::BI__builtin_hlsl_step: {
3308 if (SemaRef.checkArgCount(TheCall, 2))
3309 return true;
3310 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
3312 return true;
3313
3314 ExprResult A = TheCall->getArg(0);
3315 QualType ArgTyA = A.get()->getType();
3316 // return type is the same as the input type
3317 TheCall->setType(ArgTyA);
3318 break;
3319 }
3320 case Builtin::BI__builtin_hlsl_wave_active_max:
3321 case Builtin::BI__builtin_hlsl_wave_active_min:
3322 case Builtin::BI__builtin_hlsl_wave_active_sum: {
3323 if (SemaRef.checkArgCount(TheCall, 1))
3324 return true;
3325
3326 // Ensure input expr type is a scalar/vector and the same as the return type
3327 if (CheckAnyScalarOrVector(&SemaRef, TheCall, 0))
3328 return true;
3329 if (CheckWaveActive(&SemaRef, TheCall))
3330 return true;
3331 ExprResult Expr = TheCall->getArg(0);
3332 QualType ArgTyExpr = Expr.get()->getType();
3333 TheCall->setType(ArgTyExpr);
3334 break;
3335 }
3336 // Note these are llvm builtins that we want to catch invalid intrinsic
3337 // generation. Normal handling of these builtins will occur elsewhere.
3338 case Builtin::BI__builtin_elementwise_bitreverse: {
3339 // does not include a check for number of arguments
3340 // because that is done previously
3341 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
3343 return true;
3344 break;
3345 }
3346 case Builtin::BI__builtin_hlsl_wave_read_lane_at: {
3347 if (SemaRef.checkArgCount(TheCall, 2))
3348 return true;
3349
3350 // Ensure index parameter type can be interpreted as a uint
3351 ExprResult Index = TheCall->getArg(1);
3352 QualType ArgTyIndex = Index.get()->getType();
3353 if (!ArgTyIndex->isIntegerType()) {
3354 SemaRef.Diag(TheCall->getArg(1)->getBeginLoc(),
3355 diag::err_typecheck_convert_incompatible)
3356 << ArgTyIndex << SemaRef.Context.UnsignedIntTy << 1 << 0 << 0;
3357 return true;
3358 }
3359
3360 // Ensure input expr type is a scalar/vector and the same as the return type
3361 if (CheckAnyScalarOrVector(&SemaRef, TheCall, 0))
3362 return true;
3363
3364 ExprResult Expr = TheCall->getArg(0);
3365 QualType ArgTyExpr = Expr.get()->getType();
3366 TheCall->setType(ArgTyExpr);
3367 break;
3368 }
3369 case Builtin::BI__builtin_hlsl_wave_get_lane_index: {
3370 if (SemaRef.checkArgCount(TheCall, 0))
3371 return true;
3372 break;
3373 }
3374 case Builtin::BI__builtin_hlsl_elementwise_splitdouble: {
3375 if (SemaRef.checkArgCount(TheCall, 3))
3376 return true;
3377
3378 if (CheckScalarOrVector(&SemaRef, TheCall, SemaRef.Context.DoubleTy, 0) ||
3379 CheckScalarOrVector(&SemaRef, TheCall, SemaRef.Context.UnsignedIntTy,
3380 1) ||
3381 CheckScalarOrVector(&SemaRef, TheCall, SemaRef.Context.UnsignedIntTy,
3382 2))
3383 return true;
3384
3385 if (CheckModifiableLValue(&SemaRef, TheCall, 1) ||
3386 CheckModifiableLValue(&SemaRef, TheCall, 2))
3387 return true;
3388 break;
3389 }
3390 case Builtin::BI__builtin_hlsl_elementwise_clip: {
3391 if (SemaRef.checkArgCount(TheCall, 1))
3392 return true;
3393
3394 if (CheckScalarOrVector(&SemaRef, TheCall, SemaRef.Context.FloatTy, 0))
3395 return true;
3396 break;
3397 }
3398 case Builtin::BI__builtin_elementwise_acos:
3399 case Builtin::BI__builtin_elementwise_asin:
3400 case Builtin::BI__builtin_elementwise_atan:
3401 case Builtin::BI__builtin_elementwise_atan2:
3402 case Builtin::BI__builtin_elementwise_ceil:
3403 case Builtin::BI__builtin_elementwise_cos:
3404 case Builtin::BI__builtin_elementwise_cosh:
3405 case Builtin::BI__builtin_elementwise_exp:
3406 case Builtin::BI__builtin_elementwise_exp2:
3407 case Builtin::BI__builtin_elementwise_exp10:
3408 case Builtin::BI__builtin_elementwise_floor:
3409 case Builtin::BI__builtin_elementwise_fmod:
3410 case Builtin::BI__builtin_elementwise_log:
3411 case Builtin::BI__builtin_elementwise_log2:
3412 case Builtin::BI__builtin_elementwise_log10:
3413 case Builtin::BI__builtin_elementwise_pow:
3414 case Builtin::BI__builtin_elementwise_roundeven:
3415 case Builtin::BI__builtin_elementwise_sin:
3416 case Builtin::BI__builtin_elementwise_sinh:
3417 case Builtin::BI__builtin_elementwise_sqrt:
3418 case Builtin::BI__builtin_elementwise_tan:
3419 case Builtin::BI__builtin_elementwise_tanh:
3420 case Builtin::BI__builtin_elementwise_trunc: {
3421 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
3423 return true;
3424 break;
3425 }
3426 case Builtin::BI__builtin_hlsl_buffer_update_counter: {
3427 auto checkResTy = [](const HLSLAttributedResourceType *ResTy) -> bool {
3428 return !(ResTy->getAttrs().ResourceClass == ResourceClass::UAV &&
3429 ResTy->getAttrs().RawBuffer && ResTy->hasContainedType());
3430 };
3431 if (SemaRef.checkArgCount(TheCall, 2) ||
3432 CheckResourceHandle(&SemaRef, TheCall, 0, checkResTy) ||
3433 CheckArgTypeMatches(&SemaRef, TheCall->getArg(1),
3434 SemaRef.getASTContext().IntTy))
3435 return true;
3436 Expr *OffsetExpr = TheCall->getArg(1);
3437 std::optional<llvm::APSInt> Offset =
3438 OffsetExpr->getIntegerConstantExpr(SemaRef.getASTContext());
3439 if (!Offset.has_value() || std::abs(Offset->getExtValue()) != 1) {
3440 SemaRef.Diag(TheCall->getArg(1)->getBeginLoc(),
3441 diag::err_hlsl_expect_arg_const_int_one_or_neg_one)
3442 << 1;
3443 return true;
3444 }
3445 break;
3446 }
3447 case Builtin::BI__builtin_hlsl_elementwise_f16tof32: {
3448 if (SemaRef.checkArgCount(TheCall, 1))
3449 return true;
3450 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
3452 return true;
3453 // ensure arg integers are 32 bits
3454 if (CheckExpectedBitWidth(&SemaRef, TheCall, 0, 32))
3455 return true;
3456 // check it wasn't a bool type
3457 QualType ArgTy = TheCall->getArg(0)->getType();
3458 if (auto *VTy = ArgTy->getAs<VectorType>())
3459 ArgTy = VTy->getElementType();
3460 if (ArgTy->isBooleanType()) {
3461 SemaRef.Diag(TheCall->getArg(0)->getBeginLoc(),
3462 diag::err_builtin_invalid_arg_type)
3463 << 1 << /* scalar or vector of */ 5 << /* unsigned int */ 3
3464 << /* no fp */ 0 << TheCall->getArg(0)->getType();
3465 return true;
3466 }
3467
3468 SetElementTypeAsReturnType(&SemaRef, TheCall, getASTContext().FloatTy);
3469 break;
3470 }
3471 }
3472 return false;
3473}
3474
3478 WorkList.push_back(BaseTy);
3479 while (!WorkList.empty()) {
3480 QualType T = WorkList.pop_back_val();
3481 T = T.getCanonicalType().getUnqualifiedType();
3482 if (const auto *AT = dyn_cast<ConstantArrayType>(T)) {
3483 llvm::SmallVector<QualType, 16> ElementFields;
3484 // Generally I've avoided recursion in this algorithm, but arrays of
3485 // structs could be time-consuming to flatten and churn through on the
3486 // work list. Hopefully nesting arrays of structs containing arrays
3487 // of structs too many levels deep is unlikely.
3488 BuildFlattenedTypeList(AT->getElementType(), ElementFields);
3489 // Repeat the element's field list n times.
3490 for (uint64_t Ct = 0; Ct < AT->getZExtSize(); ++Ct)
3491 llvm::append_range(List, ElementFields);
3492 continue;
3493 }
3494 // Vectors can only have element types that are builtin types, so this can
3495 // add directly to the list instead of to the WorkList.
3496 if (const auto *VT = dyn_cast<VectorType>(T)) {
3497 List.insert(List.end(), VT->getNumElements(), VT->getElementType());
3498 continue;
3499 }
3500 if (const auto *MT = dyn_cast<ConstantMatrixType>(T)) {
3501 List.insert(List.end(), MT->getNumElementsFlattened(),
3502 MT->getElementType());
3503 continue;
3504 }
3505 if (const auto *RD = T->getAsCXXRecordDecl()) {
3506 if (RD->isStandardLayout())
3507 RD = RD->getStandardLayoutBaseWithFields();
3508
3509 // For types that we shouldn't decompose (unions and non-aggregates), just
3510 // add the type itself to the list.
3511 if (RD->isUnion() || !RD->isAggregate()) {
3512 List.push_back(T);
3513 continue;
3514 }
3515
3517 for (const auto *FD : RD->fields())
3518 if (!FD->isUnnamedBitField())
3519 FieldTypes.push_back(FD->getType());
3520 // Reverse the newly added sub-range.
3521 std::reverse(FieldTypes.begin(), FieldTypes.end());
3522 llvm::append_range(WorkList, FieldTypes);
3523
3524 // If this wasn't a standard layout type we may also have some base
3525 // classes to deal with.
3526 if (!RD->isStandardLayout()) {
3527 FieldTypes.clear();
3528 for (const auto &Base : RD->bases())
3529 FieldTypes.push_back(Base.getType());
3530 std::reverse(FieldTypes.begin(), FieldTypes.end());
3531 llvm::append_range(WorkList, FieldTypes);
3532 }
3533 continue;
3534 }
3535 List.push_back(T);
3536 }
3537}
3538
3540 // null and array types are not allowed.
3541 if (QT.isNull() || QT->isArrayType())
3542 return false;
3543
3544 // UDT types are not allowed
3545 if (QT->isRecordType())
3546 return false;
3547
3548 if (QT->isBooleanType() || QT->isEnumeralType())
3549 return false;
3550
3551 // the only other valid builtin types are scalars or vectors
3552 if (QT->isArithmeticType()) {
3553 if (SemaRef.Context.getTypeSize(QT) / 8 > 16)
3554 return false;
3555 return true;
3556 }
3557
3558 if (const VectorType *VT = QT->getAs<VectorType>()) {
3559 int ArraySize = VT->getNumElements();
3560
3561 if (ArraySize > 4)
3562 return false;
3563
3564 QualType ElTy = VT->getElementType();
3565 if (ElTy->isBooleanType())
3566 return false;
3567
3568 if (SemaRef.Context.getTypeSize(QT) / 8 > 16)
3569 return false;
3570 return true;
3571 }
3572
3573 return false;
3574}
3575
3577 if (T1.isNull() || T2.isNull())
3578 return false;
3579
3582
3583 // If both types are the same canonical type, they're obviously compatible.
3584 if (SemaRef.getASTContext().hasSameType(T1, T2))
3585 return true;
3586
3588 BuildFlattenedTypeList(T1, T1Types);
3590 BuildFlattenedTypeList(T2, T2Types);
3591
3592 // Check the flattened type list
3593 return llvm::equal(T1Types, T2Types,
3594 [this](QualType LHS, QualType RHS) -> bool {
3595 return SemaRef.IsLayoutCompatible(LHS, RHS);
3596 });
3597}
3598
3600 FunctionDecl *Old) {
3601 if (New->getNumParams() != Old->getNumParams())
3602 return true;
3603
3604 bool HadError = false;
3605
3606 for (unsigned i = 0, e = New->getNumParams(); i != e; ++i) {
3607 ParmVarDecl *NewParam = New->getParamDecl(i);
3608 ParmVarDecl *OldParam = Old->getParamDecl(i);
3609
3610 // HLSL parameter declarations for inout and out must match between
3611 // declarations. In HLSL inout and out are ambiguous at the call site,
3612 // but have different calling behavior, so you cannot overload a
3613 // method based on a difference between inout and out annotations.
3614 const auto *NDAttr = NewParam->getAttr<HLSLParamModifierAttr>();
3615 unsigned NSpellingIdx = (NDAttr ? NDAttr->getSpellingListIndex() : 0);
3616 const auto *ODAttr = OldParam->getAttr<HLSLParamModifierAttr>();
3617 unsigned OSpellingIdx = (ODAttr ? ODAttr->getSpellingListIndex() : 0);
3618
3619 if (NSpellingIdx != OSpellingIdx) {
3620 SemaRef.Diag(NewParam->getLocation(),
3621 diag::err_hlsl_param_qualifier_mismatch)
3622 << NDAttr << NewParam;
3623 SemaRef.Diag(OldParam->getLocation(), diag::note_previous_declaration_as)
3624 << ODAttr;
3625 HadError = true;
3626 }
3627 }
3628 return HadError;
3629}
3630
3631// Generally follows PerformScalarCast, with cases reordered for
3632// clarity of what types are supported
3634
3635 if (!SrcTy->isScalarType() || !DestTy->isScalarType())
3636 return false;
3637
3638 if (SemaRef.getASTContext().hasSameUnqualifiedType(SrcTy, DestTy))
3639 return true;
3640
3641 switch (SrcTy->getScalarTypeKind()) {
3642 case Type::STK_Bool: // casting from bool is like casting from an integer
3643 case Type::STK_Integral:
3644 switch (DestTy->getScalarTypeKind()) {
3645 case Type::STK_Bool:
3646 case Type::STK_Integral:
3647 case Type::STK_Floating:
3648 return true;
3649 case Type::STK_CPointer:
3653 llvm_unreachable("HLSL doesn't support pointers.");
3656 llvm_unreachable("HLSL doesn't support complex types.");
3658 llvm_unreachable("HLSL doesn't support fixed point types.");
3659 }
3660 llvm_unreachable("Should have returned before this");
3661
3662 case Type::STK_Floating:
3663 switch (DestTy->getScalarTypeKind()) {
3664 case Type::STK_Floating:
3665 case Type::STK_Bool:
3666 case Type::STK_Integral:
3667 return true;
3670 llvm_unreachable("HLSL doesn't support complex types.");
3672 llvm_unreachable("HLSL doesn't support fixed point types.");
3673 case Type::STK_CPointer:
3677 llvm_unreachable("HLSL doesn't support pointers.");
3678 }
3679 llvm_unreachable("Should have returned before this");
3680
3682 case Type::STK_CPointer:
3685 llvm_unreachable("HLSL doesn't support pointers.");
3686
3688 llvm_unreachable("HLSL doesn't support fixed point types.");
3689
3692 llvm_unreachable("HLSL doesn't support complex types.");
3693 }
3694
3695 llvm_unreachable("Unhandled scalar cast");
3696}
3697
3698// Can perform an HLSL Aggregate splat cast if the Dest is an aggregate and the
3699// Src is a scalar or a vector of length 1
3700// Or if Dest is a vector and Src is a vector of length 1
3702
3703 QualType SrcTy = Src->getType();
3704 // Not a valid HLSL Aggregate Splat cast if Dest is a scalar or if this is
3705 // going to be a vector splat from a scalar.
3706 if ((SrcTy->isScalarType() && DestTy->isVectorType()) ||
3707 DestTy->isScalarType())
3708 return false;
3709
3710 const VectorType *SrcVecTy = SrcTy->getAs<VectorType>();
3711
3712 // Src isn't a scalar or a vector of length 1
3713 if (!SrcTy->isScalarType() && !(SrcVecTy && SrcVecTy->getNumElements() == 1))
3714 return false;
3715
3716 if (SrcVecTy)
3717 SrcTy = SrcVecTy->getElementType();
3718
3720 BuildFlattenedTypeList(DestTy, DestTypes);
3721
3722 for (unsigned I = 0, Size = DestTypes.size(); I < Size; ++I) {
3723 if (DestTypes[I]->isUnionType())
3724 return false;
3725 if (!CanPerformScalarCast(SrcTy, DestTypes[I]))
3726 return false;
3727 }
3728 return true;
3729}
3730
3731// Can we perform an HLSL Elementwise cast?
3732// TODO: update this code when matrices are added; see issue #88060
3734
3735 // Don't handle casts where LHS and RHS are any combination of scalar/vector
3736 // There must be an aggregate somewhere
3737 QualType SrcTy = Src->getType();
3738 if (SrcTy->isScalarType()) // always a splat and this cast doesn't handle that
3739 return false;
3740
3741 if (SrcTy->isVectorType() &&
3742 (DestTy->isScalarType() || DestTy->isVectorType()))
3743 return false;
3744
3746 BuildFlattenedTypeList(DestTy, DestTypes);
3748 BuildFlattenedTypeList(SrcTy, SrcTypes);
3749
3750 // Usually the size of SrcTypes must be greater than or equal to the size of
3751 // DestTypes.
3752 if (SrcTypes.size() < DestTypes.size())
3753 return false;
3754
3755 unsigned SrcSize = SrcTypes.size();
3756 unsigned DstSize = DestTypes.size();
3757 unsigned I;
3758 for (I = 0; I < DstSize && I < SrcSize; I++) {
3759 if (SrcTypes[I]->isUnionType() || DestTypes[I]->isUnionType())
3760 return false;
3761 if (!CanPerformScalarCast(SrcTypes[I], DestTypes[I])) {
3762 return false;
3763 }
3764 }
3765
3766 // check the rest of the source type for unions.
3767 for (; I < SrcSize; I++) {
3768 if (SrcTypes[I]->isUnionType())
3769 return false;
3770 }
3771 return true;
3772}
3773
3775 assert(Param->hasAttr<HLSLParamModifierAttr>() &&
3776 "We should not get here without a parameter modifier expression");
3777 const auto *Attr = Param->getAttr<HLSLParamModifierAttr>();
3778 if (Attr->getABI() == ParameterABI::Ordinary)
3779 return ExprResult(Arg);
3780
3781 bool IsInOut = Attr->getABI() == ParameterABI::HLSLInOut;
3782 if (!Arg->isLValue()) {
3783 SemaRef.Diag(Arg->getBeginLoc(), diag::error_hlsl_inout_lvalue)
3784 << Arg << (IsInOut ? 1 : 0);
3785 return ExprError();
3786 }
3787
3788 ASTContext &Ctx = SemaRef.getASTContext();
3789
3790 QualType Ty = Param->getType().getNonLValueExprType(Ctx);
3791
3792 // HLSL allows implicit conversions from scalars to vectors, but not the
3793 // inverse, so we need to disallow `inout` with scalar->vector or
3794 // scalar->matrix conversions.
3795 if (Arg->getType()->isScalarType() != Ty->isScalarType()) {
3796 SemaRef.Diag(Arg->getBeginLoc(), diag::error_hlsl_inout_scalar_extension)
3797 << Arg << (IsInOut ? 1 : 0);
3798 return ExprError();
3799 }
3800
3801 auto *ArgOpV = new (Ctx) OpaqueValueExpr(Param->getBeginLoc(), Arg->getType(),
3802 VK_LValue, OK_Ordinary, Arg);
3803
3804 // Parameters are initialized via copy initialization. This allows for
3805 // overload resolution of argument constructors.
3806 InitializedEntity Entity =
3808 ExprResult Res =
3809 SemaRef.PerformCopyInitialization(Entity, Param->getBeginLoc(), ArgOpV);
3810 if (Res.isInvalid())
3811 return ExprError();
3812 Expr *Base = Res.get();
3813 // After the cast, drop the reference type when creating the exprs.
3814 Ty = Ty.getNonLValueExprType(Ctx);
3815 auto *OpV = new (Ctx)
3816 OpaqueValueExpr(Param->getBeginLoc(), Ty, VK_LValue, OK_Ordinary, Base);
3817
3818 // Writebacks are performed with `=` binary operator, which allows for
3819 // overload resolution on writeback result expressions.
3820 Res = SemaRef.ActOnBinOp(SemaRef.getCurScope(), Param->getBeginLoc(),
3821 tok::equal, ArgOpV, OpV);
3822
3823 if (Res.isInvalid())
3824 return ExprError();
3825 Expr *Writeback = Res.get();
3826 auto *OutExpr =
3827 HLSLOutArgExpr::Create(Ctx, Ty, ArgOpV, OpV, Writeback, IsInOut);
3828
3829 return ExprResult(OutExpr);
3830}
3831
3833 // If HLSL gains support for references, all the cites that use this will need
3834 // to be updated with semantic checking to produce errors for
3835 // pointers/references.
3836 assert(!Ty->isReferenceType() &&
3837 "Pointer and reference types cannot be inout or out parameters");
3838 Ty = SemaRef.getASTContext().getLValueReferenceType(Ty);
3839 Ty.addRestrict();
3840 return Ty;
3841}
3842
3844 QualType QT = VD->getType();
3845 return VD->getDeclContext()->isTranslationUnit() &&
3847 VD->getStorageClass() != SC_Static &&
3848 !VD->hasAttr<HLSLVkConstantIdAttr>() &&
3850}
3851
3853 // The variable already has an address space (groupshared for ex).
3854 if (Decl->getType().hasAddressSpace())
3855 return;
3856
3857 if (Decl->getType()->isDependentType())
3858 return;
3859
3860 QualType Type = Decl->getType();
3861
3862 if (Decl->hasAttr<HLSLVkExtBuiltinInputAttr>()) {
3863 LangAS ImplAS = LangAS::hlsl_input;
3864 Type = SemaRef.getASTContext().getAddrSpaceQualType(Type, ImplAS);
3865 Decl->setType(Type);
3866 return;
3867 }
3868
3869 if (Type->isSamplerT() || Type->isVoidType())
3870 return;
3871
3872 // Resource handles.
3874 return;
3875
3876 // Only static globals belong to the Private address space.
3877 // Non-static globals belongs to the cbuffer.
3878 if (Decl->getStorageClass() != SC_Static && !Decl->isStaticDataMember())
3879 return;
3880
3882 Type = SemaRef.getASTContext().getAddrSpaceQualType(Type, ImplAS);
3883 Decl->setType(Type);
3884}
3885
3887 if (VD->hasGlobalStorage()) {
3888 // make sure the declaration has a complete type
3889 if (SemaRef.RequireCompleteType(
3890 VD->getLocation(),
3891 SemaRef.getASTContext().getBaseElementType(VD->getType()),
3892 diag::err_typecheck_decl_incomplete_type)) {
3893 VD->setInvalidDecl();
3895 return;
3896 }
3897
3898 // Global variables outside a cbuffer block that are not a resource, static,
3899 // groupshared, or an empty array or struct belong to the default constant
3900 // buffer $Globals (to be created at the end of the translation unit).
3902 // update address space to hlsl_constant
3905 VD->setType(NewTy);
3906 DefaultCBufferDecls.push_back(VD);
3907 }
3908
3909 // find all resources bindings on decl
3910 if (VD->getType()->isHLSLIntangibleType())
3911 collectResourceBindingsOnVarDecl(VD);
3912
3914 VD->hasAttr<HLSLVkConstantIdAttr>()) {
3915 // Make the variable for resources static. The global externally visible
3916 // storage is accessed through the handle, which is a member. The variable
3917 // itself is not externally visible.
3919 }
3920
3921 // process explicit bindings
3922 processExplicitBindingsOnDecl(VD);
3923
3924 if (VD->getType()->isHLSLResourceRecordArray()) {
3925 // If the resource array does not have an explicit binding attribute,
3926 // create an implicit one. It will be used to transfer implicit binding
3927 // order_ID to codegen.
3928 ResourceBindingAttrs Binding(VD);
3929 if (!Binding.isExplicit()) {
3930 uint32_t OrderID = getNextImplicitBindingOrderID();
3931 if (Binding.hasBinding())
3932 Binding.setImplicitOrderID(OrderID);
3933 else {
3936 OrderID);
3937 // Re-create the binding object to pick up the new attribute.
3938 Binding = ResourceBindingAttrs(VD);
3939 }
3940 }
3941
3942 // Get to the base type of a potentially multi-dimensional array.
3944
3945 const CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
3946 if (hasCounterHandle(RD)) {
3947 if (!Binding.hasCounterImplicitOrderID()) {
3948 uint32_t OrderID = getNextImplicitBindingOrderID();
3949 Binding.setCounterImplicitOrderID(OrderID);
3950 }
3951 }
3952 }
3953 }
3954
3956}
3957
3958bool SemaHLSL::initGlobalResourceDecl(VarDecl *VD) {
3959 assert(VD->getType()->isHLSLResourceRecord() &&
3960 "expected resource record type");
3961
3963 uint64_t UIntTySize = AST.getTypeSize(AST.UnsignedIntTy);
3964 uint64_t IntTySize = AST.getTypeSize(AST.IntTy);
3965
3966 // Gather resource binding attributes.
3967 ResourceBindingAttrs Binding(VD);
3968
3969 // Find correct initialization method and create its arguments.
3970 QualType ResourceTy = VD->getType();
3971 CXXRecordDecl *ResourceDecl = ResourceTy->getAsCXXRecordDecl();
3972 CXXMethodDecl *CreateMethod = nullptr;
3974
3975 bool HasCounter = hasCounterHandle(ResourceDecl);
3976 const char *CreateMethodName;
3977 if (Binding.isExplicit())
3978 CreateMethodName = HasCounter ? "__createFromBindingWithImplicitCounter"
3979 : "__createFromBinding";
3980 else
3981 CreateMethodName = HasCounter
3982 ? "__createFromImplicitBindingWithImplicitCounter"
3983 : "__createFromImplicitBinding";
3984
3985 CreateMethod =
3986 lookupMethod(SemaRef, ResourceDecl, CreateMethodName, VD->getLocation());
3987
3988 if (!CreateMethod)
3989 // This can happen if someone creates a struct that looks like an HLSL
3990 // resource record but does not have the required static create method.
3991 // No binding will be generated for it.
3992 return false;
3993
3994 if (Binding.isExplicit()) {
3995 IntegerLiteral *RegSlot =
3996 IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, Binding.getSlot()),
3998 Args.push_back(RegSlot);
3999 } else {
4000 uint32_t OrderID = (Binding.hasImplicitOrderID())
4001 ? Binding.getImplicitOrderID()
4002 : getNextImplicitBindingOrderID();
4003 IntegerLiteral *OrderId =
4004 IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, OrderID),
4006 Args.push_back(OrderId);
4007 }
4008
4009 IntegerLiteral *Space =
4010 IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, Binding.getSpace()),
4011 AST.UnsignedIntTy, SourceLocation());
4012 Args.push_back(Space);
4013
4014 IntegerLiteral *RangeSize = IntegerLiteral::Create(
4015 AST, llvm::APInt(IntTySize, 1), AST.IntTy, SourceLocation());
4016 Args.push_back(RangeSize);
4017
4018 IntegerLiteral *Index = IntegerLiteral::Create(
4019 AST, llvm::APInt(UIntTySize, 0), AST.UnsignedIntTy, SourceLocation());
4020 Args.push_back(Index);
4021
4022 StringRef VarName = VD->getName();
4023 StringLiteral *Name = StringLiteral::Create(
4024 AST, VarName, StringLiteralKind::Ordinary, false,
4025 AST.getStringLiteralArrayType(AST.CharTy.withConst(), VarName.size()),
4026 SourceLocation());
4027 ImplicitCastExpr *NameCast = ImplicitCastExpr::Create(
4028 AST, AST.getPointerType(AST.CharTy.withConst()), CK_ArrayToPointerDecay,
4029 Name, nullptr, VK_PRValue, FPOptionsOverride());
4030 Args.push_back(NameCast);
4031
4032 if (HasCounter) {
4033 // Will this be in the correct order?
4034 uint32_t CounterOrderID = getNextImplicitBindingOrderID();
4035 IntegerLiteral *CounterId =
4036 IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, CounterOrderID),
4037 AST.UnsignedIntTy, SourceLocation());
4038 Args.push_back(CounterId);
4039 }
4040
4041 // Make sure the create method template is instantiated and emitted.
4042 if (!CreateMethod->isDefined() && CreateMethod->isTemplateInstantiation())
4043 SemaRef.InstantiateFunctionDefinition(VD->getLocation(), CreateMethod,
4044 true);
4045
4046 // Create CallExpr with a call to the static method and set it as the decl
4047 // initialization.
4048 DeclRefExpr *DRE = DeclRefExpr::Create(
4049 AST, NestedNameSpecifierLoc(), SourceLocation(), CreateMethod, false,
4050 CreateMethod->getNameInfo(), CreateMethod->getType(), VK_PRValue);
4051
4052 auto *ImpCast = ImplicitCastExpr::Create(
4053 AST, AST.getPointerType(CreateMethod->getType()),
4054 CK_FunctionToPointerDecay, DRE, nullptr, VK_PRValue, FPOptionsOverride());
4055
4056 CallExpr *InitExpr =
4057 CallExpr::Create(AST, ImpCast, Args, ResourceTy, VK_PRValue,
4058 SourceLocation(), FPOptionsOverride());
4059 VD->setInit(InitExpr);
4061 SemaRef.CheckCompleteVariableDeclaration(VD);
4062 return true;
4063}
4064
4065bool SemaHLSL::initGlobalResourceArrayDecl(VarDecl *VD) {
4066 assert(VD->getType()->isHLSLResourceRecordArray() &&
4067 "expected array of resource records");
4068
4069 // Individual resources in a resource array are not initialized here. They
4070 // are initialized later on during codegen when the individual resources are
4071 // accessed. Codegen will emit a call to the resource initialization method
4072 // with the specified array index. We need to make sure though that the method
4073 // for the specific resource type is instantiated, so codegen can emit a call
4074 // to it when the array element is accessed.
4075
4076 // Find correct initialization method based on the resource binding
4077 // information.
4078 ASTContext &AST = SemaRef.getASTContext();
4079 QualType ResElementTy = AST.getBaseElementType(VD->getType());
4080 CXXRecordDecl *ResourceDecl = ResElementTy->getAsCXXRecordDecl();
4081 CXXMethodDecl *CreateMethod = nullptr;
4082
4083 bool HasCounter = hasCounterHandle(ResourceDecl);
4084 ResourceBindingAttrs ResourceAttrs(VD);
4085 if (ResourceAttrs.isExplicit())
4086 // Resource has explicit binding.
4087 CreateMethod =
4088 lookupMethod(SemaRef, ResourceDecl,
4089 HasCounter ? "__createFromBindingWithImplicitCounter"
4090 : "__createFromBinding",
4091 VD->getLocation());
4092 else
4093 // Resource has implicit binding.
4094 CreateMethod = lookupMethod(
4095 SemaRef, ResourceDecl,
4096 HasCounter ? "__createFromImplicitBindingWithImplicitCounter"
4097 : "__createFromImplicitBinding",
4098 VD->getLocation());
4099
4100 if (!CreateMethod)
4101 return false;
4102
4103 // Make sure the create method template is instantiated and emitted.
4104 if (!CreateMethod->isDefined() && CreateMethod->isTemplateInstantiation())
4105 SemaRef.InstantiateFunctionDefinition(VD->getLocation(), CreateMethod,
4106 true);
4107 return true;
4108}
4109
4110// Returns true if the initialization has been handled.
4111// Returns false to use default initialization.
4113 // Objects in the hlsl_constant address space are initialized
4114 // externally, so don't synthesize an implicit initializer.
4116 return true;
4117
4118 // Initialize resources at the global scope
4119 if (VD->hasGlobalStorage()) {
4120 const Type *Ty = VD->getType().getTypePtr();
4121 if (Ty->isHLSLResourceRecord())
4122 return initGlobalResourceDecl(VD);
4123 if (Ty->isHLSLResourceRecordArray())
4124 return initGlobalResourceArrayDecl(VD);
4125 }
4126 return false;
4127}
4128
4129// Return true if everything is ok; returns false if there was an error.
4131 Expr *RHSExpr, SourceLocation Loc) {
4132 assert((LHSExpr->getType()->isHLSLResourceRecord() ||
4133 LHSExpr->getType()->isHLSLResourceRecordArray()) &&
4134 "expected LHS to be a resource record or array of resource records");
4135 if (Opc != BO_Assign)
4136 return true;
4137
4138 // If LHS is an array subscript, get the underlying declaration.
4139 Expr *E = LHSExpr;
4140 while (auto *ASE = dyn_cast<ArraySubscriptExpr>(E))
4141 E = ASE->getBase()->IgnoreParenImpCasts();
4142
4143 // Report error if LHS is a resource declared at a global scope.
4144 if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParens())) {
4145 if (VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
4146 if (VD->hasGlobalStorage()) {
4147 // assignment to global resource is not allowed
4148 SemaRef.Diag(Loc, diag::err_hlsl_assign_to_global_resource) << VD;
4149 SemaRef.Diag(VD->getLocation(), diag::note_var_declared_here) << VD;
4150 return false;
4151 }
4152 }
4153 }
4154 return true;
4155}
4156
4157// Walks though the global variable declaration, collects all resource binding
4158// requirements and adds them to Bindings
4159void SemaHLSL::collectResourceBindingsOnVarDecl(VarDecl *VD) {
4160 assert(VD->hasGlobalStorage() && VD->getType()->isHLSLIntangibleType() &&
4161 "expected global variable that contains HLSL resource");
4162
4163 // Cbuffers and Tbuffers are HLSLBufferDecl types
4164 if (const HLSLBufferDecl *CBufferOrTBuffer = dyn_cast<HLSLBufferDecl>(VD)) {
4165 Bindings.addDeclBindingInfo(VD, CBufferOrTBuffer->isCBuffer()
4166 ? ResourceClass::CBuffer
4167 : ResourceClass::SRV);
4168 return;
4169 }
4170
4171 // Unwrap arrays
4172 // FIXME: Calculate array size while unwrapping
4173 const Type *Ty = VD->getType()->getUnqualifiedDesugaredType();
4174 while (Ty->isArrayType()) {
4175 const ArrayType *AT = cast<ArrayType>(Ty);
4177 }
4178
4179 // Resource (or array of resources)
4180 if (const HLSLAttributedResourceType *AttrResType =
4181 HLSLAttributedResourceType::findHandleTypeOnResource(Ty)) {
4182 Bindings.addDeclBindingInfo(VD, AttrResType->getAttrs().ResourceClass);
4183 return;
4184 }
4185
4186 // User defined record type
4187 if (const RecordType *RT = dyn_cast<RecordType>(Ty))
4188 collectResourceBindingsOnUserRecordDecl(VD, RT);
4189}
4190
4191// Walks though the explicit resource binding attributes on the declaration,
4192// and makes sure there is a resource that matched the binding and updates
4193// DeclBindingInfoLists
4194void SemaHLSL::processExplicitBindingsOnDecl(VarDecl *VD) {
4195 assert(VD->hasGlobalStorage() && "expected global variable");
4196
4197 bool HasBinding = false;
4198 for (Attr *A : VD->attrs()) {
4200 HasBinding = true;
4201
4202 HLSLResourceBindingAttr *RBA = dyn_cast<HLSLResourceBindingAttr>(A);
4203 if (!RBA || !RBA->hasRegisterSlot())
4204 continue;
4205 HasBinding = true;
4206
4207 RegisterType RT = RBA->getRegisterType();
4208 assert(RT != RegisterType::I && "invalid or obsolete register type should "
4209 "never have an attribute created");
4210
4211 if (RT == RegisterType::C) {
4212 if (Bindings.hasBindingInfoForDecl(VD))
4213 SemaRef.Diag(VD->getLocation(),
4214 diag::warn_hlsl_user_defined_type_missing_member)
4215 << static_cast<int>(RT);
4216 continue;
4217 }
4218
4219 // Find DeclBindingInfo for this binding and update it, or report error
4220 // if it does not exist (user type does to contain resources with the
4221 // expected resource class).
4223 if (DeclBindingInfo *BI = Bindings.getDeclBindingInfo(VD, RC)) {
4224 // update binding info
4225 BI->setBindingAttribute(RBA, BindingType::Explicit);
4226 } else {
4227 SemaRef.Diag(VD->getLocation(),
4228 diag::warn_hlsl_user_defined_type_missing_member)
4229 << static_cast<int>(RT);
4230 }
4231 }
4232
4233 if (!HasBinding && isResourceRecordTypeOrArrayOf(VD))
4234 SemaRef.Diag(VD->getLocation(), diag::warn_hlsl_implicit_binding);
4235}
4236namespace {
4237class InitListTransformer {
4238 Sema &S;
4239 ASTContext &Ctx;
4240 QualType InitTy;
4241 QualType *DstIt = nullptr;
4242 Expr **ArgIt = nullptr;
4243 // Is wrapping the destination type iterator required? This is only used for
4244 // incomplete array types where we loop over the destination type since we
4245 // don't know the full number of elements from the declaration.
4246 bool Wrap;
4247
4248 bool castInitializer(Expr *E) {
4249 assert(DstIt && "This should always be something!");
4250 if (DstIt == DestTypes.end()) {
4251 if (!Wrap) {
4252 ArgExprs.push_back(E);
4253 // This is odd, but it isn't technically a failure due to conversion, we
4254 // handle mismatched counts of arguments differently.
4255 return true;
4256 }
4257 DstIt = DestTypes.begin();
4258 }
4259 InitializedEntity Entity = InitializedEntity::InitializeParameter(
4260 Ctx, *DstIt, /* Consumed (ObjC) */ false);
4261 ExprResult Res = S.PerformCopyInitialization(Entity, E->getBeginLoc(), E);
4262 if (Res.isInvalid())
4263 return false;
4264 Expr *Init = Res.get();
4265 ArgExprs.push_back(Init);
4266 DstIt++;
4267 return true;
4268 }
4269
4270 bool buildInitializerListImpl(Expr *E) {
4271 // If this is an initialization list, traverse the sub initializers.
4272 if (auto *Init = dyn_cast<InitListExpr>(E)) {
4273 for (auto *SubInit : Init->inits())
4274 if (!buildInitializerListImpl(SubInit))
4275 return false;
4276 return true;
4277 }
4278
4279 // If this is a scalar type, just enqueue the expression.
4280 QualType Ty = E->getType();
4281
4282 if (Ty->isScalarType() || (Ty->isRecordType() && !Ty->isAggregateType()))
4283 return castInitializer(E);
4284
4285 if (auto *VecTy = Ty->getAs<VectorType>()) {
4286 uint64_t Size = VecTy->getNumElements();
4287
4288 QualType SizeTy = Ctx.getSizeType();
4289 uint64_t SizeTySize = Ctx.getTypeSize(SizeTy);
4290 for (uint64_t I = 0; I < Size; ++I) {
4291 auto *Idx = IntegerLiteral::Create(Ctx, llvm::APInt(SizeTySize, I),
4292 SizeTy, SourceLocation());
4293
4295 E, E->getBeginLoc(), Idx, E->getEndLoc());
4296 if (ElExpr.isInvalid())
4297 return false;
4298 if (!castInitializer(ElExpr.get()))
4299 return false;
4300 }
4301 return true;
4302 }
4303 if (auto *MTy = Ty->getAs<ConstantMatrixType>()) {
4304 unsigned Rows = MTy->getNumRows();
4305 unsigned Cols = MTy->getNumColumns();
4306 QualType ElemTy = MTy->getElementType();
4307
4308 for (unsigned C = 0; C < Cols; ++C) {
4309 for (unsigned R = 0; R < Rows; ++R) {
4310 // row index literal
4311 Expr *RowIdx = IntegerLiteral::Create(
4312 Ctx, llvm::APInt(Ctx.getIntWidth(Ctx.IntTy), R), Ctx.IntTy,
4313 E->getBeginLoc());
4314 // column index literal
4315 Expr *ColIdx = IntegerLiteral::Create(
4316 Ctx, llvm::APInt(Ctx.getIntWidth(Ctx.IntTy), C), Ctx.IntTy,
4317 E->getBeginLoc());
4319 E, RowIdx, ColIdx, E->getEndLoc());
4320 if (ElExpr.isInvalid())
4321 return false;
4322 if (!castInitializer(ElExpr.get()))
4323 return false;
4324 ElExpr.get()->setType(ElemTy);
4325 }
4326 }
4327 return true;
4328 }
4329
4330 if (auto *ArrTy = dyn_cast<ConstantArrayType>(Ty.getTypePtr())) {
4331 uint64_t Size = ArrTy->getZExtSize();
4332 QualType SizeTy = Ctx.getSizeType();
4333 uint64_t SizeTySize = Ctx.getTypeSize(SizeTy);
4334 for (uint64_t I = 0; I < Size; ++I) {
4335 auto *Idx = IntegerLiteral::Create(Ctx, llvm::APInt(SizeTySize, I),
4336 SizeTy, SourceLocation());
4338 E, E->getBeginLoc(), Idx, E->getEndLoc());
4339 if (ElExpr.isInvalid())
4340 return false;
4341 if (!buildInitializerListImpl(ElExpr.get()))
4342 return false;
4343 }
4344 return true;
4345 }
4346
4347 if (auto *RD = Ty->getAsCXXRecordDecl()) {
4348 llvm::SmallVector<CXXRecordDecl *> RecordDecls;
4349 RecordDecls.push_back(RD);
4350 while (RecordDecls.back()->getNumBases()) {
4351 CXXRecordDecl *D = RecordDecls.back();
4352 assert(D->getNumBases() == 1 &&
4353 "HLSL doesn't support multiple inheritance");
4354 RecordDecls.push_back(
4356 }
4357 while (!RecordDecls.empty()) {
4358 CXXRecordDecl *RD = RecordDecls.pop_back_val();
4359 for (auto *FD : RD->fields()) {
4360 if (FD->isUnnamedBitField())
4361 continue;
4362 DeclAccessPair Found = DeclAccessPair::make(FD, FD->getAccess());
4363 DeclarationNameInfo NameInfo(FD->getDeclName(), E->getBeginLoc());
4365 E, false, E->getBeginLoc(), CXXScopeSpec(), FD, Found, NameInfo);
4366 if (Res.isInvalid())
4367 return false;
4368 if (!buildInitializerListImpl(Res.get()))
4369 return false;
4370 }
4371 }
4372 }
4373 return true;
4374 }
4375
4376 Expr *generateInitListsImpl(QualType Ty) {
4377 assert(ArgIt != ArgExprs.end() && "Something is off in iteration!");
4378 if (Ty->isScalarType() || (Ty->isRecordType() && !Ty->isAggregateType()))
4379 return *(ArgIt++);
4380
4381 llvm::SmallVector<Expr *> Inits;
4382 Ty = Ty.getDesugaredType(Ctx);
4383 if (Ty->isVectorType() || Ty->isConstantArrayType() ||
4384 Ty->isConstantMatrixType()) {
4385 QualType ElTy;
4386 uint64_t Size = 0;
4387 if (auto *ATy = Ty->getAs<VectorType>()) {
4388 ElTy = ATy->getElementType();
4389 Size = ATy->getNumElements();
4390 } else if (auto *CMTy = Ty->getAs<ConstantMatrixType>()) {
4391 ElTy = CMTy->getElementType();
4392 Size = CMTy->getNumElementsFlattened();
4393 } else {
4394 auto *VTy = cast<ConstantArrayType>(Ty.getTypePtr());
4395 ElTy = VTy->getElementType();
4396 Size = VTy->getZExtSize();
4397 }
4398 for (uint64_t I = 0; I < Size; ++I)
4399 Inits.push_back(generateInitListsImpl(ElTy));
4400 }
4401 if (auto *RD = Ty->getAsCXXRecordDecl()) {
4402 llvm::SmallVector<CXXRecordDecl *> RecordDecls;
4403 RecordDecls.push_back(RD);
4404 while (RecordDecls.back()->getNumBases()) {
4405 CXXRecordDecl *D = RecordDecls.back();
4406 assert(D->getNumBases() == 1 &&
4407 "HLSL doesn't support multiple inheritance");
4408 RecordDecls.push_back(
4410 }
4411 while (!RecordDecls.empty()) {
4412 CXXRecordDecl *RD = RecordDecls.pop_back_val();
4413 for (auto *FD : RD->fields())
4414 if (!FD->isUnnamedBitField())
4415 Inits.push_back(generateInitListsImpl(FD->getType()));
4416 }
4417 }
4418 auto *NewInit = new (Ctx) InitListExpr(Ctx, Inits.front()->getBeginLoc(),
4419 Inits, Inits.back()->getEndLoc());
4420 NewInit->setType(Ty);
4421 return NewInit;
4422 }
4423
4424public:
4425 llvm::SmallVector<QualType, 16> DestTypes;
4426 llvm::SmallVector<Expr *, 16> ArgExprs;
4427 InitListTransformer(Sema &SemaRef, const InitializedEntity &Entity)
4428 : S(SemaRef), Ctx(SemaRef.getASTContext()),
4429 Wrap(Entity.getType()->isIncompleteArrayType()) {
4430 InitTy = Entity.getType().getNonReferenceType();
4431 // When we're generating initializer lists for incomplete array types we
4432 // need to wrap around both when building the initializers and when
4433 // generating the final initializer lists.
4434 if (Wrap) {
4435 assert(InitTy->isIncompleteArrayType());
4436 const IncompleteArrayType *IAT = Ctx.getAsIncompleteArrayType(InitTy);
4437 InitTy = IAT->getElementType();
4438 }
4439 BuildFlattenedTypeList(InitTy, DestTypes);
4440 DstIt = DestTypes.begin();
4441 }
4442
4443 bool buildInitializerList(Expr *E) { return buildInitializerListImpl(E); }
4444
4445 Expr *generateInitLists() {
4446 assert(!ArgExprs.empty() &&
4447 "Call buildInitializerList to generate argument expressions.");
4448 ArgIt = ArgExprs.begin();
4449 if (!Wrap)
4450 return generateInitListsImpl(InitTy);
4451 llvm::SmallVector<Expr *> Inits;
4452 while (ArgIt != ArgExprs.end())
4453 Inits.push_back(generateInitListsImpl(InitTy));
4454
4455 auto *NewInit = new (Ctx) InitListExpr(Ctx, Inits.front()->getBeginLoc(),
4456 Inits, Inits.back()->getEndLoc());
4457 llvm::APInt ArySize(64, Inits.size());
4458 NewInit->setType(Ctx.getConstantArrayType(InitTy, ArySize, nullptr,
4459 ArraySizeModifier::Normal, 0));
4460 return NewInit;
4461 }
4462};
4463} // namespace
4464
4466 InitListExpr *Init) {
4467 // If the initializer is a scalar, just return it.
4468 if (Init->getType()->isScalarType())
4469 return true;
4470 ASTContext &Ctx = SemaRef.getASTContext();
4471 InitListTransformer ILT(SemaRef, Entity);
4472
4473 for (unsigned I = 0; I < Init->getNumInits(); ++I) {
4474 Expr *E = Init->getInit(I);
4475 if (E->HasSideEffects(Ctx)) {
4476 QualType Ty = E->getType();
4477 if (Ty->isRecordType())
4478 E = new (Ctx) MaterializeTemporaryExpr(Ty, E, E->isLValue());
4479 E = new (Ctx) OpaqueValueExpr(E->getBeginLoc(), Ty, E->getValueKind(),
4480 E->getObjectKind(), E);
4481 Init->setInit(I, E);
4482 }
4483 if (!ILT.buildInitializerList(E))
4484 return false;
4485 }
4486 size_t ExpectedSize = ILT.DestTypes.size();
4487 size_t ActualSize = ILT.ArgExprs.size();
4488 if (ExpectedSize == 0 && ActualSize == 0)
4489 return true;
4490
4491 // For incomplete arrays it is completely arbitrary to choose whether we think
4492 // the user intended fewer or more elements. This implementation assumes that
4493 // the user intended more, and errors that there are too few initializers to
4494 // complete the final element.
4495 if (Entity.getType()->isIncompleteArrayType())
4496 ExpectedSize =
4497 ((ActualSize + ExpectedSize - 1) / ExpectedSize) * ExpectedSize;
4498
4499 // An initializer list might be attempting to initialize a reference or
4500 // rvalue-reference. When checking the initializer we should look through
4501 // the reference.
4502 QualType InitTy = Entity.getType().getNonReferenceType();
4503 if (InitTy.hasAddressSpace())
4504 InitTy = SemaRef.getASTContext().removeAddrSpaceQualType(InitTy);
4505 if (ExpectedSize != ActualSize) {
4506 int TooManyOrFew = ActualSize > ExpectedSize ? 1 : 0;
4507 SemaRef.Diag(Init->getBeginLoc(), diag::err_hlsl_incorrect_num_initializers)
4508 << TooManyOrFew << InitTy << ExpectedSize << ActualSize;
4509 return false;
4510 }
4511
4512 // generateInitListsImpl will always return an InitListExpr here, because the
4513 // scalar case is handled above.
4514 auto *NewInit = cast<InitListExpr>(ILT.generateInitLists());
4515 Init->resizeInits(Ctx, NewInit->getNumInits());
4516 for (unsigned I = 0; I < NewInit->getNumInits(); ++I)
4517 Init->updateInit(Ctx, I, NewInit->getInit(I));
4518 return true;
4519}
4520
4522 const HLSLVkConstantIdAttr *ConstIdAttr =
4523 VDecl->getAttr<HLSLVkConstantIdAttr>();
4524 if (!ConstIdAttr)
4525 return true;
4526
4527 ASTContext &Context = SemaRef.getASTContext();
4528
4529 APValue InitValue;
4530 if (!Init->isCXX11ConstantExpr(Context, &InitValue)) {
4531 Diag(VDecl->getLocation(), diag::err_specialization_const);
4532 VDecl->setInvalidDecl();
4533 return false;
4534 }
4535
4536 Builtin::ID BID =
4538
4539 // Argument 1: The ID from the attribute
4540 int ConstantID = ConstIdAttr->getId();
4541 llvm::APInt IDVal(Context.getIntWidth(Context.IntTy), ConstantID);
4542 Expr *IdExpr = IntegerLiteral::Create(Context, IDVal, Context.IntTy,
4543 ConstIdAttr->getLocation());
4544
4545 SmallVector<Expr *, 2> Args = {IdExpr, Init};
4546 Expr *C = SemaRef.BuildBuiltinCallExpr(Init->getExprLoc(), BID, Args);
4547 if (C->getType()->getCanonicalTypeUnqualified() !=
4549 C = SemaRef
4550 .BuildCStyleCastExpr(SourceLocation(),
4551 Context.getTrivialTypeSourceInfo(
4552 Init->getType(), Init->getExprLoc()),
4553 SourceLocation(), C)
4554 .get();
4555 }
4556 Init = C;
4557 return true;
4558}
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)
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)
static CXXRecordDecl * findRecordDeclInContext(IdentifierInfo *II, DeclContext *DC)
Definition SemaHLSL.cpp:404
static bool CheckExpectedBitWidth(Sema *S, CallExpr *TheCall, unsigned ArgOrdinal, unsigned Width)
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)
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:45
attr::Kind getKind() const
Definition Attr.h:91
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
uint64_t getZExtSize() const
Return the size zero-extended as a uint64_t.
Definition TypeBase.h:3836
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:985
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:878
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:181
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:48
const llvm::hlsl::rootsig::RootElement & getElement() const
Definition SemaHLSL.h:47