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