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