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