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 D->addAttr(::new (getASTContext())
1773 HLSLVkPushConstantAttr(getASTContext(), AL));
1774}
1775
1777 uint32_t Id;
1778 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), Id))
1779 return;
1780 HLSLVkConstantIdAttr *NewAttr = mergeVkConstantIdAttr(D, AL, Id);
1781 if (NewAttr)
1782 D->addAttr(NewAttr);
1783}
1784
1786 uint32_t Binding = 0;
1787 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), Binding))
1788 return;
1789 uint32_t Set = 0;
1790 if (AL.getNumArgs() > 1 &&
1791 !SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(1), Set))
1792 return;
1793
1794 D->addAttr(::new (getASTContext())
1795 HLSLVkBindingAttr(getASTContext(), AL, Binding, Set));
1796}
1797
1799 uint32_t Location;
1800 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), Location))
1801 return;
1802
1803 D->addAttr(::new (getASTContext())
1804 HLSLVkLocationAttr(getASTContext(), AL, Location));
1805}
1806
1808 const auto *VT = T->getAs<VectorType>();
1809
1810 if (!T->hasUnsignedIntegerRepresentation() ||
1811 (VT && VT->getNumElements() > 3)) {
1812 Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type)
1813 << AL << "uint/uint2/uint3";
1814 return false;
1815 }
1816
1817 return true;
1818}
1819
1821 const auto *VT = T->getAs<VectorType>();
1822 if (!T->hasFloatingRepresentation() || (VT && VT->getNumElements() > 4)) {
1823 Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type)
1824 << AL << "float/float1/float2/float3/float4";
1825 return false;
1826 }
1827
1828 return true;
1829}
1830
1832 std::optional<unsigned> Index) {
1833 std::string SemanticName = AL.getAttrName()->getName().upper();
1834
1835 auto *VD = cast<ValueDecl>(D);
1836 QualType ValueType = VD->getType();
1837 if (auto *FD = dyn_cast<FunctionDecl>(D))
1838 ValueType = FD->getReturnType();
1839
1840 bool IsOutput = false;
1841 if (HLSLParamModifierAttr *MA = D->getAttr<HLSLParamModifierAttr>()) {
1842 if (MA->isOut()) {
1843 IsOutput = true;
1844 ValueType = cast<ReferenceType>(ValueType)->getPointeeType();
1845 }
1846 }
1847
1848 if (SemanticName == "SV_DISPATCHTHREADID") {
1849 diagnoseInputIDType(ValueType, AL);
1850 if (IsOutput)
1851 Diag(AL.getLoc(), diag::err_hlsl_semantic_output_not_supported) << AL;
1852 if (Index.has_value())
1853 Diag(AL.getLoc(), diag::err_hlsl_semantic_indexing_not_supported) << AL;
1855 return;
1856 }
1857
1858 if (SemanticName == "SV_GROUPINDEX") {
1859 if (IsOutput)
1860 Diag(AL.getLoc(), diag::err_hlsl_semantic_output_not_supported) << AL;
1861 if (Index.has_value())
1862 Diag(AL.getLoc(), diag::err_hlsl_semantic_indexing_not_supported) << AL;
1864 return;
1865 }
1866
1867 if (SemanticName == "SV_GROUPTHREADID") {
1868 diagnoseInputIDType(ValueType, AL);
1869 if (IsOutput)
1870 Diag(AL.getLoc(), diag::err_hlsl_semantic_output_not_supported) << AL;
1871 if (Index.has_value())
1872 Diag(AL.getLoc(), diag::err_hlsl_semantic_indexing_not_supported) << AL;
1874 return;
1875 }
1876
1877 if (SemanticName == "SV_GROUPID") {
1878 diagnoseInputIDType(ValueType, AL);
1879 if (IsOutput)
1880 Diag(AL.getLoc(), diag::err_hlsl_semantic_output_not_supported) << AL;
1881 if (Index.has_value())
1882 Diag(AL.getLoc(), diag::err_hlsl_semantic_indexing_not_supported) << AL;
1884 return;
1885 }
1886
1887 if (SemanticName == "SV_POSITION") {
1888 const auto *VT = ValueType->getAs<VectorType>();
1889 if (!ValueType->hasFloatingRepresentation() ||
1890 (VT && VT->getNumElements() > 4))
1891 Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type)
1892 << AL << "float/float1/float2/float3/float4";
1894 return;
1895 }
1896
1897 if (SemanticName == "SV_TARGET") {
1898 const auto *VT = ValueType->getAs<VectorType>();
1899 if (!ValueType->hasFloatingRepresentation() ||
1900 (VT && VT->getNumElements() > 4))
1901 Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type)
1902 << AL << "float/float1/float2/float3/float4";
1904 return;
1905 }
1906
1907 Diag(AL.getLoc(), diag::err_hlsl_unknown_semantic) << AL;
1908}
1909
1911 uint32_t IndexValue, ExplicitIndex;
1912 SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), IndexValue);
1913 SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(1), ExplicitIndex);
1914 assert(IndexValue > 0 ? ExplicitIndex : true);
1915 std::optional<unsigned> Index =
1916 ExplicitIndex ? std::optional<unsigned>(IndexValue) : std::nullopt;
1917
1918 if (AL.getAttrName()->getName().starts_with_insensitive("SV_"))
1919 diagnoseSystemSemanticAttr(D, AL, Index);
1920 else
1922}
1923
1926 Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_ast_node)
1927 << AL << "shader constant in a constant buffer";
1928 return;
1929 }
1930
1931 uint32_t SubComponent;
1932 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), SubComponent))
1933 return;
1934 uint32_t Component;
1935 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(1), Component))
1936 return;
1937
1938 QualType T = cast<VarDecl>(D)->getType().getCanonicalType();
1939 // Check if T is an array or struct type.
1940 // TODO: mark matrix type as aggregate type.
1941 bool IsAggregateTy = (T->isArrayType() || T->isStructureType());
1942
1943 // Check Component is valid for T.
1944 if (Component) {
1945 unsigned Size = getASTContext().getTypeSize(T);
1946 if (IsAggregateTy || Size > 128) {
1947 Diag(AL.getLoc(), diag::err_hlsl_packoffset_cross_reg_boundary);
1948 return;
1949 } else {
1950 // Make sure Component + sizeof(T) <= 4.
1951 if ((Component * 32 + Size) > 128) {
1952 Diag(AL.getLoc(), diag::err_hlsl_packoffset_cross_reg_boundary);
1953 return;
1954 }
1955 QualType EltTy = T;
1956 if (const auto *VT = T->getAs<VectorType>())
1957 EltTy = VT->getElementType();
1958 unsigned Align = getASTContext().getTypeAlign(EltTy);
1959 if (Align > 32 && Component == 1) {
1960 // NOTE: Component 3 will hit err_hlsl_packoffset_cross_reg_boundary.
1961 // So we only need to check Component 1 here.
1962 Diag(AL.getLoc(), diag::err_hlsl_packoffset_alignment_mismatch)
1963 << Align << EltTy;
1964 return;
1965 }
1966 }
1967 }
1968
1969 D->addAttr(::new (getASTContext()) HLSLPackOffsetAttr(
1970 getASTContext(), AL, SubComponent, Component));
1971}
1972
1974 StringRef Str;
1975 SourceLocation ArgLoc;
1976 if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
1977 return;
1978
1979 llvm::Triple::EnvironmentType ShaderType;
1980 if (!HLSLShaderAttr::ConvertStrToEnvironmentType(Str, ShaderType)) {
1981 Diag(AL.getLoc(), diag::warn_attribute_type_not_supported)
1982 << AL << Str << ArgLoc;
1983 return;
1984 }
1985
1986 // FIXME: check function match the shader stage.
1987
1988 HLSLShaderAttr *NewAttr = mergeShaderAttr(D, AL, ShaderType);
1989 if (NewAttr)
1990 D->addAttr(NewAttr);
1991}
1992
1994 Sema &S, QualType Wrapped, ArrayRef<const Attr *> AttrList,
1995 QualType &ResType, HLSLAttributedResourceLocInfo *LocInfo) {
1996 assert(AttrList.size() && "expected list of resource attributes");
1997
1998 QualType ContainedTy = QualType();
1999 TypeSourceInfo *ContainedTyInfo = nullptr;
2000 SourceLocation LocBegin = AttrList[0]->getRange().getBegin();
2001 SourceLocation LocEnd = AttrList[0]->getRange().getEnd();
2002
2003 HLSLAttributedResourceType::Attributes ResAttrs;
2004
2005 bool HasResourceClass = false;
2006 for (const Attr *A : AttrList) {
2007 if (!A)
2008 continue;
2009 LocEnd = A->getRange().getEnd();
2010 switch (A->getKind()) {
2011 case attr::HLSLResourceClass: {
2012 ResourceClass RC = cast<HLSLResourceClassAttr>(A)->getResourceClass();
2013 if (HasResourceClass) {
2014 S.Diag(A->getLocation(), ResAttrs.ResourceClass == RC
2015 ? diag::warn_duplicate_attribute_exact
2016 : diag::warn_duplicate_attribute)
2017 << A;
2018 return false;
2019 }
2020 ResAttrs.ResourceClass = RC;
2021 HasResourceClass = true;
2022 break;
2023 }
2024 case attr::HLSLROV:
2025 if (ResAttrs.IsROV) {
2026 S.Diag(A->getLocation(), diag::warn_duplicate_attribute_exact) << A;
2027 return false;
2028 }
2029 ResAttrs.IsROV = true;
2030 break;
2031 case attr::HLSLRawBuffer:
2032 if (ResAttrs.RawBuffer) {
2033 S.Diag(A->getLocation(), diag::warn_duplicate_attribute_exact) << A;
2034 return false;
2035 }
2036 ResAttrs.RawBuffer = true;
2037 break;
2038 case attr::HLSLIsCounter:
2039 if (ResAttrs.IsCounter) {
2040 S.Diag(A->getLocation(), diag::warn_duplicate_attribute_exact) << A;
2041 return false;
2042 }
2043 ResAttrs.IsCounter = true;
2044 break;
2045 case attr::HLSLContainedType: {
2046 const HLSLContainedTypeAttr *CTAttr = cast<HLSLContainedTypeAttr>(A);
2047 QualType Ty = CTAttr->getType();
2048 if (!ContainedTy.isNull()) {
2049 S.Diag(A->getLocation(), ContainedTy == Ty
2050 ? diag::warn_duplicate_attribute_exact
2051 : diag::warn_duplicate_attribute)
2052 << A;
2053 return false;
2054 }
2055 ContainedTy = Ty;
2056 ContainedTyInfo = CTAttr->getTypeLoc();
2057 break;
2058 }
2059 default:
2060 llvm_unreachable("unhandled resource attribute type");
2061 }
2062 }
2063
2064 if (!HasResourceClass) {
2065 S.Diag(AttrList.back()->getRange().getEnd(),
2066 diag::err_hlsl_missing_resource_class);
2067 return false;
2068 }
2069
2071 Wrapped, ContainedTy, ResAttrs);
2072
2073 if (LocInfo && ContainedTyInfo) {
2074 LocInfo->Range = SourceRange(LocBegin, LocEnd);
2075 LocInfo->ContainedTyInfo = ContainedTyInfo;
2076 }
2077 return true;
2078}
2079
2080// Validates and creates an HLSL attribute that is applied as type attribute on
2081// HLSL resource. The attributes are collected in HLSLResourcesTypeAttrs and at
2082// the end of the declaration they are applied to the declaration type by
2083// wrapping it in HLSLAttributedResourceType.
2085 // only allow resource type attributes on intangible types
2086 if (!T->isHLSLResourceType()) {
2087 Diag(AL.getLoc(), diag::err_hlsl_attribute_needs_intangible_type)
2088 << AL << getASTContext().HLSLResourceTy;
2089 return false;
2090 }
2091
2092 // validate number of arguments
2093 if (!AL.checkExactlyNumArgs(SemaRef, AL.getMinArgs()))
2094 return false;
2095
2096 Attr *A = nullptr;
2097
2101 {
2102 AttributeCommonInfo::AS_CXX11, 0, false /*IsAlignas*/,
2103 false /*IsRegularKeywordAttribute*/
2104 });
2105
2106 switch (AL.getKind()) {
2107 case ParsedAttr::AT_HLSLResourceClass: {
2108 if (!AL.isArgIdent(0)) {
2109 Diag(AL.getLoc(), diag::err_attribute_argument_type)
2110 << AL << AANT_ArgumentIdentifier;
2111 return false;
2112 }
2113
2114 IdentifierLoc *Loc = AL.getArgAsIdent(0);
2115 StringRef Identifier = Loc->getIdentifierInfo()->getName();
2116 SourceLocation ArgLoc = Loc->getLoc();
2117
2118 // Validate resource class value
2119 ResourceClass RC;
2120 if (!HLSLResourceClassAttr::ConvertStrToResourceClass(Identifier, RC)) {
2121 Diag(ArgLoc, diag::warn_attribute_type_not_supported)
2122 << "ResourceClass" << Identifier;
2123 return false;
2124 }
2125 A = HLSLResourceClassAttr::Create(getASTContext(), RC, ACI);
2126 break;
2127 }
2128
2129 case ParsedAttr::AT_HLSLROV:
2130 A = HLSLROVAttr::Create(getASTContext(), ACI);
2131 break;
2132
2133 case ParsedAttr::AT_HLSLRawBuffer:
2134 A = HLSLRawBufferAttr::Create(getASTContext(), ACI);
2135 break;
2136
2137 case ParsedAttr::AT_HLSLIsCounter:
2138 A = HLSLIsCounterAttr::Create(getASTContext(), ACI);
2139 break;
2140
2141 case ParsedAttr::AT_HLSLContainedType: {
2142 if (AL.getNumArgs() != 1 && !AL.hasParsedType()) {
2143 Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1;
2144 return false;
2145 }
2146
2147 TypeSourceInfo *TSI = nullptr;
2148 QualType QT = SemaRef.GetTypeFromParser(AL.getTypeArg(), &TSI);
2149 assert(TSI && "no type source info for attribute argument");
2150 if (SemaRef.RequireCompleteType(TSI->getTypeLoc().getBeginLoc(), QT,
2151 diag::err_incomplete_type))
2152 return false;
2153 A = HLSLContainedTypeAttr::Create(getASTContext(), TSI, ACI);
2154 break;
2155 }
2156
2157 default:
2158 llvm_unreachable("unhandled HLSL attribute");
2159 }
2160
2161 HLSLResourcesTypeAttrs.emplace_back(A);
2162 return true;
2163}
2164
2165// Combines all resource type attributes and creates HLSLAttributedResourceType.
2167 if (!HLSLResourcesTypeAttrs.size())
2168 return CurrentType;
2169
2170 QualType QT = CurrentType;
2173 HLSLResourcesTypeAttrs, QT, &LocInfo)) {
2174 const HLSLAttributedResourceType *RT =
2176
2177 // Temporarily store TypeLoc information for the new type.
2178 // It will be transferred to HLSLAttributesResourceTypeLoc
2179 // shortly after the type is created by TypeSpecLocFiller which
2180 // will call the TakeLocForHLSLAttribute method below.
2181 LocsForHLSLAttributedResources.insert(std::pair(RT, LocInfo));
2182 }
2183 HLSLResourcesTypeAttrs.clear();
2184 return QT;
2185}
2186
2187// Returns source location for the HLSLAttributedResourceType
2189SemaHLSL::TakeLocForHLSLAttribute(const HLSLAttributedResourceType *RT) {
2190 HLSLAttributedResourceLocInfo LocInfo = {};
2191 auto I = LocsForHLSLAttributedResources.find(RT);
2192 if (I != LocsForHLSLAttributedResources.end()) {
2193 LocInfo = I->second;
2194 LocsForHLSLAttributedResources.erase(I);
2195 return LocInfo;
2196 }
2197 LocInfo.Range = SourceRange();
2198 return LocInfo;
2199}
2200
2201// Walks though the global variable declaration, collects all resource binding
2202// requirements and adds them to Bindings
2203void SemaHLSL::collectResourceBindingsOnUserRecordDecl(const VarDecl *VD,
2204 const RecordType *RT) {
2205 const RecordDecl *RD = RT->getDecl()->getDefinitionOrSelf();
2206 for (FieldDecl *FD : RD->fields()) {
2207 const Type *Ty = FD->getType()->getUnqualifiedDesugaredType();
2208
2209 // Unwrap arrays
2210 // FIXME: Calculate array size while unwrapping
2211 assert(!Ty->isIncompleteArrayType() &&
2212 "incomplete arrays inside user defined types are not supported");
2213 while (Ty->isConstantArrayType()) {
2216 }
2217
2218 if (!Ty->isRecordType())
2219 continue;
2220
2221 if (const HLSLAttributedResourceType *AttrResType =
2222 HLSLAttributedResourceType::findHandleTypeOnResource(Ty)) {
2223 // Add a new DeclBindingInfo to Bindings if it does not already exist
2224 ResourceClass RC = AttrResType->getAttrs().ResourceClass;
2225 DeclBindingInfo *DBI = Bindings.getDeclBindingInfo(VD, RC);
2226 if (!DBI)
2227 Bindings.addDeclBindingInfo(VD, RC);
2228 } else if (const RecordType *RT = dyn_cast<RecordType>(Ty)) {
2229 // Recursively scan embedded struct or class; it would be nice to do this
2230 // without recursion, but tricky to correctly calculate the size of the
2231 // binding, which is something we are probably going to need to do later
2232 // on. Hopefully nesting of structs in structs too many levels is
2233 // unlikely.
2234 collectResourceBindingsOnUserRecordDecl(VD, RT);
2235 }
2236 }
2237}
2238
2239// Diagnose localized register binding errors for a single binding; does not
2240// diagnose resource binding on user record types, that will be done later
2241// in processResourceBindingOnDecl based on the information collected in
2242// collectResourceBindingsOnVarDecl.
2243// Returns false if the register binding is not valid.
2245 Decl *D, RegisterType RegType,
2246 bool SpecifiedSpace) {
2247 int RegTypeNum = static_cast<int>(RegType);
2248
2249 // check if the decl type is groupshared
2250 if (D->hasAttr<HLSLGroupSharedAddressSpaceAttr>()) {
2251 S.Diag(ArgLoc, diag::err_hlsl_binding_type_mismatch) << RegTypeNum;
2252 return false;
2253 }
2254
2255 // Cbuffers and Tbuffers are HLSLBufferDecl types
2256 if (HLSLBufferDecl *CBufferOrTBuffer = dyn_cast<HLSLBufferDecl>(D)) {
2257 ResourceClass RC = CBufferOrTBuffer->isCBuffer() ? ResourceClass::CBuffer
2258 : ResourceClass::SRV;
2259 if (RegType == getRegisterType(RC))
2260 return true;
2261
2262 S.Diag(D->getLocation(), diag::err_hlsl_binding_type_mismatch)
2263 << RegTypeNum;
2264 return false;
2265 }
2266
2267 // Samplers, UAVs, and SRVs are VarDecl types
2268 assert(isa<VarDecl>(D) && "D is expected to be VarDecl or HLSLBufferDecl");
2269 VarDecl *VD = cast<VarDecl>(D);
2270
2271 // Resource
2272 if (const HLSLAttributedResourceType *AttrResType =
2273 HLSLAttributedResourceType::findHandleTypeOnResource(
2274 VD->getType().getTypePtr())) {
2275 if (RegType == getRegisterType(AttrResType))
2276 return true;
2277
2278 S.Diag(D->getLocation(), diag::err_hlsl_binding_type_mismatch)
2279 << RegTypeNum;
2280 return false;
2281 }
2282
2283 const clang::Type *Ty = VD->getType().getTypePtr();
2284 while (Ty->isArrayType())
2286
2287 // Basic types
2288 if (Ty->isArithmeticType() || Ty->isVectorType()) {
2289 bool DeclaredInCOrTBuffer = isa<HLSLBufferDecl>(D->getDeclContext());
2290 if (SpecifiedSpace && !DeclaredInCOrTBuffer)
2291 S.Diag(ArgLoc, diag::err_hlsl_space_on_global_constant);
2292
2293 if (!DeclaredInCOrTBuffer && (Ty->isIntegralType(S.getASTContext()) ||
2294 Ty->isFloatingType() || Ty->isVectorType())) {
2295 // Register annotation on default constant buffer declaration ($Globals)
2296 if (RegType == RegisterType::CBuffer)
2297 S.Diag(ArgLoc, diag::warn_hlsl_deprecated_register_type_b);
2298 else if (RegType != RegisterType::C)
2299 S.Diag(ArgLoc, diag::err_hlsl_binding_type_mismatch) << RegTypeNum;
2300 else
2301 return true;
2302 } else {
2303 if (RegType == RegisterType::C)
2304 S.Diag(ArgLoc, diag::warn_hlsl_register_type_c_packoffset);
2305 else
2306 S.Diag(ArgLoc, diag::err_hlsl_binding_type_mismatch) << RegTypeNum;
2307 }
2308 return false;
2309 }
2310 if (Ty->isRecordType())
2311 // RecordTypes will be diagnosed in processResourceBindingOnDecl
2312 // that is called from ActOnVariableDeclarator
2313 return true;
2314
2315 // Anything else is an error
2316 S.Diag(ArgLoc, diag::err_hlsl_binding_type_mismatch) << RegTypeNum;
2317 return false;
2318}
2319
2321 RegisterType regType) {
2322 // make sure that there are no two register annotations
2323 // applied to the decl with the same register type
2324 bool RegisterTypesDetected[5] = {false};
2325 RegisterTypesDetected[static_cast<int>(regType)] = true;
2326
2327 for (auto it = TheDecl->attr_begin(); it != TheDecl->attr_end(); ++it) {
2328 if (HLSLResourceBindingAttr *attr =
2329 dyn_cast<HLSLResourceBindingAttr>(*it)) {
2330
2331 RegisterType otherRegType = attr->getRegisterType();
2332 if (RegisterTypesDetected[static_cast<int>(otherRegType)]) {
2333 int otherRegTypeNum = static_cast<int>(otherRegType);
2334 S.Diag(TheDecl->getLocation(),
2335 diag::err_hlsl_duplicate_register_annotation)
2336 << otherRegTypeNum;
2337 return false;
2338 }
2339 RegisterTypesDetected[static_cast<int>(otherRegType)] = true;
2340 }
2341 }
2342 return true;
2343}
2344
2346 Decl *D, RegisterType RegType,
2347 bool SpecifiedSpace) {
2348
2349 // exactly one of these two types should be set
2350 assert(((isa<VarDecl>(D) && !isa<HLSLBufferDecl>(D)) ||
2351 (!isa<VarDecl>(D) && isa<HLSLBufferDecl>(D))) &&
2352 "expecting VarDecl or HLSLBufferDecl");
2353
2354 // check if the declaration contains resource matching the register type
2355 if (!DiagnoseLocalRegisterBinding(S, ArgLoc, D, RegType, SpecifiedSpace))
2356 return false;
2357
2358 // next, if multiple register annotations exist, check that none conflict.
2359 return ValidateMultipleRegisterAnnotations(S, D, RegType);
2360}
2361
2363 if (VarDecl *VD = dyn_cast<VarDecl>(TheDecl)) {
2364 QualType Ty = VD->getType();
2365 if (const auto *IAT = dyn_cast<IncompleteArrayType>(Ty))
2366 Ty = IAT->getElementType();
2367 if (SemaRef.RequireCompleteType(TheDecl->getBeginLoc(), Ty,
2368 diag::err_incomplete_type))
2369 return;
2370 }
2371
2372 StringRef Slot = "";
2373 StringRef Space = "";
2374 SourceLocation SlotLoc, SpaceLoc;
2375
2376 if (!AL.isArgIdent(0)) {
2377 Diag(AL.getLoc(), diag::err_attribute_argument_type)
2378 << AL << AANT_ArgumentIdentifier;
2379 return;
2380 }
2381 IdentifierLoc *Loc = AL.getArgAsIdent(0);
2382
2383 if (AL.getNumArgs() == 2) {
2384 Slot = Loc->getIdentifierInfo()->getName();
2385 SlotLoc = Loc->getLoc();
2386 if (!AL.isArgIdent(1)) {
2387 Diag(AL.getLoc(), diag::err_attribute_argument_type)
2388 << AL << AANT_ArgumentIdentifier;
2389 return;
2390 }
2391 Loc = AL.getArgAsIdent(1);
2392 Space = Loc->getIdentifierInfo()->getName();
2393 SpaceLoc = Loc->getLoc();
2394 } else {
2395 StringRef Str = Loc->getIdentifierInfo()->getName();
2396 if (Str.starts_with("space")) {
2397 Space = Str;
2398 SpaceLoc = Loc->getLoc();
2399 } else {
2400 Slot = Str;
2401 SlotLoc = Loc->getLoc();
2402 Space = "space0";
2403 }
2404 }
2405
2406 RegisterType RegType = RegisterType::SRV;
2407 std::optional<unsigned> SlotNum;
2408 unsigned SpaceNum = 0;
2409
2410 // Validate slot
2411 if (!Slot.empty()) {
2412 if (!convertToRegisterType(Slot, &RegType)) {
2413 Diag(SlotLoc, diag::err_hlsl_binding_type_invalid) << Slot.substr(0, 1);
2414 return;
2415 }
2416 if (RegType == RegisterType::I) {
2417 Diag(SlotLoc, diag::warn_hlsl_deprecated_register_type_i);
2418 return;
2419 }
2420 StringRef SlotNumStr = Slot.substr(1);
2421 unsigned N;
2422 if (SlotNumStr.getAsInteger(10, N)) {
2423 Diag(SlotLoc, diag::err_hlsl_unsupported_register_number);
2424 return;
2425 }
2426 SlotNum = N;
2427 }
2428
2429 // Validate space
2430 if (!Space.starts_with("space")) {
2431 Diag(SpaceLoc, diag::err_hlsl_expected_space) << Space;
2432 return;
2433 }
2434 StringRef SpaceNumStr = Space.substr(5);
2435 if (SpaceNumStr.getAsInteger(10, SpaceNum)) {
2436 Diag(SpaceLoc, diag::err_hlsl_expected_space) << Space;
2437 return;
2438 }
2439
2440 // If we have slot, diagnose it is the right register type for the decl
2441 if (SlotNum.has_value())
2442 if (!DiagnoseHLSLRegisterAttribute(SemaRef, SlotLoc, TheDecl, RegType,
2443 !SpaceLoc.isInvalid()))
2444 return;
2445
2446 HLSLResourceBindingAttr *NewAttr =
2447 HLSLResourceBindingAttr::Create(getASTContext(), Slot, Space, AL);
2448 if (NewAttr) {
2449 NewAttr->setBinding(RegType, SlotNum, SpaceNum);
2450 TheDecl->addAttr(NewAttr);
2451 }
2452}
2453
2455 HLSLParamModifierAttr *NewAttr = mergeParamModifierAttr(
2456 D, AL,
2457 static_cast<HLSLParamModifierAttr::Spelling>(AL.getSemanticSpelling()));
2458 if (NewAttr)
2459 D->addAttr(NewAttr);
2460}
2461
2462namespace {
2463
2464/// This class implements HLSL availability diagnostics for default
2465/// and relaxed mode
2466///
2467/// The goal of this diagnostic is to emit an error or warning when an
2468/// unavailable API is found in code that is reachable from the shader
2469/// entry function or from an exported function (when compiling a shader
2470/// library).
2471///
2472/// This is done by traversing the AST of all shader entry point functions
2473/// and of all exported functions, and any functions that are referenced
2474/// from this AST. In other words, any functions that are reachable from
2475/// the entry points.
2476class DiagnoseHLSLAvailability : public DynamicRecursiveASTVisitor {
2477 Sema &SemaRef;
2478
2479 // Stack of functions to be scaned
2481
2482 // Tracks which environments functions have been scanned in.
2483 //
2484 // Maps FunctionDecl to an unsigned number that represents the set of shader
2485 // environments the function has been scanned for.
2486 // The llvm::Triple::EnvironmentType enum values for shader stages guaranteed
2487 // to be numbered from llvm::Triple::Pixel to llvm::Triple::Amplification
2488 // (verified by static_asserts in Triple.cpp), we can use it to index
2489 // individual bits in the set, as long as we shift the values to start with 0
2490 // by subtracting the value of llvm::Triple::Pixel first.
2491 //
2492 // The N'th bit in the set will be set if the function has been scanned
2493 // in shader environment whose llvm::Triple::EnvironmentType integer value
2494 // equals (llvm::Triple::Pixel + N).
2495 //
2496 // For example, if a function has been scanned in compute and pixel stage
2497 // environment, the value will be 0x21 (100001 binary) because:
2498 //
2499 // (int)(llvm::Triple::Pixel - llvm::Triple::Pixel) == 0
2500 // (int)(llvm::Triple::Compute - llvm::Triple::Pixel) == 5
2501 //
2502 // A FunctionDecl is mapped to 0 (or not included in the map) if it has not
2503 // been scanned in any environment.
2504 llvm::DenseMap<const FunctionDecl *, unsigned> ScannedDecls;
2505
2506 // Do not access these directly, use the get/set methods below to make
2507 // sure the values are in sync
2508 llvm::Triple::EnvironmentType CurrentShaderEnvironment;
2509 unsigned CurrentShaderStageBit;
2510
2511 // True if scanning a function that was already scanned in a different
2512 // shader stage context, and therefore we should not report issues that
2513 // depend only on shader model version because they would be duplicate.
2514 bool ReportOnlyShaderStageIssues;
2515
2516 // Helper methods for dealing with current stage context / environment
2517 void SetShaderStageContext(llvm::Triple::EnvironmentType ShaderType) {
2518 static_assert(sizeof(unsigned) >= 4);
2519 assert(HLSLShaderAttr::isValidShaderType(ShaderType));
2520 assert((unsigned)(ShaderType - llvm::Triple::Pixel) < 31 &&
2521 "ShaderType is too big for this bitmap"); // 31 is reserved for
2522 // "unknown"
2523
2524 unsigned bitmapIndex = ShaderType - llvm::Triple::Pixel;
2525 CurrentShaderEnvironment = ShaderType;
2526 CurrentShaderStageBit = (1 << bitmapIndex);
2527 }
2528
2529 void SetUnknownShaderStageContext() {
2530 CurrentShaderEnvironment = llvm::Triple::UnknownEnvironment;
2531 CurrentShaderStageBit = (1 << 31);
2532 }
2533
2534 llvm::Triple::EnvironmentType GetCurrentShaderEnvironment() const {
2535 return CurrentShaderEnvironment;
2536 }
2537
2538 bool InUnknownShaderStageContext() const {
2539 return CurrentShaderEnvironment == llvm::Triple::UnknownEnvironment;
2540 }
2541
2542 // Helper methods for dealing with shader stage bitmap
2543 void AddToScannedFunctions(const FunctionDecl *FD) {
2544 unsigned &ScannedStages = ScannedDecls[FD];
2545 ScannedStages |= CurrentShaderStageBit;
2546 }
2547
2548 unsigned GetScannedStages(const FunctionDecl *FD) { return ScannedDecls[FD]; }
2549
2550 bool WasAlreadyScannedInCurrentStage(const FunctionDecl *FD) {
2551 return WasAlreadyScannedInCurrentStage(GetScannedStages(FD));
2552 }
2553
2554 bool WasAlreadyScannedInCurrentStage(unsigned ScannerStages) {
2555 return ScannerStages & CurrentShaderStageBit;
2556 }
2557
2558 static bool NeverBeenScanned(unsigned ScannedStages) {
2559 return ScannedStages == 0;
2560 }
2561
2562 // Scanning methods
2563 void HandleFunctionOrMethodRef(FunctionDecl *FD, Expr *RefExpr);
2564 void CheckDeclAvailability(NamedDecl *D, const AvailabilityAttr *AA,
2565 SourceRange Range);
2566 const AvailabilityAttr *FindAvailabilityAttr(const Decl *D);
2567 bool HasMatchingEnvironmentOrNone(const AvailabilityAttr *AA);
2568
2569public:
2570 DiagnoseHLSLAvailability(Sema &SemaRef)
2571 : SemaRef(SemaRef),
2572 CurrentShaderEnvironment(llvm::Triple::UnknownEnvironment),
2573 CurrentShaderStageBit(0), ReportOnlyShaderStageIssues(false) {}
2574
2575 // AST traversal methods
2576 void RunOnTranslationUnit(const TranslationUnitDecl *TU);
2577 void RunOnFunction(const FunctionDecl *FD);
2578
2579 bool VisitDeclRefExpr(DeclRefExpr *DRE) override {
2580 FunctionDecl *FD = llvm::dyn_cast<FunctionDecl>(DRE->getDecl());
2581 if (FD)
2582 HandleFunctionOrMethodRef(FD, DRE);
2583 return true;
2584 }
2585
2586 bool VisitMemberExpr(MemberExpr *ME) override {
2587 FunctionDecl *FD = llvm::dyn_cast<FunctionDecl>(ME->getMemberDecl());
2588 if (FD)
2589 HandleFunctionOrMethodRef(FD, ME);
2590 return true;
2591 }
2592};
2593
2594void DiagnoseHLSLAvailability::HandleFunctionOrMethodRef(FunctionDecl *FD,
2595 Expr *RefExpr) {
2596 assert((isa<DeclRefExpr>(RefExpr) || isa<MemberExpr>(RefExpr)) &&
2597 "expected DeclRefExpr or MemberExpr");
2598
2599 // has a definition -> add to stack to be scanned
2600 const FunctionDecl *FDWithBody = nullptr;
2601 if (FD->hasBody(FDWithBody)) {
2602 if (!WasAlreadyScannedInCurrentStage(FDWithBody))
2603 DeclsToScan.push_back(FDWithBody);
2604 return;
2605 }
2606
2607 // no body -> diagnose availability
2608 const AvailabilityAttr *AA = FindAvailabilityAttr(FD);
2609 if (AA)
2610 CheckDeclAvailability(
2611 FD, AA, SourceRange(RefExpr->getBeginLoc(), RefExpr->getEndLoc()));
2612}
2613
2614void DiagnoseHLSLAvailability::RunOnTranslationUnit(
2615 const TranslationUnitDecl *TU) {
2616
2617 // Iterate over all shader entry functions and library exports, and for those
2618 // that have a body (definiton), run diag scan on each, setting appropriate
2619 // shader environment context based on whether it is a shader entry function
2620 // or an exported function. Exported functions can be in namespaces and in
2621 // export declarations so we need to scan those declaration contexts as well.
2623 DeclContextsToScan.push_back(TU);
2624
2625 while (!DeclContextsToScan.empty()) {
2626 const DeclContext *DC = DeclContextsToScan.pop_back_val();
2627 for (auto &D : DC->decls()) {
2628 // do not scan implicit declaration generated by the implementation
2629 if (D->isImplicit())
2630 continue;
2631
2632 // for namespace or export declaration add the context to the list to be
2633 // scanned later
2634 if (llvm::dyn_cast<NamespaceDecl>(D) || llvm::dyn_cast<ExportDecl>(D)) {
2635 DeclContextsToScan.push_back(llvm::dyn_cast<DeclContext>(D));
2636 continue;
2637 }
2638
2639 // skip over other decls or function decls without body
2640 const FunctionDecl *FD = llvm::dyn_cast<FunctionDecl>(D);
2641 if (!FD || !FD->isThisDeclarationADefinition())
2642 continue;
2643
2644 // shader entry point
2645 if (HLSLShaderAttr *ShaderAttr = FD->getAttr<HLSLShaderAttr>()) {
2646 SetShaderStageContext(ShaderAttr->getType());
2647 RunOnFunction(FD);
2648 continue;
2649 }
2650 // exported library function
2651 // FIXME: replace this loop with external linkage check once issue #92071
2652 // is resolved
2653 bool isExport = FD->isInExportDeclContext();
2654 if (!isExport) {
2655 for (const auto *Redecl : FD->redecls()) {
2656 if (Redecl->isInExportDeclContext()) {
2657 isExport = true;
2658 break;
2659 }
2660 }
2661 }
2662 if (isExport) {
2663 SetUnknownShaderStageContext();
2664 RunOnFunction(FD);
2665 continue;
2666 }
2667 }
2668 }
2669}
2670
2671void DiagnoseHLSLAvailability::RunOnFunction(const FunctionDecl *FD) {
2672 assert(DeclsToScan.empty() && "DeclsToScan should be empty");
2673 DeclsToScan.push_back(FD);
2674
2675 while (!DeclsToScan.empty()) {
2676 // Take one decl from the stack and check it by traversing its AST.
2677 // For any CallExpr found during the traversal add it's callee to the top of
2678 // the stack to be processed next. Functions already processed are stored in
2679 // ScannedDecls.
2680 const FunctionDecl *FD = DeclsToScan.pop_back_val();
2681
2682 // Decl was already scanned
2683 const unsigned ScannedStages = GetScannedStages(FD);
2684 if (WasAlreadyScannedInCurrentStage(ScannedStages))
2685 continue;
2686
2687 ReportOnlyShaderStageIssues = !NeverBeenScanned(ScannedStages);
2688
2689 AddToScannedFunctions(FD);
2690 TraverseStmt(FD->getBody());
2691 }
2692}
2693
2694bool DiagnoseHLSLAvailability::HasMatchingEnvironmentOrNone(
2695 const AvailabilityAttr *AA) {
2696 IdentifierInfo *IIEnvironment = AA->getEnvironment();
2697 if (!IIEnvironment)
2698 return true;
2699
2700 llvm::Triple::EnvironmentType CurrentEnv = GetCurrentShaderEnvironment();
2701 if (CurrentEnv == llvm::Triple::UnknownEnvironment)
2702 return false;
2703
2704 llvm::Triple::EnvironmentType AttrEnv =
2705 AvailabilityAttr::getEnvironmentType(IIEnvironment->getName());
2706
2707 return CurrentEnv == AttrEnv;
2708}
2709
2710const AvailabilityAttr *
2711DiagnoseHLSLAvailability::FindAvailabilityAttr(const Decl *D) {
2712 AvailabilityAttr const *PartialMatch = nullptr;
2713 // Check each AvailabilityAttr to find the one for this platform.
2714 // For multiple attributes with the same platform try to find one for this
2715 // environment.
2716 for (const auto *A : D->attrs()) {
2717 if (const auto *Avail = dyn_cast<AvailabilityAttr>(A)) {
2718 StringRef AttrPlatform = Avail->getPlatform()->getName();
2719 StringRef TargetPlatform =
2721
2722 // Match the platform name.
2723 if (AttrPlatform == TargetPlatform) {
2724 // Find the best matching attribute for this environment
2725 if (HasMatchingEnvironmentOrNone(Avail))
2726 return Avail;
2727 PartialMatch = Avail;
2728 }
2729 }
2730 }
2731 return PartialMatch;
2732}
2733
2734// Check availability against target shader model version and current shader
2735// stage and emit diagnostic
2736void DiagnoseHLSLAvailability::CheckDeclAvailability(NamedDecl *D,
2737 const AvailabilityAttr *AA,
2738 SourceRange Range) {
2739
2740 IdentifierInfo *IIEnv = AA->getEnvironment();
2741
2742 if (!IIEnv) {
2743 // The availability attribute does not have environment -> it depends only
2744 // on shader model version and not on specific the shader stage.
2745
2746 // Skip emitting the diagnostics if the diagnostic mode is set to
2747 // strict (-fhlsl-strict-availability) because all relevant diagnostics
2748 // were already emitted in the DiagnoseUnguardedAvailability scan
2749 // (SemaAvailability.cpp).
2750 if (SemaRef.getLangOpts().HLSLStrictAvailability)
2751 return;
2752
2753 // Do not report shader-stage-independent issues if scanning a function
2754 // that was already scanned in a different shader stage context (they would
2755 // be duplicate)
2756 if (ReportOnlyShaderStageIssues)
2757 return;
2758
2759 } else {
2760 // The availability attribute has environment -> we need to know
2761 // the current stage context to property diagnose it.
2762 if (InUnknownShaderStageContext())
2763 return;
2764 }
2765
2766 // Check introduced version and if environment matches
2767 bool EnvironmentMatches = HasMatchingEnvironmentOrNone(AA);
2768 VersionTuple Introduced = AA->getIntroduced();
2769 VersionTuple TargetVersion =
2771
2772 if (TargetVersion >= Introduced && EnvironmentMatches)
2773 return;
2774
2775 // Emit diagnostic message
2776 const TargetInfo &TI = SemaRef.getASTContext().getTargetInfo();
2777 llvm::StringRef PlatformName(
2778 AvailabilityAttr::getPrettyPlatformName(TI.getPlatformName()));
2779
2780 llvm::StringRef CurrentEnvStr =
2781 llvm::Triple::getEnvironmentTypeName(GetCurrentShaderEnvironment());
2782
2783 llvm::StringRef AttrEnvStr =
2784 AA->getEnvironment() ? AA->getEnvironment()->getName() : "";
2785 bool UseEnvironment = !AttrEnvStr.empty();
2786
2787 if (EnvironmentMatches) {
2788 SemaRef.Diag(Range.getBegin(), diag::warn_hlsl_availability)
2789 << Range << D << PlatformName << Introduced.getAsString()
2790 << UseEnvironment << CurrentEnvStr;
2791 } else {
2792 SemaRef.Diag(Range.getBegin(), diag::warn_hlsl_availability_unavailable)
2793 << Range << D;
2794 }
2795
2796 SemaRef.Diag(D->getLocation(), diag::note_partial_availability_specified_here)
2797 << D << PlatformName << Introduced.getAsString()
2798 << SemaRef.Context.getTargetInfo().getPlatformMinVersion().getAsString()
2799 << UseEnvironment << AttrEnvStr << CurrentEnvStr;
2800}
2801
2802} // namespace
2803
2805 // process default CBuffer - create buffer layout struct and invoke codegenCGH
2806 if (!DefaultCBufferDecls.empty()) {
2808 SemaRef.getASTContext(), SemaRef.getCurLexicalContext(),
2809 DefaultCBufferDecls);
2810 addImplicitBindingAttrToDecl(SemaRef, DefaultCBuffer, RegisterType::CBuffer,
2811 getNextImplicitBindingOrderID());
2812 SemaRef.getCurLexicalContext()->addDecl(DefaultCBuffer);
2814
2815 // Set HasValidPackoffset if any of the decls has a register(c#) annotation;
2816 for (const Decl *VD : DefaultCBufferDecls) {
2817 const HLSLResourceBindingAttr *RBA =
2818 VD->getAttr<HLSLResourceBindingAttr>();
2819 if (RBA && RBA->hasRegisterSlot() &&
2820 RBA->getRegisterType() == HLSLResourceBindingAttr::RegisterType::C) {
2821 DefaultCBuffer->setHasValidPackoffset(true);
2822 break;
2823 }
2824 }
2825
2826 DeclGroupRef DG(DefaultCBuffer);
2827 SemaRef.Consumer.HandleTopLevelDecl(DG);
2828 }
2829 diagnoseAvailabilityViolations(TU);
2830}
2831
2832void SemaHLSL::diagnoseAvailabilityViolations(TranslationUnitDecl *TU) {
2833 // Skip running the diagnostics scan if the diagnostic mode is
2834 // strict (-fhlsl-strict-availability) and the target shader stage is known
2835 // because all relevant diagnostics were already emitted in the
2836 // DiagnoseUnguardedAvailability scan (SemaAvailability.cpp).
2838 if (SemaRef.getLangOpts().HLSLStrictAvailability &&
2839 TI.getTriple().getEnvironment() != llvm::Triple::EnvironmentType::Library)
2840 return;
2841
2842 DiagnoseHLSLAvailability(SemaRef).RunOnTranslationUnit(TU);
2843}
2844
2845static bool CheckAllArgsHaveSameType(Sema *S, CallExpr *TheCall) {
2846 assert(TheCall->getNumArgs() > 1);
2847 QualType ArgTy0 = TheCall->getArg(0)->getType();
2848
2849 for (unsigned I = 1, N = TheCall->getNumArgs(); I < N; ++I) {
2851 ArgTy0, TheCall->getArg(I)->getType())) {
2852 S->Diag(TheCall->getBeginLoc(), diag::err_vec_builtin_incompatible_vector)
2853 << TheCall->getDirectCallee() << /*useAllTerminology*/ true
2854 << SourceRange(TheCall->getArg(0)->getBeginLoc(),
2855 TheCall->getArg(N - 1)->getEndLoc());
2856 return true;
2857 }
2858 }
2859 return false;
2860}
2861
2863 QualType ArgType = Arg->getType();
2865 S->Diag(Arg->getBeginLoc(), diag::err_typecheck_convert_incompatible)
2866 << ArgType << ExpectedType << 1 << 0 << 0;
2867 return true;
2868 }
2869 return false;
2870}
2871
2873 Sema *S, CallExpr *TheCall,
2874 llvm::function_ref<bool(Sema *S, SourceLocation Loc, int ArgOrdinal,
2875 clang::QualType PassedType)>
2876 Check) {
2877 for (unsigned I = 0; I < TheCall->getNumArgs(); ++I) {
2878 Expr *Arg = TheCall->getArg(I);
2879 if (Check(S, Arg->getBeginLoc(), I + 1, Arg->getType()))
2880 return true;
2881 }
2882 return false;
2883}
2884
2886 int ArgOrdinal,
2887 clang::QualType PassedType) {
2888 clang::QualType BaseType =
2889 PassedType->isVectorType()
2890 ? PassedType->castAs<clang::VectorType>()->getElementType()
2891 : PassedType;
2892 if (!BaseType->isHalfType() && !BaseType->isFloat32Type())
2893 return S->Diag(Loc, diag::err_builtin_invalid_arg_type)
2894 << ArgOrdinal << /* scalar or vector of */ 5 << /* no int */ 0
2895 << /* half or float */ 2 << PassedType;
2896 return false;
2897}
2898
2899static bool CheckModifiableLValue(Sema *S, CallExpr *TheCall,
2900 unsigned ArgIndex) {
2901 auto *Arg = TheCall->getArg(ArgIndex);
2902 SourceLocation OrigLoc = Arg->getExprLoc();
2903 if (Arg->IgnoreCasts()->isModifiableLvalue(S->Context, &OrigLoc) ==
2905 return false;
2906 S->Diag(OrigLoc, diag::error_hlsl_inout_lvalue) << Arg << 0;
2907 return true;
2908}
2909
2910static bool CheckNoDoubleVectors(Sema *S, SourceLocation Loc, int ArgOrdinal,
2911 clang::QualType PassedType) {
2912 const auto *VecTy = PassedType->getAs<VectorType>();
2913 if (!VecTy)
2914 return false;
2915
2916 if (VecTy->getElementType()->isDoubleType())
2917 return S->Diag(Loc, diag::err_builtin_invalid_arg_type)
2918 << ArgOrdinal << /* scalar */ 1 << /* no int */ 0 << /* fp */ 1
2919 << PassedType;
2920 return false;
2921}
2922
2924 int ArgOrdinal,
2925 clang::QualType PassedType) {
2926 if (!PassedType->hasIntegerRepresentation() &&
2927 !PassedType->hasFloatingRepresentation())
2928 return S->Diag(Loc, diag::err_builtin_invalid_arg_type)
2929 << ArgOrdinal << /* scalar or vector of */ 5 << /* integer */ 1
2930 << /* fp */ 1 << PassedType;
2931 return false;
2932}
2933
2935 int ArgOrdinal,
2936 clang::QualType PassedType) {
2937 if (auto *VecTy = PassedType->getAs<VectorType>())
2938 if (VecTy->getElementType()->isUnsignedIntegerType())
2939 return false;
2940
2941 return S->Diag(Loc, diag::err_builtin_invalid_arg_type)
2942 << ArgOrdinal << /* vector of */ 4 << /* uint */ 3 << /* no fp */ 0
2943 << PassedType;
2944}
2945
2946// checks for unsigned ints of all sizes
2948 int ArgOrdinal,
2949 clang::QualType PassedType) {
2950 if (!PassedType->hasUnsignedIntegerRepresentation())
2951 return S->Diag(Loc, diag::err_builtin_invalid_arg_type)
2952 << ArgOrdinal << /* scalar or vector of */ 5 << /* unsigned int */ 3
2953 << /* no fp */ 0 << PassedType;
2954 return false;
2955}
2956
2957static bool CheckExpectedBitWidth(Sema *S, CallExpr *TheCall,
2958 unsigned ArgOrdinal, unsigned Width) {
2959 QualType ArgTy = TheCall->getArg(0)->getType();
2960 if (auto *VTy = ArgTy->getAs<VectorType>())
2961 ArgTy = VTy->getElementType();
2962 // ensure arg type has expected bit width
2963 uint64_t ElementBitCount =
2965 if (ElementBitCount != Width) {
2966 S->Diag(TheCall->getArg(0)->getBeginLoc(),
2967 diag::err_integer_incorrect_bit_count)
2968 << Width << ElementBitCount;
2969 return true;
2970 }
2971 return false;
2972}
2973
2975 QualType ReturnType) {
2976 auto *VecTyA = TheCall->getArg(0)->getType()->getAs<VectorType>();
2977 if (VecTyA)
2978 ReturnType =
2979 S->Context.getExtVectorType(ReturnType, VecTyA->getNumElements());
2980
2981 TheCall->setType(ReturnType);
2982}
2983
2984static bool CheckScalarOrVector(Sema *S, CallExpr *TheCall, QualType Scalar,
2985 unsigned ArgIndex) {
2986 assert(TheCall->getNumArgs() >= ArgIndex);
2987 QualType ArgType = TheCall->getArg(ArgIndex)->getType();
2988 auto *VTy = ArgType->getAs<VectorType>();
2989 // not the scalar or vector<scalar>
2990 if (!(S->Context.hasSameUnqualifiedType(ArgType, Scalar) ||
2991 (VTy &&
2992 S->Context.hasSameUnqualifiedType(VTy->getElementType(), Scalar)))) {
2993 S->Diag(TheCall->getArg(0)->getBeginLoc(),
2994 diag::err_typecheck_expect_scalar_or_vector)
2995 << ArgType << Scalar;
2996 return true;
2997 }
2998 return false;
2999}
3000
3001static bool CheckAnyScalarOrVector(Sema *S, CallExpr *TheCall,
3002 unsigned ArgIndex) {
3003 assert(TheCall->getNumArgs() >= ArgIndex);
3004 QualType ArgType = TheCall->getArg(ArgIndex)->getType();
3005 auto *VTy = ArgType->getAs<VectorType>();
3006 // not the scalar or vector<scalar>
3007 if (!(ArgType->isScalarType() ||
3008 (VTy && VTy->getElementType()->isScalarType()))) {
3009 S->Diag(TheCall->getArg(0)->getBeginLoc(),
3010 diag::err_typecheck_expect_any_scalar_or_vector)
3011 << ArgType << 1;
3012 return true;
3013 }
3014 return false;
3015}
3016
3017static bool CheckWaveActive(Sema *S, CallExpr *TheCall) {
3018 QualType BoolType = S->getASTContext().BoolTy;
3019 assert(TheCall->getNumArgs() >= 1);
3020 QualType ArgType = TheCall->getArg(0)->getType();
3021 auto *VTy = ArgType->getAs<VectorType>();
3022 // is the bool or vector<bool>
3023 if (S->Context.hasSameUnqualifiedType(ArgType, BoolType) ||
3024 (VTy &&
3025 S->Context.hasSameUnqualifiedType(VTy->getElementType(), BoolType))) {
3026 S->Diag(TheCall->getArg(0)->getBeginLoc(),
3027 diag::err_typecheck_expect_any_scalar_or_vector)
3028 << ArgType << 0;
3029 return true;
3030 }
3031 return false;
3032}
3033
3034static bool CheckBoolSelect(Sema *S, CallExpr *TheCall) {
3035 assert(TheCall->getNumArgs() == 3);
3036 Expr *Arg1 = TheCall->getArg(1);
3037 Expr *Arg2 = TheCall->getArg(2);
3038 if (!S->Context.hasSameUnqualifiedType(Arg1->getType(), Arg2->getType())) {
3039 S->Diag(TheCall->getBeginLoc(),
3040 diag::err_typecheck_call_different_arg_types)
3041 << Arg1->getType() << Arg2->getType() << Arg1->getSourceRange()
3042 << Arg2->getSourceRange();
3043 return true;
3044 }
3045
3046 TheCall->setType(Arg1->getType());
3047 return false;
3048}
3049
3050static bool CheckVectorSelect(Sema *S, CallExpr *TheCall) {
3051 assert(TheCall->getNumArgs() == 3);
3052 Expr *Arg1 = TheCall->getArg(1);
3053 QualType Arg1Ty = Arg1->getType();
3054 Expr *Arg2 = TheCall->getArg(2);
3055 QualType Arg2Ty = Arg2->getType();
3056
3057 QualType Arg1ScalarTy = Arg1Ty;
3058 if (auto VTy = Arg1ScalarTy->getAs<VectorType>())
3059 Arg1ScalarTy = VTy->getElementType();
3060
3061 QualType Arg2ScalarTy = Arg2Ty;
3062 if (auto VTy = Arg2ScalarTy->getAs<VectorType>())
3063 Arg2ScalarTy = VTy->getElementType();
3064
3065 if (!S->Context.hasSameUnqualifiedType(Arg1ScalarTy, Arg2ScalarTy))
3066 S->Diag(Arg1->getBeginLoc(), diag::err_hlsl_builtin_scalar_vector_mismatch)
3067 << /* second and third */ 1 << TheCall->getCallee() << Arg1Ty << Arg2Ty;
3068
3069 QualType Arg0Ty = TheCall->getArg(0)->getType();
3070 unsigned Arg0Length = Arg0Ty->getAs<VectorType>()->getNumElements();
3071 unsigned Arg1Length = Arg1Ty->isVectorType()
3072 ? Arg1Ty->getAs<VectorType>()->getNumElements()
3073 : 0;
3074 unsigned Arg2Length = Arg2Ty->isVectorType()
3075 ? Arg2Ty->getAs<VectorType>()->getNumElements()
3076 : 0;
3077 if (Arg1Length > 0 && Arg0Length != Arg1Length) {
3078 S->Diag(TheCall->getBeginLoc(),
3079 diag::err_typecheck_vector_lengths_not_equal)
3080 << Arg0Ty << Arg1Ty << TheCall->getArg(0)->getSourceRange()
3081 << Arg1->getSourceRange();
3082 return true;
3083 }
3084
3085 if (Arg2Length > 0 && Arg0Length != Arg2Length) {
3086 S->Diag(TheCall->getBeginLoc(),
3087 diag::err_typecheck_vector_lengths_not_equal)
3088 << Arg0Ty << Arg2Ty << TheCall->getArg(0)->getSourceRange()
3089 << Arg2->getSourceRange();
3090 return true;
3091 }
3092
3093 TheCall->setType(
3094 S->getASTContext().getExtVectorType(Arg1ScalarTy, Arg0Length));
3095 return false;
3096}
3097
3099 Sema *S, CallExpr *TheCall, unsigned ArgIndex,
3100 llvm::function_ref<bool(const HLSLAttributedResourceType *ResType)> Check =
3101 nullptr) {
3102 assert(TheCall->getNumArgs() >= ArgIndex);
3103 QualType ArgType = TheCall->getArg(ArgIndex)->getType();
3104 const HLSLAttributedResourceType *ResTy =
3105 ArgType.getTypePtr()->getAs<HLSLAttributedResourceType>();
3106 if (!ResTy) {
3107 S->Diag(TheCall->getArg(ArgIndex)->getBeginLoc(),
3108 diag::err_typecheck_expect_hlsl_resource)
3109 << ArgType;
3110 return true;
3111 }
3112 if (Check && Check(ResTy)) {
3113 S->Diag(TheCall->getArg(ArgIndex)->getExprLoc(),
3114 diag::err_invalid_hlsl_resource_type)
3115 << ArgType;
3116 return true;
3117 }
3118 return false;
3119}
3120
3121// Note: returning true in this case results in CheckBuiltinFunctionCall
3122// returning an ExprError
3123bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
3124 switch (BuiltinID) {
3125 case Builtin::BI__builtin_hlsl_adduint64: {
3126 if (SemaRef.checkArgCount(TheCall, 2))
3127 return true;
3128
3129 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
3131 return true;
3132
3133 // ensure arg integers are 32-bits
3134 if (CheckExpectedBitWidth(&SemaRef, TheCall, 0, 32))
3135 return true;
3136
3137 // ensure both args are vectors of total bit size of a multiple of 64
3138 auto *VTy = TheCall->getArg(0)->getType()->getAs<VectorType>();
3139 int NumElementsArg = VTy->getNumElements();
3140 if (NumElementsArg != 2 && NumElementsArg != 4) {
3141 SemaRef.Diag(TheCall->getBeginLoc(), diag::err_vector_incorrect_bit_count)
3142 << 1 /*a multiple of*/ << 64 << NumElementsArg * 32;
3143 return true;
3144 }
3145
3146 // ensure first arg and second arg have the same type
3147 if (CheckAllArgsHaveSameType(&SemaRef, TheCall))
3148 return true;
3149
3150 ExprResult A = TheCall->getArg(0);
3151 QualType ArgTyA = A.get()->getType();
3152 // return type is the same as the input type
3153 TheCall->setType(ArgTyA);
3154 break;
3155 }
3156 case Builtin::BI__builtin_hlsl_resource_getpointer: {
3157 if (SemaRef.checkArgCount(TheCall, 2) ||
3158 CheckResourceHandle(&SemaRef, TheCall, 0) ||
3159 CheckArgTypeMatches(&SemaRef, TheCall->getArg(1),
3160 SemaRef.getASTContext().UnsignedIntTy))
3161 return true;
3162
3163 auto *ResourceTy =
3164 TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
3165 QualType ContainedTy = ResourceTy->getContainedType();
3166 auto ReturnType =
3167 SemaRef.Context.getAddrSpaceQualType(ContainedTy, LangAS::hlsl_device);
3168 ReturnType = SemaRef.Context.getPointerType(ReturnType);
3169 TheCall->setType(ReturnType);
3170 TheCall->setValueKind(VK_LValue);
3171
3172 break;
3173 }
3174 case Builtin::BI__builtin_hlsl_resource_load_with_status: {
3175 if (SemaRef.checkArgCount(TheCall, 3) ||
3176 CheckResourceHandle(&SemaRef, TheCall, 0) ||
3177 CheckArgTypeMatches(&SemaRef, TheCall->getArg(1),
3178 SemaRef.getASTContext().UnsignedIntTy) ||
3179 CheckArgTypeMatches(&SemaRef, TheCall->getArg(2),
3180 SemaRef.getASTContext().UnsignedIntTy) ||
3181 CheckModifiableLValue(&SemaRef, TheCall, 2))
3182 return true;
3183
3184 auto *ResourceTy =
3185 TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
3186 QualType ReturnType = ResourceTy->getContainedType();
3187 TheCall->setType(ReturnType);
3188
3189 break;
3190 }
3191
3192 case Builtin::BI__builtin_hlsl_resource_uninitializedhandle: {
3193 assert(TheCall->getNumArgs() == 1 && "expected 1 arg");
3194 // Update return type to be the attributed resource type from arg0.
3195 QualType ResourceTy = TheCall->getArg(0)->getType();
3196 TheCall->setType(ResourceTy);
3197 break;
3198 }
3199 case Builtin::BI__builtin_hlsl_resource_handlefrombinding: {
3200 assert(TheCall->getNumArgs() == 6 && "expected 6 args");
3201 // Update return type to be the attributed resource type from arg0.
3202 QualType ResourceTy = TheCall->getArg(0)->getType();
3203 TheCall->setType(ResourceTy);
3204 break;
3205 }
3206 case Builtin::BI__builtin_hlsl_resource_handlefromimplicitbinding: {
3207 assert(TheCall->getNumArgs() == 6 && "expected 6 args");
3208 // Update return type to be the attributed resource type from arg0.
3209 QualType ResourceTy = TheCall->getArg(0)->getType();
3210 TheCall->setType(ResourceTy);
3211 break;
3212 }
3213 case Builtin::BI__builtin_hlsl_resource_counterhandlefromimplicitbinding: {
3214 assert(TheCall->getNumArgs() == 3 && "expected 3 args");
3215 ASTContext &AST = SemaRef.getASTContext();
3216 QualType MainHandleTy = TheCall->getArg(0)->getType();
3217 auto *MainResType = MainHandleTy->getAs<HLSLAttributedResourceType>();
3218 auto MainAttrs = MainResType->getAttrs();
3219 assert(!MainAttrs.IsCounter && "cannot create a counter from a counter");
3220 MainAttrs.IsCounter = true;
3221 QualType CounterHandleTy = AST.getHLSLAttributedResourceType(
3222 MainResType->getWrappedType(), MainResType->getContainedType(),
3223 MainAttrs);
3224 // Update return type to be the attributed resource type from arg0
3225 // with added IsCounter flag.
3226 TheCall->setType(CounterHandleTy);
3227 break;
3228 }
3229 case Builtin::BI__builtin_hlsl_and:
3230 case Builtin::BI__builtin_hlsl_or: {
3231 if (SemaRef.checkArgCount(TheCall, 2))
3232 return true;
3233 if (CheckScalarOrVector(&SemaRef, TheCall, getASTContext().BoolTy, 0))
3234 return true;
3235 if (CheckAllArgsHaveSameType(&SemaRef, TheCall))
3236 return true;
3237
3238 ExprResult A = TheCall->getArg(0);
3239 QualType ArgTyA = A.get()->getType();
3240 // return type is the same as the input type
3241 TheCall->setType(ArgTyA);
3242 break;
3243 }
3244 case Builtin::BI__builtin_hlsl_all:
3245 case Builtin::BI__builtin_hlsl_any: {
3246 if (SemaRef.checkArgCount(TheCall, 1))
3247 return true;
3248 if (CheckAnyScalarOrVector(&SemaRef, TheCall, 0))
3249 return true;
3250 break;
3251 }
3252 case Builtin::BI__builtin_hlsl_asdouble: {
3253 if (SemaRef.checkArgCount(TheCall, 2))
3254 return true;
3256 &SemaRef, TheCall,
3257 /*only check for uint*/ SemaRef.Context.UnsignedIntTy,
3258 /* arg index */ 0))
3259 return true;
3261 &SemaRef, TheCall,
3262 /*only check for uint*/ SemaRef.Context.UnsignedIntTy,
3263 /* arg index */ 1))
3264 return true;
3265 if (CheckAllArgsHaveSameType(&SemaRef, TheCall))
3266 return true;
3267
3268 SetElementTypeAsReturnType(&SemaRef, TheCall, getASTContext().DoubleTy);
3269 break;
3270 }
3271 case Builtin::BI__builtin_hlsl_elementwise_clamp: {
3272 if (SemaRef.BuiltinElementwiseTernaryMath(
3273 TheCall, /*ArgTyRestr=*/
3275 return true;
3276 break;
3277 }
3278 case Builtin::BI__builtin_hlsl_dot: {
3279 // arg count is checked by BuiltinVectorToScalarMath
3280 if (SemaRef.BuiltinVectorToScalarMath(TheCall))
3281 return true;
3283 return true;
3284 break;
3285 }
3286 case Builtin::BI__builtin_hlsl_elementwise_firstbithigh:
3287 case Builtin::BI__builtin_hlsl_elementwise_firstbitlow: {
3288 if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall))
3289 return true;
3290
3291 const Expr *Arg = TheCall->getArg(0);
3292 QualType ArgTy = Arg->getType();
3293 QualType EltTy = ArgTy;
3294
3295 QualType ResTy = SemaRef.Context.UnsignedIntTy;
3296
3297 if (auto *VecTy = EltTy->getAs<VectorType>()) {
3298 EltTy = VecTy->getElementType();
3299 ResTy = SemaRef.Context.getExtVectorType(ResTy, VecTy->getNumElements());
3300 }
3301
3302 if (!EltTy->isIntegerType()) {
3303 Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
3304 << 1 << /* scalar or vector of */ 5 << /* integer ty */ 1
3305 << /* no fp */ 0 << ArgTy;
3306 return true;
3307 }
3308
3309 TheCall->setType(ResTy);
3310 break;
3311 }
3312 case Builtin::BI__builtin_hlsl_select: {
3313 if (SemaRef.checkArgCount(TheCall, 3))
3314 return true;
3315 if (CheckScalarOrVector(&SemaRef, TheCall, getASTContext().BoolTy, 0))
3316 return true;
3317 QualType ArgTy = TheCall->getArg(0)->getType();
3318 if (ArgTy->isBooleanType() && CheckBoolSelect(&SemaRef, TheCall))
3319 return true;
3320 auto *VTy = ArgTy->getAs<VectorType>();
3321 if (VTy && VTy->getElementType()->isBooleanType() &&
3322 CheckVectorSelect(&SemaRef, TheCall))
3323 return true;
3324 break;
3325 }
3326 case Builtin::BI__builtin_hlsl_elementwise_saturate:
3327 case Builtin::BI__builtin_hlsl_elementwise_rcp: {
3328 if (SemaRef.checkArgCount(TheCall, 1))
3329 return true;
3330 if (!TheCall->getArg(0)
3331 ->getType()
3332 ->hasFloatingRepresentation()) // half or float or double
3333 return SemaRef.Diag(TheCall->getArg(0)->getBeginLoc(),
3334 diag::err_builtin_invalid_arg_type)
3335 << /* ordinal */ 1 << /* scalar or vector */ 5 << /* no int */ 0
3336 << /* fp */ 1 << TheCall->getArg(0)->getType();
3337 if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall))
3338 return true;
3339 break;
3340 }
3341 case Builtin::BI__builtin_hlsl_elementwise_degrees:
3342 case Builtin::BI__builtin_hlsl_elementwise_radians:
3343 case Builtin::BI__builtin_hlsl_elementwise_rsqrt:
3344 case Builtin::BI__builtin_hlsl_elementwise_frac:
3345 case Builtin::BI__builtin_hlsl_elementwise_ddx_coarse:
3346 case Builtin::BI__builtin_hlsl_elementwise_ddy_coarse:
3347 case Builtin::BI__builtin_hlsl_elementwise_ddx_fine:
3348 case Builtin::BI__builtin_hlsl_elementwise_ddy_fine: {
3349 if (SemaRef.checkArgCount(TheCall, 1))
3350 return true;
3351 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
3353 return true;
3354 if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall))
3355 return true;
3356 break;
3357 }
3358 case Builtin::BI__builtin_hlsl_elementwise_isinf:
3359 case Builtin::BI__builtin_hlsl_elementwise_isnan: {
3360 if (SemaRef.checkArgCount(TheCall, 1))
3361 return true;
3362 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
3364 return true;
3365 if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall))
3366 return true;
3368 break;
3369 }
3370 case Builtin::BI__builtin_hlsl_lerp: {
3371 if (SemaRef.checkArgCount(TheCall, 3))
3372 return true;
3373 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
3375 return true;
3376 if (CheckAllArgsHaveSameType(&SemaRef, TheCall))
3377 return true;
3378 if (SemaRef.BuiltinElementwiseTernaryMath(TheCall))
3379 return true;
3380 break;
3381 }
3382 case Builtin::BI__builtin_hlsl_mad: {
3383 if (SemaRef.BuiltinElementwiseTernaryMath(
3384 TheCall, /*ArgTyRestr=*/
3386 return true;
3387 break;
3388 }
3389 case Builtin::BI__builtin_hlsl_normalize: {
3390 if (SemaRef.checkArgCount(TheCall, 1))
3391 return true;
3392 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
3394 return true;
3395 ExprResult A = TheCall->getArg(0);
3396 QualType ArgTyA = A.get()->getType();
3397 // return type is the same as the input type
3398 TheCall->setType(ArgTyA);
3399 break;
3400 }
3401 case Builtin::BI__builtin_hlsl_elementwise_sign: {
3402 if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall))
3403 return true;
3404 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
3406 return true;
3408 break;
3409 }
3410 case Builtin::BI__builtin_hlsl_step: {
3411 if (SemaRef.checkArgCount(TheCall, 2))
3412 return true;
3413 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
3415 return true;
3416
3417 ExprResult A = TheCall->getArg(0);
3418 QualType ArgTyA = A.get()->getType();
3419 // return type is the same as the input type
3420 TheCall->setType(ArgTyA);
3421 break;
3422 }
3423 case Builtin::BI__builtin_hlsl_wave_active_max:
3424 case Builtin::BI__builtin_hlsl_wave_active_min:
3425 case Builtin::BI__builtin_hlsl_wave_active_sum: {
3426 if (SemaRef.checkArgCount(TheCall, 1))
3427 return true;
3428
3429 // Ensure input expr type is a scalar/vector and the same as the return type
3430 if (CheckAnyScalarOrVector(&SemaRef, TheCall, 0))
3431 return true;
3432 if (CheckWaveActive(&SemaRef, TheCall))
3433 return true;
3434 ExprResult Expr = TheCall->getArg(0);
3435 QualType ArgTyExpr = Expr.get()->getType();
3436 TheCall->setType(ArgTyExpr);
3437 break;
3438 }
3439 // Note these are llvm builtins that we want to catch invalid intrinsic
3440 // generation. Normal handling of these builtins will occur elsewhere.
3441 case Builtin::BI__builtin_elementwise_bitreverse: {
3442 // does not include a check for number of arguments
3443 // because that is done previously
3444 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
3446 return true;
3447 break;
3448 }
3449 case Builtin::BI__builtin_hlsl_wave_read_lane_at: {
3450 if (SemaRef.checkArgCount(TheCall, 2))
3451 return true;
3452
3453 // Ensure index parameter type can be interpreted as a uint
3454 ExprResult Index = TheCall->getArg(1);
3455 QualType ArgTyIndex = Index.get()->getType();
3456 if (!ArgTyIndex->isIntegerType()) {
3457 SemaRef.Diag(TheCall->getArg(1)->getBeginLoc(),
3458 diag::err_typecheck_convert_incompatible)
3459 << ArgTyIndex << SemaRef.Context.UnsignedIntTy << 1 << 0 << 0;
3460 return true;
3461 }
3462
3463 // Ensure input expr type is a scalar/vector and the same as the return type
3464 if (CheckAnyScalarOrVector(&SemaRef, TheCall, 0))
3465 return true;
3466
3467 ExprResult Expr = TheCall->getArg(0);
3468 QualType ArgTyExpr = Expr.get()->getType();
3469 TheCall->setType(ArgTyExpr);
3470 break;
3471 }
3472 case Builtin::BI__builtin_hlsl_wave_get_lane_index: {
3473 if (SemaRef.checkArgCount(TheCall, 0))
3474 return true;
3475 break;
3476 }
3477 case Builtin::BI__builtin_hlsl_elementwise_splitdouble: {
3478 if (SemaRef.checkArgCount(TheCall, 3))
3479 return true;
3480
3481 if (CheckScalarOrVector(&SemaRef, TheCall, SemaRef.Context.DoubleTy, 0) ||
3482 CheckScalarOrVector(&SemaRef, TheCall, SemaRef.Context.UnsignedIntTy,
3483 1) ||
3484 CheckScalarOrVector(&SemaRef, TheCall, SemaRef.Context.UnsignedIntTy,
3485 2))
3486 return true;
3487
3488 if (CheckModifiableLValue(&SemaRef, TheCall, 1) ||
3489 CheckModifiableLValue(&SemaRef, TheCall, 2))
3490 return true;
3491 break;
3492 }
3493 case Builtin::BI__builtin_hlsl_elementwise_clip: {
3494 if (SemaRef.checkArgCount(TheCall, 1))
3495 return true;
3496
3497 if (CheckScalarOrVector(&SemaRef, TheCall, SemaRef.Context.FloatTy, 0))
3498 return true;
3499 break;
3500 }
3501 case Builtin::BI__builtin_elementwise_acos:
3502 case Builtin::BI__builtin_elementwise_asin:
3503 case Builtin::BI__builtin_elementwise_atan:
3504 case Builtin::BI__builtin_elementwise_atan2:
3505 case Builtin::BI__builtin_elementwise_ceil:
3506 case Builtin::BI__builtin_elementwise_cos:
3507 case Builtin::BI__builtin_elementwise_cosh:
3508 case Builtin::BI__builtin_elementwise_exp:
3509 case Builtin::BI__builtin_elementwise_exp2:
3510 case Builtin::BI__builtin_elementwise_exp10:
3511 case Builtin::BI__builtin_elementwise_floor:
3512 case Builtin::BI__builtin_elementwise_fmod:
3513 case Builtin::BI__builtin_elementwise_log:
3514 case Builtin::BI__builtin_elementwise_log2:
3515 case Builtin::BI__builtin_elementwise_log10:
3516 case Builtin::BI__builtin_elementwise_pow:
3517 case Builtin::BI__builtin_elementwise_roundeven:
3518 case Builtin::BI__builtin_elementwise_sin:
3519 case Builtin::BI__builtin_elementwise_sinh:
3520 case Builtin::BI__builtin_elementwise_sqrt:
3521 case Builtin::BI__builtin_elementwise_tan:
3522 case Builtin::BI__builtin_elementwise_tanh:
3523 case Builtin::BI__builtin_elementwise_trunc: {
3524 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
3526 return true;
3527 break;
3528 }
3529 case Builtin::BI__builtin_hlsl_buffer_update_counter: {
3530 assert(TheCall->getNumArgs() == 2 && "expected 2 args");
3531 auto checkResTy = [](const HLSLAttributedResourceType *ResTy) -> bool {
3532 return !(ResTy->getAttrs().ResourceClass == ResourceClass::UAV &&
3533 ResTy->getAttrs().RawBuffer && ResTy->hasContainedType());
3534 };
3535 if (CheckResourceHandle(&SemaRef, TheCall, 0, checkResTy))
3536 return true;
3537 Expr *OffsetExpr = TheCall->getArg(1);
3538 std::optional<llvm::APSInt> Offset =
3539 OffsetExpr->getIntegerConstantExpr(SemaRef.getASTContext());
3540 if (!Offset.has_value() || std::abs(Offset->getExtValue()) != 1) {
3541 SemaRef.Diag(TheCall->getArg(1)->getBeginLoc(),
3542 diag::err_hlsl_expect_arg_const_int_one_or_neg_one)
3543 << 1;
3544 return true;
3545 }
3546 break;
3547 }
3548 case Builtin::BI__builtin_hlsl_elementwise_f16tof32: {
3549 if (SemaRef.checkArgCount(TheCall, 1))
3550 return true;
3551 if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
3553 return true;
3554 // ensure arg integers are 32 bits
3555 if (CheckExpectedBitWidth(&SemaRef, TheCall, 0, 32))
3556 return true;
3557 // check it wasn't a bool type
3558 QualType ArgTy = TheCall->getArg(0)->getType();
3559 if (auto *VTy = ArgTy->getAs<VectorType>())
3560 ArgTy = VTy->getElementType();
3561 if (ArgTy->isBooleanType()) {
3562 SemaRef.Diag(TheCall->getArg(0)->getBeginLoc(),
3563 diag::err_builtin_invalid_arg_type)
3564 << 1 << /* scalar or vector of */ 5 << /* unsigned int */ 3
3565 << /* no fp */ 0 << TheCall->getArg(0)->getType();
3566 return true;
3567 }
3568
3569 SetElementTypeAsReturnType(&SemaRef, TheCall, getASTContext().FloatTy);
3570 break;
3571 }
3572 }
3573 return false;
3574}
3575
3579 WorkList.push_back(BaseTy);
3580 while (!WorkList.empty()) {
3581 QualType T = WorkList.pop_back_val();
3582 T = T.getCanonicalType().getUnqualifiedType();
3583 if (const auto *AT = dyn_cast<ConstantArrayType>(T)) {
3584 llvm::SmallVector<QualType, 16> ElementFields;
3585 // Generally I've avoided recursion in this algorithm, but arrays of
3586 // structs could be time-consuming to flatten and churn through on the
3587 // work list. Hopefully nesting arrays of structs containing arrays
3588 // of structs too many levels deep is unlikely.
3589 BuildFlattenedTypeList(AT->getElementType(), ElementFields);
3590 // Repeat the element's field list n times.
3591 for (uint64_t Ct = 0; Ct < AT->getZExtSize(); ++Ct)
3592 llvm::append_range(List, ElementFields);
3593 continue;
3594 }
3595 // Vectors can only have element types that are builtin types, so this can
3596 // add directly to the list instead of to the WorkList.
3597 if (const auto *VT = dyn_cast<VectorType>(T)) {
3598 List.insert(List.end(), VT->getNumElements(), VT->getElementType());
3599 continue;
3600 }
3601 if (const auto *MT = dyn_cast<ConstantMatrixType>(T)) {
3602 List.insert(List.end(), MT->getNumElementsFlattened(),
3603 MT->getElementType());
3604 continue;
3605 }
3606 if (const auto *RD = T->getAsCXXRecordDecl()) {
3607 if (RD->isStandardLayout())
3608 RD = RD->getStandardLayoutBaseWithFields();
3609
3610 // For types that we shouldn't decompose (unions and non-aggregates), just
3611 // add the type itself to the list.
3612 if (RD->isUnion() || !RD->isAggregate()) {
3613 List.push_back(T);
3614 continue;
3615 }
3616
3618 for (const auto *FD : RD->fields())
3619 if (!FD->isUnnamedBitField())
3620 FieldTypes.push_back(FD->getType());
3621 // Reverse the newly added sub-range.
3622 std::reverse(FieldTypes.begin(), FieldTypes.end());
3623 llvm::append_range(WorkList, FieldTypes);
3624
3625 // If this wasn't a standard layout type we may also have some base
3626 // classes to deal with.
3627 if (!RD->isStandardLayout()) {
3628 FieldTypes.clear();
3629 for (const auto &Base : RD->bases())
3630 FieldTypes.push_back(Base.getType());
3631 std::reverse(FieldTypes.begin(), FieldTypes.end());
3632 llvm::append_range(WorkList, FieldTypes);
3633 }
3634 continue;
3635 }
3636 List.push_back(T);
3637 }
3638}
3639
3641 // null and array types are not allowed.
3642 if (QT.isNull() || QT->isArrayType())
3643 return false;
3644
3645 // UDT types are not allowed
3646 if (QT->isRecordType())
3647 return false;
3648
3649 if (QT->isBooleanType() || QT->isEnumeralType())
3650 return false;
3651
3652 // the only other valid builtin types are scalars or vectors
3653 if (QT->isArithmeticType()) {
3654 if (SemaRef.Context.getTypeSize(QT) / 8 > 16)
3655 return false;
3656 return true;
3657 }
3658
3659 if (const VectorType *VT = QT->getAs<VectorType>()) {
3660 int ArraySize = VT->getNumElements();
3661
3662 if (ArraySize > 4)
3663 return false;
3664
3665 QualType ElTy = VT->getElementType();
3666 if (ElTy->isBooleanType())
3667 return false;
3668
3669 if (SemaRef.Context.getTypeSize(QT) / 8 > 16)
3670 return false;
3671 return true;
3672 }
3673
3674 return false;
3675}
3676
3678 if (T1.isNull() || T2.isNull())
3679 return false;
3680
3683
3684 // If both types are the same canonical type, they're obviously compatible.
3685 if (SemaRef.getASTContext().hasSameType(T1, T2))
3686 return true;
3687
3689 BuildFlattenedTypeList(T1, T1Types);
3691 BuildFlattenedTypeList(T2, T2Types);
3692
3693 // Check the flattened type list
3694 return llvm::equal(T1Types, T2Types,
3695 [this](QualType LHS, QualType RHS) -> bool {
3696 return SemaRef.IsLayoutCompatible(LHS, RHS);
3697 });
3698}
3699
3701 FunctionDecl *Old) {
3702 if (New->getNumParams() != Old->getNumParams())
3703 return true;
3704
3705 bool HadError = false;
3706
3707 for (unsigned i = 0, e = New->getNumParams(); i != e; ++i) {
3708 ParmVarDecl *NewParam = New->getParamDecl(i);
3709 ParmVarDecl *OldParam = Old->getParamDecl(i);
3710
3711 // HLSL parameter declarations for inout and out must match between
3712 // declarations. In HLSL inout and out are ambiguous at the call site,
3713 // but have different calling behavior, so you cannot overload a
3714 // method based on a difference between inout and out annotations.
3715 const auto *NDAttr = NewParam->getAttr<HLSLParamModifierAttr>();
3716 unsigned NSpellingIdx = (NDAttr ? NDAttr->getSpellingListIndex() : 0);
3717 const auto *ODAttr = OldParam->getAttr<HLSLParamModifierAttr>();
3718 unsigned OSpellingIdx = (ODAttr ? ODAttr->getSpellingListIndex() : 0);
3719
3720 if (NSpellingIdx != OSpellingIdx) {
3721 SemaRef.Diag(NewParam->getLocation(),
3722 diag::err_hlsl_param_qualifier_mismatch)
3723 << NDAttr << NewParam;
3724 SemaRef.Diag(OldParam->getLocation(), diag::note_previous_declaration_as)
3725 << ODAttr;
3726 HadError = true;
3727 }
3728 }
3729 return HadError;
3730}
3731
3732// Generally follows PerformScalarCast, with cases reordered for
3733// clarity of what types are supported
3735
3736 if (!SrcTy->isScalarType() || !DestTy->isScalarType())
3737 return false;
3738
3739 if (SemaRef.getASTContext().hasSameUnqualifiedType(SrcTy, DestTy))
3740 return true;
3741
3742 switch (SrcTy->getScalarTypeKind()) {
3743 case Type::STK_Bool: // casting from bool is like casting from an integer
3744 case Type::STK_Integral:
3745 switch (DestTy->getScalarTypeKind()) {
3746 case Type::STK_Bool:
3747 case Type::STK_Integral:
3748 case Type::STK_Floating:
3749 return true;
3750 case Type::STK_CPointer:
3754 llvm_unreachable("HLSL doesn't support pointers.");
3757 llvm_unreachable("HLSL doesn't support complex types.");
3759 llvm_unreachable("HLSL doesn't support fixed point types.");
3760 }
3761 llvm_unreachable("Should have returned before this");
3762
3763 case Type::STK_Floating:
3764 switch (DestTy->getScalarTypeKind()) {
3765 case Type::STK_Floating:
3766 case Type::STK_Bool:
3767 case Type::STK_Integral:
3768 return true;
3771 llvm_unreachable("HLSL doesn't support complex types.");
3773 llvm_unreachable("HLSL doesn't support fixed point types.");
3774 case Type::STK_CPointer:
3778 llvm_unreachable("HLSL doesn't support pointers.");
3779 }
3780 llvm_unreachable("Should have returned before this");
3781
3783 case Type::STK_CPointer:
3786 llvm_unreachable("HLSL doesn't support pointers.");
3787
3789 llvm_unreachable("HLSL doesn't support fixed point types.");
3790
3793 llvm_unreachable("HLSL doesn't support complex types.");
3794 }
3795
3796 llvm_unreachable("Unhandled scalar cast");
3797}
3798
3799// Can perform an HLSL Aggregate splat cast if the Dest is an aggregate and the
3800// Src is a scalar or a vector of length 1
3801// Or if Dest is a vector and Src is a vector of length 1
3803
3804 QualType SrcTy = Src->getType();
3805 // Not a valid HLSL Aggregate Splat cast if Dest is a scalar or if this is
3806 // going to be a vector splat from a scalar.
3807 if ((SrcTy->isScalarType() && DestTy->isVectorType()) ||
3808 DestTy->isScalarType())
3809 return false;
3810
3811 const VectorType *SrcVecTy = SrcTy->getAs<VectorType>();
3812
3813 // Src isn't a scalar or a vector of length 1
3814 if (!SrcTy->isScalarType() && !(SrcVecTy && SrcVecTy->getNumElements() == 1))
3815 return false;
3816
3817 if (SrcVecTy)
3818 SrcTy = SrcVecTy->getElementType();
3819
3821 BuildFlattenedTypeList(DestTy, DestTypes);
3822
3823 for (unsigned I = 0, Size = DestTypes.size(); I < Size; ++I) {
3824 if (DestTypes[I]->isUnionType())
3825 return false;
3826 if (!CanPerformScalarCast(SrcTy, DestTypes[I]))
3827 return false;
3828 }
3829 return true;
3830}
3831
3832// Can we perform an HLSL Elementwise cast?
3834
3835 // Don't handle casts where LHS and RHS are any combination of scalar/vector
3836 // There must be an aggregate somewhere
3837 QualType SrcTy = Src->getType();
3838 if (SrcTy->isScalarType()) // always a splat and this cast doesn't handle that
3839 return false;
3840
3841 if (SrcTy->isVectorType() &&
3842 (DestTy->isScalarType() || DestTy->isVectorType()))
3843 return false;
3844
3845 if (SrcTy->isConstantMatrixType() &&
3846 (DestTy->isScalarType() || DestTy->isConstantMatrixType()))
3847 return false;
3848
3850 BuildFlattenedTypeList(DestTy, DestTypes);
3852 BuildFlattenedTypeList(SrcTy, SrcTypes);
3853
3854 // Usually the size of SrcTypes must be greater than or equal to the size of
3855 // DestTypes.
3856 if (SrcTypes.size() < DestTypes.size())
3857 return false;
3858
3859 unsigned SrcSize = SrcTypes.size();
3860 unsigned DstSize = DestTypes.size();
3861 unsigned I;
3862 for (I = 0; I < DstSize && I < SrcSize; I++) {
3863 if (SrcTypes[I]->isUnionType() || DestTypes[I]->isUnionType())
3864 return false;
3865 if (!CanPerformScalarCast(SrcTypes[I], DestTypes[I])) {
3866 return false;
3867 }
3868 }
3869
3870 // check the rest of the source type for unions.
3871 for (; I < SrcSize; I++) {
3872 if (SrcTypes[I]->isUnionType())
3873 return false;
3874 }
3875 return true;
3876}
3877
3879 assert(Param->hasAttr<HLSLParamModifierAttr>() &&
3880 "We should not get here without a parameter modifier expression");
3881 const auto *Attr = Param->getAttr<HLSLParamModifierAttr>();
3882 if (Attr->getABI() == ParameterABI::Ordinary)
3883 return ExprResult(Arg);
3884
3885 bool IsInOut = Attr->getABI() == ParameterABI::HLSLInOut;
3886 if (!Arg->isLValue()) {
3887 SemaRef.Diag(Arg->getBeginLoc(), diag::error_hlsl_inout_lvalue)
3888 << Arg << (IsInOut ? 1 : 0);
3889 return ExprError();
3890 }
3891
3892 ASTContext &Ctx = SemaRef.getASTContext();
3893
3894 QualType Ty = Param->getType().getNonLValueExprType(Ctx);
3895
3896 // HLSL allows implicit conversions from scalars to vectors, but not the
3897 // inverse, so we need to disallow `inout` with scalar->vector or
3898 // scalar->matrix conversions.
3899 if (Arg->getType()->isScalarType() != Ty->isScalarType()) {
3900 SemaRef.Diag(Arg->getBeginLoc(), diag::error_hlsl_inout_scalar_extension)
3901 << Arg << (IsInOut ? 1 : 0);
3902 return ExprError();
3903 }
3904
3905 auto *ArgOpV = new (Ctx) OpaqueValueExpr(Param->getBeginLoc(), Arg->getType(),
3906 VK_LValue, OK_Ordinary, Arg);
3907
3908 // Parameters are initialized via copy initialization. This allows for
3909 // overload resolution of argument constructors.
3910 InitializedEntity Entity =
3912 ExprResult Res =
3913 SemaRef.PerformCopyInitialization(Entity, Param->getBeginLoc(), ArgOpV);
3914 if (Res.isInvalid())
3915 return ExprError();
3916 Expr *Base = Res.get();
3917 // After the cast, drop the reference type when creating the exprs.
3918 Ty = Ty.getNonLValueExprType(Ctx);
3919 auto *OpV = new (Ctx)
3920 OpaqueValueExpr(Param->getBeginLoc(), Ty, VK_LValue, OK_Ordinary, Base);
3921
3922 // Writebacks are performed with `=` binary operator, which allows for
3923 // overload resolution on writeback result expressions.
3924 Res = SemaRef.ActOnBinOp(SemaRef.getCurScope(), Param->getBeginLoc(),
3925 tok::equal, ArgOpV, OpV);
3926
3927 if (Res.isInvalid())
3928 return ExprError();
3929 Expr *Writeback = Res.get();
3930 auto *OutExpr =
3931 HLSLOutArgExpr::Create(Ctx, Ty, ArgOpV, OpV, Writeback, IsInOut);
3932
3933 return ExprResult(OutExpr);
3934}
3935
3937 // If HLSL gains support for references, all the cites that use this will need
3938 // to be updated with semantic checking to produce errors for
3939 // pointers/references.
3940 assert(!Ty->isReferenceType() &&
3941 "Pointer and reference types cannot be inout or out parameters");
3942 Ty = SemaRef.getASTContext().getLValueReferenceType(Ty);
3943 Ty.addRestrict();
3944 return Ty;
3945}
3946
3947static bool IsDefaultBufferConstantDecl(const ASTContext &Ctx, VarDecl *VD) {
3948 bool IsVulkan =
3949 Ctx.getTargetInfo().getTriple().getOS() == llvm::Triple::Vulkan;
3950 bool IsVKPushConstant = IsVulkan && VD->hasAttr<HLSLVkPushConstantAttr>();
3951 QualType QT = VD->getType();
3952 return VD->getDeclContext()->isTranslationUnit() &&
3953 QT.getAddressSpace() == LangAS::Default &&
3954 VD->getStorageClass() != SC_Static &&
3955 !VD->hasAttr<HLSLVkConstantIdAttr>() && !IsVKPushConstant &&
3957}
3958
3960 // The variable already has an address space (groupshared for ex).
3961 if (Decl->getType().hasAddressSpace())
3962 return;
3963
3964 if (Decl->getType()->isDependentType())
3965 return;
3966
3967 QualType Type = Decl->getType();
3968
3969 if (Decl->hasAttr<HLSLVkExtBuiltinInputAttr>()) {
3970 LangAS ImplAS = LangAS::hlsl_input;
3971 Type = SemaRef.getASTContext().getAddrSpaceQualType(Type, ImplAS);
3972 Decl->setType(Type);
3973 return;
3974 }
3975
3976 bool IsVulkan = getASTContext().getTargetInfo().getTriple().getOS() ==
3977 llvm::Triple::Vulkan;
3978 if (IsVulkan && Decl->hasAttr<HLSLVkPushConstantAttr>()) {
3979 if (HasDeclaredAPushConstant)
3980 SemaRef.Diag(Decl->getLocation(), diag::err_hlsl_push_constant_unique);
3981
3983 Type = SemaRef.getASTContext().getAddrSpaceQualType(Type, ImplAS);
3984 Decl->setType(Type);
3985 HasDeclaredAPushConstant = true;
3986 return;
3987 }
3988
3989 if (Type->isSamplerT() || Type->isVoidType())
3990 return;
3991
3992 // Resource handles.
3994 return;
3995
3996 // Only static globals belong to the Private address space.
3997 // Non-static globals belongs to the cbuffer.
3998 if (Decl->getStorageClass() != SC_Static && !Decl->isStaticDataMember())
3999 return;
4000
4002 Type = SemaRef.getASTContext().getAddrSpaceQualType(Type, ImplAS);
4003 Decl->setType(Type);
4004}
4005
4007 if (VD->hasGlobalStorage()) {
4008 // make sure the declaration has a complete type
4009 if (SemaRef.RequireCompleteType(
4010 VD->getLocation(),
4011 SemaRef.getASTContext().getBaseElementType(VD->getType()),
4012 diag::err_typecheck_decl_incomplete_type)) {
4013 VD->setInvalidDecl();
4015 return;
4016 }
4017
4018 // Global variables outside a cbuffer block that are not a resource, static,
4019 // groupshared, or an empty array or struct belong to the default constant
4020 // buffer $Globals (to be created at the end of the translation unit).
4022 // update address space to hlsl_constant
4025 VD->setType(NewTy);
4026 DefaultCBufferDecls.push_back(VD);
4027 }
4028
4029 // find all resources bindings on decl
4030 if (VD->getType()->isHLSLIntangibleType())
4031 collectResourceBindingsOnVarDecl(VD);
4032
4033 if (VD->hasAttr<HLSLVkConstantIdAttr>())
4035
4037 VD->getStorageClass() != SC_Static) {
4038 // Add internal linkage attribute to non-static resource variables. The
4039 // global externally visible storage is accessed through the handle, which
4040 // is a member. The variable itself is not externally visible.
4041 VD->addAttr(InternalLinkageAttr::CreateImplicit(getASTContext()));
4042 }
4043
4044 // process explicit bindings
4045 processExplicitBindingsOnDecl(VD);
4046
4047 // Add implicit binding attribute to non-static resource arrays.
4048 if (VD->getType()->isHLSLResourceRecordArray() &&
4049 VD->getStorageClass() != SC_Static) {
4050 // If the resource array does not have an explicit binding attribute,
4051 // create an implicit one. It will be used to transfer implicit binding
4052 // order_ID to codegen.
4053 ResourceBindingAttrs Binding(VD);
4054 if (!Binding.isExplicit()) {
4055 uint32_t OrderID = getNextImplicitBindingOrderID();
4056 if (Binding.hasBinding())
4057 Binding.setImplicitOrderID(OrderID);
4058 else {
4061 OrderID);
4062 // Re-create the binding object to pick up the new attribute.
4063 Binding = ResourceBindingAttrs(VD);
4064 }
4065 }
4066
4067 // Get to the base type of a potentially multi-dimensional array.
4069
4070 const CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
4071 if (hasCounterHandle(RD)) {
4072 if (!Binding.hasCounterImplicitOrderID()) {
4073 uint32_t OrderID = getNextImplicitBindingOrderID();
4074 Binding.setCounterImplicitOrderID(OrderID);
4075 }
4076 }
4077 }
4078 }
4079
4081}
4082
4083bool SemaHLSL::initGlobalResourceDecl(VarDecl *VD) {
4084 assert(VD->getType()->isHLSLResourceRecord() &&
4085 "expected resource record type");
4086
4088 uint64_t UIntTySize = AST.getTypeSize(AST.UnsignedIntTy);
4089 uint64_t IntTySize = AST.getTypeSize(AST.IntTy);
4090
4091 // Gather resource binding attributes.
4092 ResourceBindingAttrs Binding(VD);
4093
4094 // Find correct initialization method and create its arguments.
4095 QualType ResourceTy = VD->getType();
4096 CXXRecordDecl *ResourceDecl = ResourceTy->getAsCXXRecordDecl();
4097 CXXMethodDecl *CreateMethod = nullptr;
4099
4100 bool HasCounter = hasCounterHandle(ResourceDecl);
4101 const char *CreateMethodName;
4102 if (Binding.isExplicit())
4103 CreateMethodName = HasCounter ? "__createFromBindingWithImplicitCounter"
4104 : "__createFromBinding";
4105 else
4106 CreateMethodName = HasCounter
4107 ? "__createFromImplicitBindingWithImplicitCounter"
4108 : "__createFromImplicitBinding";
4109
4110 CreateMethod =
4111 lookupMethod(SemaRef, ResourceDecl, CreateMethodName, VD->getLocation());
4112
4113 if (!CreateMethod)
4114 // This can happen if someone creates a struct that looks like an HLSL
4115 // resource record but does not have the required static create method.
4116 // No binding will be generated for it.
4117 return false;
4118
4119 if (Binding.isExplicit()) {
4120 IntegerLiteral *RegSlot =
4121 IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, Binding.getSlot()),
4123 Args.push_back(RegSlot);
4124 } else {
4125 uint32_t OrderID = (Binding.hasImplicitOrderID())
4126 ? Binding.getImplicitOrderID()
4127 : getNextImplicitBindingOrderID();
4128 IntegerLiteral *OrderId =
4129 IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, OrderID),
4131 Args.push_back(OrderId);
4132 }
4133
4134 IntegerLiteral *Space =
4135 IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, Binding.getSpace()),
4136 AST.UnsignedIntTy, SourceLocation());
4137 Args.push_back(Space);
4138
4139 IntegerLiteral *RangeSize = IntegerLiteral::Create(
4140 AST, llvm::APInt(IntTySize, 1), AST.IntTy, SourceLocation());
4141 Args.push_back(RangeSize);
4142
4143 IntegerLiteral *Index = IntegerLiteral::Create(
4144 AST, llvm::APInt(UIntTySize, 0), AST.UnsignedIntTy, SourceLocation());
4145 Args.push_back(Index);
4146
4147 StringRef VarName = VD->getName();
4148 StringLiteral *Name = StringLiteral::Create(
4149 AST, VarName, StringLiteralKind::Ordinary, false,
4150 AST.getStringLiteralArrayType(AST.CharTy.withConst(), VarName.size()),
4151 SourceLocation());
4152 ImplicitCastExpr *NameCast = ImplicitCastExpr::Create(
4153 AST, AST.getPointerType(AST.CharTy.withConst()), CK_ArrayToPointerDecay,
4154 Name, nullptr, VK_PRValue, FPOptionsOverride());
4155 Args.push_back(NameCast);
4156
4157 if (HasCounter) {
4158 // Will this be in the correct order?
4159 uint32_t CounterOrderID = getNextImplicitBindingOrderID();
4160 IntegerLiteral *CounterId =
4161 IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, CounterOrderID),
4162 AST.UnsignedIntTy, SourceLocation());
4163 Args.push_back(CounterId);
4164 }
4165
4166 // Make sure the create method template is instantiated and emitted.
4167 if (!CreateMethod->isDefined() && CreateMethod->isTemplateInstantiation())
4168 SemaRef.InstantiateFunctionDefinition(VD->getLocation(), CreateMethod,
4169 true);
4170
4171 // Create CallExpr with a call to the static method and set it as the decl
4172 // initialization.
4173 DeclRefExpr *DRE = DeclRefExpr::Create(
4174 AST, NestedNameSpecifierLoc(), SourceLocation(), CreateMethod, false,
4175 CreateMethod->getNameInfo(), CreateMethod->getType(), VK_PRValue);
4176
4177 auto *ImpCast = ImplicitCastExpr::Create(
4178 AST, AST.getPointerType(CreateMethod->getType()),
4179 CK_FunctionToPointerDecay, DRE, nullptr, VK_PRValue, FPOptionsOverride());
4180
4181 CallExpr *InitExpr =
4182 CallExpr::Create(AST, ImpCast, Args, ResourceTy, VK_PRValue,
4183 SourceLocation(), FPOptionsOverride());
4184 VD->setInit(InitExpr);
4186 SemaRef.CheckCompleteVariableDeclaration(VD);
4187 return true;
4188}
4189
4190bool SemaHLSL::initGlobalResourceArrayDecl(VarDecl *VD) {
4191 assert(VD->getType()->isHLSLResourceRecordArray() &&
4192 "expected array of resource records");
4193
4194 // Individual resources in a resource array are not initialized here. They
4195 // are initialized later on during codegen when the individual resources are
4196 // accessed. Codegen will emit a call to the resource initialization method
4197 // with the specified array index. We need to make sure though that the method
4198 // for the specific resource type is instantiated, so codegen can emit a call
4199 // to it when the array element is accessed.
4200
4201 // Find correct initialization method based on the resource binding
4202 // information.
4203 ASTContext &AST = SemaRef.getASTContext();
4204 QualType ResElementTy = AST.getBaseElementType(VD->getType());
4205 CXXRecordDecl *ResourceDecl = ResElementTy->getAsCXXRecordDecl();
4206 CXXMethodDecl *CreateMethod = nullptr;
4207
4208 bool HasCounter = hasCounterHandle(ResourceDecl);
4209 ResourceBindingAttrs ResourceAttrs(VD);
4210 if (ResourceAttrs.isExplicit())
4211 // Resource has explicit binding.
4212 CreateMethod =
4213 lookupMethod(SemaRef, ResourceDecl,
4214 HasCounter ? "__createFromBindingWithImplicitCounter"
4215 : "__createFromBinding",
4216 VD->getLocation());
4217 else
4218 // Resource has implicit binding.
4219 CreateMethod = lookupMethod(
4220 SemaRef, ResourceDecl,
4221 HasCounter ? "__createFromImplicitBindingWithImplicitCounter"
4222 : "__createFromImplicitBinding",
4223 VD->getLocation());
4224
4225 if (!CreateMethod)
4226 return false;
4227
4228 // Make sure the create method template is instantiated and emitted.
4229 if (!CreateMethod->isDefined() && CreateMethod->isTemplateInstantiation())
4230 SemaRef.InstantiateFunctionDefinition(VD->getLocation(), CreateMethod,
4231 true);
4232 return true;
4233}
4234
4235// Returns true if the initialization has been handled.
4236// Returns false to use default initialization.
4238 // Objects in the hlsl_constant address space are initialized
4239 // externally, so don't synthesize an implicit initializer.
4241 return true;
4242
4243 // Initialize non-static resources at the global scope.
4244 if (VD->hasGlobalStorage() && VD->getStorageClass() != SC_Static) {
4245 const Type *Ty = VD->getType().getTypePtr();
4246 if (Ty->isHLSLResourceRecord())
4247 return initGlobalResourceDecl(VD);
4248 if (Ty->isHLSLResourceRecordArray())
4249 return initGlobalResourceArrayDecl(VD);
4250 }
4251 return false;
4252}
4253
4254// Return true if everything is ok; returns false if there was an error.
4256 Expr *RHSExpr, SourceLocation Loc) {
4257 assert((LHSExpr->getType()->isHLSLResourceRecord() ||
4258 LHSExpr->getType()->isHLSLResourceRecordArray()) &&
4259 "expected LHS to be a resource record or array of resource records");
4260 if (Opc != BO_Assign)
4261 return true;
4262
4263 // If LHS is an array subscript, get the underlying declaration.
4264 Expr *E = LHSExpr;
4265 while (auto *ASE = dyn_cast<ArraySubscriptExpr>(E))
4266 E = ASE->getBase()->IgnoreParenImpCasts();
4267
4268 // Report error if LHS is a non-static resource declared at a global scope.
4269 if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParens())) {
4270 if (VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
4271 if (VD->hasGlobalStorage() && VD->getStorageClass() != SC_Static) {
4272 // assignment to global resource is not allowed
4273 SemaRef.Diag(Loc, diag::err_hlsl_assign_to_global_resource) << VD;
4274 SemaRef.Diag(VD->getLocation(), diag::note_var_declared_here) << VD;
4275 return false;
4276 }
4277 }
4278 }
4279 return true;
4280}
4281
4282// Walks though the global variable declaration, collects all resource binding
4283// requirements and adds them to Bindings
4284void SemaHLSL::collectResourceBindingsOnVarDecl(VarDecl *VD) {
4285 assert(VD->hasGlobalStorage() && VD->getType()->isHLSLIntangibleType() &&
4286 "expected global variable that contains HLSL resource");
4287
4288 // Cbuffers and Tbuffers are HLSLBufferDecl types
4289 if (const HLSLBufferDecl *CBufferOrTBuffer = dyn_cast<HLSLBufferDecl>(VD)) {
4290 Bindings.addDeclBindingInfo(VD, CBufferOrTBuffer->isCBuffer()
4291 ? ResourceClass::CBuffer
4292 : ResourceClass::SRV);
4293 return;
4294 }
4295
4296 // Unwrap arrays
4297 // FIXME: Calculate array size while unwrapping
4298 const Type *Ty = VD->getType()->getUnqualifiedDesugaredType();
4299 while (Ty->isArrayType()) {
4300 const ArrayType *AT = cast<ArrayType>(Ty);
4302 }
4303
4304 // Resource (or array of resources)
4305 if (const HLSLAttributedResourceType *AttrResType =
4306 HLSLAttributedResourceType::findHandleTypeOnResource(Ty)) {
4307 Bindings.addDeclBindingInfo(VD, AttrResType->getAttrs().ResourceClass);
4308 return;
4309 }
4310
4311 // User defined record type
4312 if (const RecordType *RT = dyn_cast<RecordType>(Ty))
4313 collectResourceBindingsOnUserRecordDecl(VD, RT);
4314}
4315
4316// Walks though the explicit resource binding attributes on the declaration,
4317// and makes sure there is a resource that matched the binding and updates
4318// DeclBindingInfoLists
4319void SemaHLSL::processExplicitBindingsOnDecl(VarDecl *VD) {
4320 assert(VD->hasGlobalStorage() && "expected global variable");
4321
4322 bool HasBinding = false;
4323 for (Attr *A : VD->attrs()) {
4324 if (isa<HLSLVkBindingAttr>(A)) {
4325 HasBinding = true;
4326 if (auto PA = VD->getAttr<HLSLVkPushConstantAttr>())
4327 Diag(PA->getLoc(), diag::err_hlsl_attr_incompatible) << A << PA;
4328 }
4329
4330 HLSLResourceBindingAttr *RBA = dyn_cast<HLSLResourceBindingAttr>(A);
4331 if (!RBA || !RBA->hasRegisterSlot())
4332 continue;
4333 HasBinding = true;
4334
4335 RegisterType RT = RBA->getRegisterType();
4336 assert(RT != RegisterType::I && "invalid or obsolete register type should "
4337 "never have an attribute created");
4338
4339 if (RT == RegisterType::C) {
4340 if (Bindings.hasBindingInfoForDecl(VD))
4341 SemaRef.Diag(VD->getLocation(),
4342 diag::warn_hlsl_user_defined_type_missing_member)
4343 << static_cast<int>(RT);
4344 continue;
4345 }
4346
4347 // Find DeclBindingInfo for this binding and update it, or report error
4348 // if it does not exist (user type does to contain resources with the
4349 // expected resource class).
4351 if (DeclBindingInfo *BI = Bindings.getDeclBindingInfo(VD, RC)) {
4352 // update binding info
4353 BI->setBindingAttribute(RBA, BindingType::Explicit);
4354 } else {
4355 SemaRef.Diag(VD->getLocation(),
4356 diag::warn_hlsl_user_defined_type_missing_member)
4357 << static_cast<int>(RT);
4358 }
4359 }
4360
4361 if (!HasBinding && isResourceRecordTypeOrArrayOf(VD))
4362 SemaRef.Diag(VD->getLocation(), diag::warn_hlsl_implicit_binding);
4363}
4364namespace {
4365class InitListTransformer {
4366 Sema &S;
4367 ASTContext &Ctx;
4368 QualType InitTy;
4369 QualType *DstIt = nullptr;
4370 Expr **ArgIt = nullptr;
4371 // Is wrapping the destination type iterator required? This is only used for
4372 // incomplete array types where we loop over the destination type since we
4373 // don't know the full number of elements from the declaration.
4374 bool Wrap;
4375
4376 bool castInitializer(Expr *E) {
4377 assert(DstIt && "This should always be something!");
4378 if (DstIt == DestTypes.end()) {
4379 if (!Wrap) {
4380 ArgExprs.push_back(E);
4381 // This is odd, but it isn't technically a failure due to conversion, we
4382 // handle mismatched counts of arguments differently.
4383 return true;
4384 }
4385 DstIt = DestTypes.begin();
4386 }
4387 InitializedEntity Entity = InitializedEntity::InitializeParameter(
4388 Ctx, *DstIt, /* Consumed (ObjC) */ false);
4389 ExprResult Res = S.PerformCopyInitialization(Entity, E->getBeginLoc(), E);
4390 if (Res.isInvalid())
4391 return false;
4392 Expr *Init = Res.get();
4393 ArgExprs.push_back(Init);
4394 DstIt++;
4395 return true;
4396 }
4397
4398 bool buildInitializerListImpl(Expr *E) {
4399 // If this is an initialization list, traverse the sub initializers.
4400 if (auto *Init = dyn_cast<InitListExpr>(E)) {
4401 for (auto *SubInit : Init->inits())
4402 if (!buildInitializerListImpl(SubInit))
4403 return false;
4404 return true;
4405 }
4406
4407 // If this is a scalar type, just enqueue the expression.
4408 QualType Ty = E->getType();
4409
4410 if (Ty->isScalarType() || (Ty->isRecordType() && !Ty->isAggregateType()))
4411 return castInitializer(E);
4412
4413 if (auto *VecTy = Ty->getAs<VectorType>()) {
4414 uint64_t Size = VecTy->getNumElements();
4415
4416 QualType SizeTy = Ctx.getSizeType();
4417 uint64_t SizeTySize = Ctx.getTypeSize(SizeTy);
4418 for (uint64_t I = 0; I < Size; ++I) {
4419 auto *Idx = IntegerLiteral::Create(Ctx, llvm::APInt(SizeTySize, I),
4420 SizeTy, SourceLocation());
4421
4423 E, E->getBeginLoc(), Idx, E->getEndLoc());
4424 if (ElExpr.isInvalid())
4425 return false;
4426 if (!castInitializer(ElExpr.get()))
4427 return false;
4428 }
4429 return true;
4430 }
4431 if (auto *MTy = Ty->getAs<ConstantMatrixType>()) {
4432 unsigned Rows = MTy->getNumRows();
4433 unsigned Cols = MTy->getNumColumns();
4434 QualType ElemTy = MTy->getElementType();
4435
4436 for (unsigned C = 0; C < Cols; ++C) {
4437 for (unsigned R = 0; R < Rows; ++R) {
4438 // row index literal
4439 Expr *RowIdx = IntegerLiteral::Create(
4440 Ctx, llvm::APInt(Ctx.getIntWidth(Ctx.IntTy), R), Ctx.IntTy,
4441 E->getBeginLoc());
4442 // column index literal
4443 Expr *ColIdx = IntegerLiteral::Create(
4444 Ctx, llvm::APInt(Ctx.getIntWidth(Ctx.IntTy), C), Ctx.IntTy,
4445 E->getBeginLoc());
4447 E, RowIdx, ColIdx, E->getEndLoc());
4448 if (ElExpr.isInvalid())
4449 return false;
4450 if (!castInitializer(ElExpr.get()))
4451 return false;
4452 ElExpr.get()->setType(ElemTy);
4453 }
4454 }
4455 return true;
4456 }
4457
4458 if (auto *ArrTy = dyn_cast<ConstantArrayType>(Ty.getTypePtr())) {
4459 uint64_t Size = ArrTy->getZExtSize();
4460 QualType SizeTy = Ctx.getSizeType();
4461 uint64_t SizeTySize = Ctx.getTypeSize(SizeTy);
4462 for (uint64_t I = 0; I < Size; ++I) {
4463 auto *Idx = IntegerLiteral::Create(Ctx, llvm::APInt(SizeTySize, I),
4464 SizeTy, SourceLocation());
4466 E, E->getBeginLoc(), Idx, E->getEndLoc());
4467 if (ElExpr.isInvalid())
4468 return false;
4469 if (!buildInitializerListImpl(ElExpr.get()))
4470 return false;
4471 }
4472 return true;
4473 }
4474
4475 if (auto *RD = Ty->getAsCXXRecordDecl()) {
4476 llvm::SmallVector<CXXRecordDecl *> RecordDecls;
4477 RecordDecls.push_back(RD);
4478 while (RecordDecls.back()->getNumBases()) {
4479 CXXRecordDecl *D = RecordDecls.back();
4480 assert(D->getNumBases() == 1 &&
4481 "HLSL doesn't support multiple inheritance");
4482 RecordDecls.push_back(
4484 }
4485 while (!RecordDecls.empty()) {
4486 CXXRecordDecl *RD = RecordDecls.pop_back_val();
4487 for (auto *FD : RD->fields()) {
4488 if (FD->isUnnamedBitField())
4489 continue;
4490 DeclAccessPair Found = DeclAccessPair::make(FD, FD->getAccess());
4491 DeclarationNameInfo NameInfo(FD->getDeclName(), E->getBeginLoc());
4493 E, false, E->getBeginLoc(), CXXScopeSpec(), FD, Found, NameInfo);
4494 if (Res.isInvalid())
4495 return false;
4496 if (!buildInitializerListImpl(Res.get()))
4497 return false;
4498 }
4499 }
4500 }
4501 return true;
4502 }
4503
4504 Expr *generateInitListsImpl(QualType Ty) {
4505 assert(ArgIt != ArgExprs.end() && "Something is off in iteration!");
4506 if (Ty->isScalarType() || (Ty->isRecordType() && !Ty->isAggregateType()))
4507 return *(ArgIt++);
4508
4509 llvm::SmallVector<Expr *> Inits;
4510 Ty = Ty.getDesugaredType(Ctx);
4511 if (Ty->isVectorType() || Ty->isConstantArrayType() ||
4512 Ty->isConstantMatrixType()) {
4513 QualType ElTy;
4514 uint64_t Size = 0;
4515 if (auto *ATy = Ty->getAs<VectorType>()) {
4516 ElTy = ATy->getElementType();
4517 Size = ATy->getNumElements();
4518 } else if (auto *CMTy = Ty->getAs<ConstantMatrixType>()) {
4519 ElTy = CMTy->getElementType();
4520 Size = CMTy->getNumElementsFlattened();
4521 } else {
4522 auto *VTy = cast<ConstantArrayType>(Ty.getTypePtr());
4523 ElTy = VTy->getElementType();
4524 Size = VTy->getZExtSize();
4525 }
4526 for (uint64_t I = 0; I < Size; ++I)
4527 Inits.push_back(generateInitListsImpl(ElTy));
4528 }
4529 if (auto *RD = Ty->getAsCXXRecordDecl()) {
4530 llvm::SmallVector<CXXRecordDecl *> RecordDecls;
4531 RecordDecls.push_back(RD);
4532 while (RecordDecls.back()->getNumBases()) {
4533 CXXRecordDecl *D = RecordDecls.back();
4534 assert(D->getNumBases() == 1 &&
4535 "HLSL doesn't support multiple inheritance");
4536 RecordDecls.push_back(
4538 }
4539 while (!RecordDecls.empty()) {
4540 CXXRecordDecl *RD = RecordDecls.pop_back_val();
4541 for (auto *FD : RD->fields())
4542 if (!FD->isUnnamedBitField())
4543 Inits.push_back(generateInitListsImpl(FD->getType()));
4544 }
4545 }
4546 auto *NewInit = new (Ctx) InitListExpr(Ctx, Inits.front()->getBeginLoc(),
4547 Inits, Inits.back()->getEndLoc());
4548 NewInit->setType(Ty);
4549 return NewInit;
4550 }
4551
4552public:
4553 llvm::SmallVector<QualType, 16> DestTypes;
4554 llvm::SmallVector<Expr *, 16> ArgExprs;
4555 InitListTransformer(Sema &SemaRef, const InitializedEntity &Entity)
4556 : S(SemaRef), Ctx(SemaRef.getASTContext()),
4557 Wrap(Entity.getType()->isIncompleteArrayType()) {
4558 InitTy = Entity.getType().getNonReferenceType();
4559 // When we're generating initializer lists for incomplete array types we
4560 // need to wrap around both when building the initializers and when
4561 // generating the final initializer lists.
4562 if (Wrap) {
4563 assert(InitTy->isIncompleteArrayType());
4564 const IncompleteArrayType *IAT = Ctx.getAsIncompleteArrayType(InitTy);
4565 InitTy = IAT->getElementType();
4566 }
4567 BuildFlattenedTypeList(InitTy, DestTypes);
4568 DstIt = DestTypes.begin();
4569 }
4570
4571 bool buildInitializerList(Expr *E) { return buildInitializerListImpl(E); }
4572
4573 Expr *generateInitLists() {
4574 assert(!ArgExprs.empty() &&
4575 "Call buildInitializerList to generate argument expressions.");
4576 ArgIt = ArgExprs.begin();
4577 if (!Wrap)
4578 return generateInitListsImpl(InitTy);
4579 llvm::SmallVector<Expr *> Inits;
4580 while (ArgIt != ArgExprs.end())
4581 Inits.push_back(generateInitListsImpl(InitTy));
4582
4583 auto *NewInit = new (Ctx) InitListExpr(Ctx, Inits.front()->getBeginLoc(),
4584 Inits, Inits.back()->getEndLoc());
4585 llvm::APInt ArySize(64, Inits.size());
4586 NewInit->setType(Ctx.getConstantArrayType(InitTy, ArySize, nullptr,
4587 ArraySizeModifier::Normal, 0));
4588 return NewInit;
4589 }
4590};
4591} // namespace
4592
4594 InitListExpr *Init) {
4595 // If the initializer is a scalar, just return it.
4596 if (Init->getType()->isScalarType())
4597 return true;
4598 ASTContext &Ctx = SemaRef.getASTContext();
4599 InitListTransformer ILT(SemaRef, Entity);
4600
4601 for (unsigned I = 0; I < Init->getNumInits(); ++I) {
4602 Expr *E = Init->getInit(I);
4603 if (E->HasSideEffects(Ctx)) {
4604 QualType Ty = E->getType();
4605 if (Ty->isRecordType())
4606 E = new (Ctx) MaterializeTemporaryExpr(Ty, E, E->isLValue());
4607 E = new (Ctx) OpaqueValueExpr(E->getBeginLoc(), Ty, E->getValueKind(),
4608 E->getObjectKind(), E);
4609 Init->setInit(I, E);
4610 }
4611 if (!ILT.buildInitializerList(E))
4612 return false;
4613 }
4614 size_t ExpectedSize = ILT.DestTypes.size();
4615 size_t ActualSize = ILT.ArgExprs.size();
4616 if (ExpectedSize == 0 && ActualSize == 0)
4617 return true;
4618
4619 // For incomplete arrays it is completely arbitrary to choose whether we think
4620 // the user intended fewer or more elements. This implementation assumes that
4621 // the user intended more, and errors that there are too few initializers to
4622 // complete the final element.
4623 if (Entity.getType()->isIncompleteArrayType())
4624 ExpectedSize =
4625 ((ActualSize + ExpectedSize - 1) / ExpectedSize) * ExpectedSize;
4626
4627 // An initializer list might be attempting to initialize a reference or
4628 // rvalue-reference. When checking the initializer we should look through
4629 // the reference.
4630 QualType InitTy = Entity.getType().getNonReferenceType();
4631 if (InitTy.hasAddressSpace())
4632 InitTy = SemaRef.getASTContext().removeAddrSpaceQualType(InitTy);
4633 if (ExpectedSize != ActualSize) {
4634 int TooManyOrFew = ActualSize > ExpectedSize ? 1 : 0;
4635 SemaRef.Diag(Init->getBeginLoc(), diag::err_hlsl_incorrect_num_initializers)
4636 << TooManyOrFew << InitTy << ExpectedSize << ActualSize;
4637 return false;
4638 }
4639
4640 // generateInitListsImpl will always return an InitListExpr here, because the
4641 // scalar case is handled above.
4642 auto *NewInit = cast<InitListExpr>(ILT.generateInitLists());
4643 Init->resizeInits(Ctx, NewInit->getNumInits());
4644 for (unsigned I = 0; I < NewInit->getNumInits(); ++I)
4645 Init->updateInit(Ctx, I, NewInit->getInit(I));
4646 return true;
4647}
4648
4650 const HLSLVkConstantIdAttr *ConstIdAttr =
4651 VDecl->getAttr<HLSLVkConstantIdAttr>();
4652 if (!ConstIdAttr)
4653 return true;
4654
4655 ASTContext &Context = SemaRef.getASTContext();
4656
4657 APValue InitValue;
4658 if (!Init->isCXX11ConstantExpr(Context, &InitValue)) {
4659 Diag(VDecl->getLocation(), diag::err_specialization_const);
4660 VDecl->setInvalidDecl();
4661 return false;
4662 }
4663
4664 Builtin::ID BID =
4666
4667 // Argument 1: The ID from the attribute
4668 int ConstantID = ConstIdAttr->getId();
4669 llvm::APInt IDVal(Context.getIntWidth(Context.IntTy), ConstantID);
4670 Expr *IdExpr = IntegerLiteral::Create(Context, IDVal, Context.IntTy,
4671 ConstIdAttr->getLocation());
4672
4673 SmallVector<Expr *, 2> Args = {IdExpr, Init};
4674 Expr *C = SemaRef.BuildBuiltinCallExpr(Init->getExprLoc(), BID, Args);
4675 if (C->getType()->getCanonicalTypeUnqualified() !=
4677 C = SemaRef
4678 .BuildCStyleCastExpr(SourceLocation(),
4679 Context.getTrivialTypeSourceInfo(
4680 Init->getType(), Init->getExprLoc()),
4681 SourceLocation(), C)
4682 .get();
4683 }
4684 Init = C;
4685 return true;
4686}
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
static bool IsDefaultBufferConstantDecl(const ASTContext &Ctx, VarDecl *VD)
HLSLResourceBindingAttr::RegisterType RegisterType
Definition SemaHLSL.cpp:58
static CastKind getScalarCastKind(ASTContext &Ctx, QualType DestTy, QualType SrcTy)
static bool isValidWaveSizeValue(unsigned Value)
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:790
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:909
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:3723
QualType getElementType() const
Definition TypeBase.h:3735
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:2943
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition Expr.h:3147
SourceLocation getBeginLoc() const
Definition Expr.h:3277
static CallExpr * Create(const ASTContext &Ctx, Expr *Fn, ArrayRef< Expr * > Args, QualType Ty, ExprValueKind VK, SourceLocation RParenLoc, FPOptionsOverride FPFeatures, unsigned MinNumArgs=0, ADLCallKind UsesADL=NotADL)
Create a call expression.
Definition Expr.cpp:1516
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
Definition Expr.h:3126
Expr * getCallee()
Definition Expr.h:3090
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition Expr.h:3134
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:3761
bool isZeroSize() const
Return true if the size is zero.
Definition TypeBase.h:3831
uint64_t getZExtSize() const
Return the size zero-extended as a uint64_t.
Definition TypeBase.h:3837
static DeclAccessPair make(NamedDecl *D, AccessSpecifier AS)
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Definition DeclBase.h:1449
lookup_result lookup(DeclarationName Name) const
lookup - Find the declarations (if any) with the given Name in this context.
bool isTranslationUnit() const
Definition DeclBase.h:2185
void addDecl(Decl *D)
Add the declaration D into this context.
decl_range decls() const
decls_begin/decls_end - Iterate over the declarations stored in this context.
Definition DeclBase.h:2373
DeclContext * getNonTransparentContext()
A reference to a declared variable, function, enum, etc.
Definition Expr.h:1270
static DeclRefExpr * Create(const ASTContext &Context, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, ValueDecl *D, bool RefersToEnclosingVariableOrCapture, SourceLocation NameLoc, QualType T, ExprValueKind VK, NamedDecl *FoundD=nullptr, const TemplateArgumentListInfo *TemplateArgs=nullptr, NonOdrUseReason NOUR=NOUR_None)
Definition Expr.cpp:487
ValueDecl * getDecl()
Definition Expr.h:1338
Decl - This represents one declaration (or definition), e.g.
Definition DeclBase.h:86
T * getAttr() const
Definition DeclBase.h:573
void addAttr(Attr *A)
attr_iterator attr_end() const
Definition DeclBase.h:542
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
Definition DeclBase.h:593
void setInvalidDecl(bool Invalid=true)
setInvalidDecl - Indicates the Decl had a semantic error.
Definition DeclBase.cpp:178
bool isInExportDeclContext() const
Whether this declaration was exported in a lexical context.
attr_iterator attr_begin() const
Definition DeclBase.h:539
SourceLocation getLocation() const
Definition DeclBase.h:439
void setImplicit(bool I=true)
Definition DeclBase.h:594
DeclContext * getDeclContext()
Definition DeclBase.h:448
attr_range attrs() const
Definition DeclBase.h:535
AccessSpecifier getAccess() const
Definition DeclBase.h:507
SourceLocation getBeginLoc() const LLVM_READONLY
Definition DeclBase.h:431
void dropAttr()
Definition DeclBase.h:556
bool hasAttr() const
Definition DeclBase.h:577
The name of a declaration.
Represents a ValueDecl that came out of a declarator.
Definition Decl.h:780
SourceLocation getBeginLoc() const LLVM_READONLY
Definition Decl.h:831
This represents one expression.
Definition Expr.h:112
void setType(QualType t)
Definition Expr.h:145
ExprValueKind getValueKind() const
getValueKind - The value kind that this expression produces.
Definition Expr.h:444
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
Definition Expr.cpp:3089
Expr * IgnoreParens() LLVM_READONLY
Skip past any parentheses which might surround this expression until reaching a fixed point.
Definition Expr.cpp:3085
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:3669
void setValueKind(ExprValueKind Cat)
setValueKind - Set the value kind produced by this expression.
Definition Expr.h:461
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Definition Expr.cpp:276
@ MLV_Valid
Definition Expr.h:305
QualType getType() const
Definition Expr.h:144
Represents a member of a struct/union/class.
Definition Decl.h:3160
static FieldDecl * Create(const ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, const IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, Expr *BW, bool Mutable, InClassInitStyle InitStyle)
Definition Decl.cpp: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:5839
void addLayoutStruct(CXXRecordDecl *LS)
Definition Decl.cpp:5879
void setHasValidPackoffset(bool PO)
Definition Decl.h:5235
static HLSLBufferDecl * CreateDefaultCBuffer(ASTContext &C, DeclContext *LexicalParent, ArrayRef< Decl * > DefaultCBufferDecls)
Definition Decl.cpp:5862
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:5531
static HLSLRootSignatureDecl * Create(ASTContext &C, DeclContext *DC, SourceLocation Loc, IdentifierInfo *ID, llvm::dxbc::RootSignatureVersion Version, ArrayRef< llvm::hlsl::rootsig::RootElement > RootElements)
Definition Decl.cpp:5925
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:2072
Describes an C or C++ initializer list.
Definition Expr.h:5299
Describes an entity that is being initialized.
QualType getType() const
Retrieve type being initialized.
static InitializedEntity InitializeParameter(ASTContext &Context, ParmVarDecl *Parm)
Create the initialization entity for a parameter.
static IntegerLiteral * Create(const ASTContext &C, const llvm::APInt &V, QualType type, SourceLocation l)
Returns a new integer literal with value 'V' and type 'type'.
Definition Expr.cpp:974
Represents the results of name lookup.
Definition Lookup.h:147
NamedDecl * getFoundDecl() const
Fetch the unique decl found by this lookup.
Definition Lookup.h:569
Represents a prvalue temporary that is written into memory so that a reference can bind to it.
Definition ExprCXX.h:4920
ValueDecl * getMemberDecl() const
Retrieve the member declaration to which this expression refers.
Definition Expr.h:3447
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:3556
QualType getDesugaredType(const ASTContext &Context) const
Return the specified type with any "sugar" removed from the type.
Definition TypeBase.h:1296
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition TypeBase.h:1004
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Definition TypeBase.h:8293
LangAS getAddressSpace() const
Return the address space of this type.
Definition TypeBase.h:8419
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:8478
QualType getCanonicalType() const
Definition TypeBase.h:8345
QualType getUnqualifiedType() const
Retrieve the unqualified variant of the given type, removing as little sugar as possible.
Definition TypeBase.h:8387
bool hasAddressSpace() const
Check if this type has any address space qualifier.
Definition TypeBase.h:8414
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)
void handleVkPushConstantAttr(Decl *D, 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:855
@ LookupOrdinaryName
Ordinary name lookup, which finds ordinary names (functions, variables, typedefs, etc....
Definition Sema.h:9315
@ LookupMemberName
Member name lookup, which finds the names of class/struct/union members.
Definition Sema.h:9323
ASTContext & Context
Definition Sema.h:1283
ASTContext & getASTContext() const
Definition Sema.h:926
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:919
ExprResult BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow, SourceLocation OpLoc, const CXXScopeSpec &SS, FieldDecl *Field, DeclAccessPair FoundDecl, const DeclarationNameInfo &MemberNameInfo)
ExprResult CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, Expr *Idx, SourceLocation RLoc)
bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, bool InUnqualifiedLookup=false)
Perform qualified name lookup into a given context.
ExprResult PerformCopyInitialization(const InitializedEntity &Entity, SourceLocation EqualLoc, ExprResult Init, bool TopLevelOfInitList=false, bool AllowExplicit=false)
ExprResult CreateBuiltinMatrixSubscriptExpr(Expr *Base, Expr *RowIdx, Expr *ColumnIdx, SourceLocation RBLoc)
Encodes a location in the source.
A trivial tuple used to represent a source range.
SourceLocation getEnd() const
SourceLocation getEndLoc() const LLVM_READONLY
Definition Stmt.cpp:362
void printPretty(raw_ostream &OS, PrinterHelper *Helper, const PrintingPolicy &Policy, unsigned Indentation=0, StringRef NewlineSymbol="\n", const ASTContext *Context=nullptr) const
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition Stmt.cpp:338
SourceLocation getBeginLoc() const LLVM_READONLY
Definition Stmt.cpp:350
static StringLiteral * Create(const ASTContext &Ctx, StringRef Str, StringLiteralKind Kind, bool Pascal, QualType Ty, ArrayRef< SourceLocation > Locs)
This is the "fully general" constructor that allows representation of strings formed from one or more...
Definition Expr.cpp:1187
void startDefinition()
Starts the definition of this tag declaration.
Definition Decl.cpp: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:326
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:8264
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:8892
bool isBooleanType() const
Definition TypeBase.h:9022
bool isIncompleteArrayType() const
Definition TypeBase.h:8637
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:8633
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:2067
bool isArrayType() const
Definition TypeBase.h:8629
CXXRecordDecl * castAsCXXRecordDecl() const
Definition Type.h:36
bool isArithmeticType() const
Definition Type.cpp:2338
bool isConstantMatrixType() const
Definition TypeBase.h:8697
bool isHLSLBuiltinIntangibleType() const
Definition TypeBase.h:8837
CanQualType getCanonicalTypeUnqualified() const
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
Definition TypeBase.h:8936
const T * castAs() const
Member-template castAs<specific type>.
Definition TypeBase.h:9179
bool isReferenceType() const
Definition TypeBase.h:8554
bool isHLSLIntangibleType() const
Definition Type.cpp:5376
bool isEnumeralType() const
Definition TypeBase.h:8661
bool isScalarType() const
Definition TypeBase.h:8994
bool isIntegralType(const ASTContext &Ctx) const
Determine whether this type is an integral type.
Definition Type.cpp:2104
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:472
bool hasUnsignedIntegerRepresentation() const
Determine whether this type has an unsigned integer representation of some sort, e....
Definition Type.cpp:2292
bool isAggregateType() const
Determines whether the type is a C++ aggregate type or C aggregate or union type.
Definition Type.cpp:2412
ScalarTypeKind getScalarTypeKind() const
Given that this is a scalar type, classify it.
Definition Type.cpp:2365
bool hasSignedIntegerRepresentation() const
Determine whether this type has an signed integer representation of some sort, e.g....
Definition Type.cpp:2244
bool isHLSLResourceRecord() const
Definition Type.cpp:5363
bool hasFloatingRepresentation() const
Determine whether this type has a floating-point representation of some sort, e.g....
Definition Type.cpp:2313
bool isVectorType() const
Definition TypeBase.h:8669
bool isRealFloatingType() const
Floating point categories.
Definition Type.cpp:2321
bool isHLSLAttributedResourceType() const
Definition TypeBase.h:8849
@ STK_FloatingComplex
Definition TypeBase.h:2765
@ STK_ObjCObjectPointer
Definition TypeBase.h:2759
@ STK_IntegralComplex
Definition TypeBase.h:2764
@ STK_MemberPointer
Definition TypeBase.h:2760
bool isFloatingType() const
Definition Type.cpp:2305
bool isSamplerT() const
Definition TypeBase.h:8770
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9112
const Type * getUnqualifiedDesugaredType() const
Return the specified type with any "sugar" removed from the type, removing any typedefs,...
Definition Type.cpp:654
bool isRecordType() const
Definition TypeBase.h:8657
bool isHLSLResourceRecordArray() const
Definition Type.cpp:5367
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:4176
unsigned getNumElements() const
Definition TypeBase.h:4191
QualType getElementType() const
Definition TypeBase.h:4190
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:563
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