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