1782ac218SXiang Li //===- SemaHLSL.cpp - Semantic Analysis for HLSL constructs ---------------===// 2782ac218SXiang Li // 3782ac218SXiang Li // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4782ac218SXiang Li // See https://llvm.org/LICENSE.txt for license information. 5782ac218SXiang Li // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6782ac218SXiang Li // 7782ac218SXiang Li //===----------------------------------------------------------------------===// 8782ac218SXiang Li // This implements Semantic Analysis for HLSL constructs. 9782ac218SXiang Li //===----------------------------------------------------------------------===// 10782ac218SXiang Li 11d345f6a2SVlad Serebrennikov #include "clang/Sema/SemaHLSL.h" 128e35c869SHelena Kotas #include "clang/AST/ASTContext.h" 130a7a1ef2SHelena Kotas #include "clang/AST/Attr.h" 140a7a1ef2SHelena Kotas #include "clang/AST/Attrs.inc" 158890209eSHelena Kotas #include "clang/AST/Decl.h" 169efe3773SHelena Kotas #include "clang/AST/DeclBase.h" 179efe3773SHelena Kotas #include "clang/AST/DeclCXX.h" 18825e7129SHelena Kotas #include "clang/AST/DeclarationName.h" 19dde802b1SSirraide #include "clang/AST/DynamicRecursiveASTVisitor.h" 208890209eSHelena Kotas #include "clang/AST/Expr.h" 219efe3773SHelena Kotas #include "clang/AST/Type.h" 220a7a1ef2SHelena Kotas #include "clang/AST/TypeLoc.h" 23dce50397STim Gymnich #include "clang/Basic/Builtins.h" 24b45c9c31SVlad Serebrennikov #include "clang/Basic/DiagnosticSema.h" 25825e7129SHelena Kotas #include "clang/Basic/IdentifierTable.h" 26b45c9c31SVlad Serebrennikov #include "clang/Basic/LLVM.h" 27e00e9a3fSHelena Kotas #include "clang/Basic/SourceLocation.h" 28d92bac8aSHelena Kotas #include "clang/Basic/Specifiers.h" 29b45c9c31SVlad Serebrennikov #include "clang/Basic/TargetInfo.h" 3089fb8490SChris B #include "clang/Sema/Initialization.h" 316b755b0cSVlad Serebrennikov #include "clang/Sema/ParsedAttr.h" 32782ac218SXiang Li #include "clang/Sema/Sema.h" 338e35c869SHelena Kotas #include "clang/Sema/Template.h" 34b45c9c31SVlad Serebrennikov #include "llvm/ADT/STLExtras.h" 358e35c869SHelena Kotas #include "llvm/ADT/SmallVector.h" 36b45c9c31SVlad Serebrennikov #include "llvm/ADT/StringExtras.h" 37b45c9c31SVlad Serebrennikov #include "llvm/ADT/StringRef.h" 38825e7129SHelena Kotas #include "llvm/ADT/Twine.h" 398890209eSHelena Kotas #include "llvm/Support/Casting.h" 40e41579a3SXiang Li #include "llvm/Support/DXILABI.h" 41b45c9c31SVlad Serebrennikov #include "llvm/Support/ErrorHandling.h" 42b45c9c31SVlad Serebrennikov #include "llvm/TargetParser/Triple.h" 43825e7129SHelena Kotas #include <cstddef> 44b45c9c31SVlad Serebrennikov #include <iterator> 458e35c869SHelena Kotas #include <utility> 46782ac218SXiang Li 47782ac218SXiang Li using namespace clang; 484512bbe7SHelena Kotas using RegisterType = HLSLResourceBindingAttr::RegisterType; 49f2128267SHelena Kotas 50825e7129SHelena Kotas static CXXRecordDecl *createHostLayoutStruct(Sema &S, 51825e7129SHelena Kotas CXXRecordDecl *StructDecl); 52825e7129SHelena Kotas 53f2128267SHelena Kotas static RegisterType getRegisterType(ResourceClass RC) { 54f2128267SHelena Kotas switch (RC) { 55f2128267SHelena Kotas case ResourceClass::SRV: 56f2128267SHelena Kotas return RegisterType::SRV; 57f2128267SHelena Kotas case ResourceClass::UAV: 58f2128267SHelena Kotas return RegisterType::UAV; 59f2128267SHelena Kotas case ResourceClass::CBuffer: 60f2128267SHelena Kotas return RegisterType::CBuffer; 61f2128267SHelena Kotas case ResourceClass::Sampler: 62f2128267SHelena Kotas return RegisterType::Sampler; 63f2128267SHelena Kotas } 64f2128267SHelena Kotas llvm_unreachable("unexpected ResourceClass value"); 65f2128267SHelena Kotas } 66f2128267SHelena Kotas 674512bbe7SHelena Kotas // Converts the first letter of string Slot to RegisterType. 684512bbe7SHelena Kotas // Returns false if the letter does not correspond to a valid register type. 694512bbe7SHelena Kotas static bool convertToRegisterType(StringRef Slot, RegisterType *RT) { 704512bbe7SHelena Kotas assert(RT != nullptr); 71f2128267SHelena Kotas switch (Slot[0]) { 72f2128267SHelena Kotas case 't': 73f2128267SHelena Kotas case 'T': 744512bbe7SHelena Kotas *RT = RegisterType::SRV; 754512bbe7SHelena Kotas return true; 76f2128267SHelena Kotas case 'u': 77f2128267SHelena Kotas case 'U': 784512bbe7SHelena Kotas *RT = RegisterType::UAV; 794512bbe7SHelena Kotas return true; 80f2128267SHelena Kotas case 'b': 81f2128267SHelena Kotas case 'B': 824512bbe7SHelena Kotas *RT = RegisterType::CBuffer; 834512bbe7SHelena Kotas return true; 84f2128267SHelena Kotas case 's': 85f2128267SHelena Kotas case 'S': 864512bbe7SHelena Kotas *RT = RegisterType::Sampler; 874512bbe7SHelena Kotas return true; 88f2128267SHelena Kotas case 'c': 89f2128267SHelena Kotas case 'C': 904512bbe7SHelena Kotas *RT = RegisterType::C; 914512bbe7SHelena Kotas return true; 92f2128267SHelena Kotas case 'i': 93f2128267SHelena Kotas case 'I': 944512bbe7SHelena Kotas *RT = RegisterType::I; 954512bbe7SHelena Kotas return true; 96f2128267SHelena Kotas default: 974512bbe7SHelena Kotas return false; 98f2128267SHelena Kotas } 99f2128267SHelena Kotas } 100782ac218SXiang Li 1014512bbe7SHelena Kotas static ResourceClass getResourceClass(RegisterType RT) { 1024512bbe7SHelena Kotas switch (RT) { 1034512bbe7SHelena Kotas case RegisterType::SRV: 1044512bbe7SHelena Kotas return ResourceClass::SRV; 1054512bbe7SHelena Kotas case RegisterType::UAV: 1064512bbe7SHelena Kotas return ResourceClass::UAV; 1074512bbe7SHelena Kotas case RegisterType::CBuffer: 1084512bbe7SHelena Kotas return ResourceClass::CBuffer; 1094512bbe7SHelena Kotas case RegisterType::Sampler: 1104512bbe7SHelena Kotas return ResourceClass::Sampler; 1114512bbe7SHelena Kotas case RegisterType::C: 1124512bbe7SHelena Kotas case RegisterType::I: 1139120adeaSDaniel Paoliello // Deliberately falling through to the unreachable below. 1149120adeaSDaniel Paoliello break; 1154512bbe7SHelena Kotas } 1169120adeaSDaniel Paoliello llvm_unreachable("unexpected RegisterType value"); 1174512bbe7SHelena Kotas } 1184512bbe7SHelena Kotas 1194512bbe7SHelena Kotas DeclBindingInfo *ResourceBindings::addDeclBindingInfo(const VarDecl *VD, 1204512bbe7SHelena Kotas ResourceClass ResClass) { 1214512bbe7SHelena Kotas assert(getDeclBindingInfo(VD, ResClass) == nullptr && 1224512bbe7SHelena Kotas "DeclBindingInfo already added"); 123f35a14ddSHelena Kotas assert(!hasBindingInfoForDecl(VD) || BindingsList.back().Decl == VD); 1244512bbe7SHelena Kotas // VarDecl may have multiple entries for different resource classes. 1254512bbe7SHelena Kotas // DeclToBindingListIndex stores the index of the first binding we saw 1264512bbe7SHelena Kotas // for this decl. If there are any additional ones then that index 1274512bbe7SHelena Kotas // shouldn't be updated. 1284512bbe7SHelena Kotas DeclToBindingListIndex.try_emplace(VD, BindingsList.size()); 1294512bbe7SHelena Kotas return &BindingsList.emplace_back(VD, ResClass); 1304512bbe7SHelena Kotas } 1314512bbe7SHelena Kotas 1324512bbe7SHelena Kotas DeclBindingInfo *ResourceBindings::getDeclBindingInfo(const VarDecl *VD, 1334512bbe7SHelena Kotas ResourceClass ResClass) { 1344512bbe7SHelena Kotas auto Entry = DeclToBindingListIndex.find(VD); 1354512bbe7SHelena Kotas if (Entry != DeclToBindingListIndex.end()) { 1364512bbe7SHelena Kotas for (unsigned Index = Entry->getSecond(); 1374512bbe7SHelena Kotas Index < BindingsList.size() && BindingsList[Index].Decl == VD; 1384512bbe7SHelena Kotas ++Index) { 1394512bbe7SHelena Kotas if (BindingsList[Index].ResClass == ResClass) 1404512bbe7SHelena Kotas return &BindingsList[Index]; 1414512bbe7SHelena Kotas } 1424512bbe7SHelena Kotas } 1434512bbe7SHelena Kotas return nullptr; 1444512bbe7SHelena Kotas } 1454512bbe7SHelena Kotas 1464512bbe7SHelena Kotas bool ResourceBindings::hasBindingInfoForDecl(const VarDecl *VD) const { 1474512bbe7SHelena Kotas return DeclToBindingListIndex.contains(VD); 1484512bbe7SHelena Kotas } 1494512bbe7SHelena Kotas 150d345f6a2SVlad Serebrennikov SemaHLSL::SemaHLSL(Sema &S) : SemaBase(S) {} 151d345f6a2SVlad Serebrennikov 152b45c9c31SVlad Serebrennikov Decl *SemaHLSL::ActOnStartBuffer(Scope *BufferScope, bool CBuffer, 153b45c9c31SVlad Serebrennikov SourceLocation KwLoc, IdentifierInfo *Ident, 154782ac218SXiang Li SourceLocation IdentLoc, 155782ac218SXiang Li SourceLocation LBrace) { 156782ac218SXiang Li // For anonymous namespace, take the location of the left brace. 157d345f6a2SVlad Serebrennikov DeclContext *LexicalParent = SemaRef.getCurLexicalContext(); 158782ac218SXiang Li HLSLBufferDecl *Result = HLSLBufferDecl::Create( 159d345f6a2SVlad Serebrennikov getASTContext(), LexicalParent, CBuffer, KwLoc, Ident, IdentLoc, LBrace); 160782ac218SXiang Li 161ebc4a66eSJoshua Batista // if CBuffer is false, then it's a TBuffer 162ebc4a66eSJoshua Batista auto RC = CBuffer ? llvm::hlsl::ResourceClass::CBuffer 163ebc4a66eSJoshua Batista : llvm::hlsl::ResourceClass::SRV; 164ebc4a66eSJoshua Batista auto RK = CBuffer ? llvm::hlsl::ResourceKind::CBuffer 165ebc4a66eSJoshua Batista : llvm::hlsl::ResourceKind::TBuffer; 166ebc4a66eSJoshua Batista Result->addAttr(HLSLResourceClassAttr::CreateImplicit(getASTContext(), RC)); 167ebc4a66eSJoshua Batista Result->addAttr(HLSLResourceAttr::CreateImplicit(getASTContext(), RK)); 168ebc4a66eSJoshua Batista 169d345f6a2SVlad Serebrennikov SemaRef.PushOnScopeChains(Result, BufferScope); 170d345f6a2SVlad Serebrennikov SemaRef.PushDeclContext(BufferScope, Result); 171782ac218SXiang Li 172782ac218SXiang Li return Result; 173782ac218SXiang Li } 174782ac218SXiang Li 175c123d0c1SHelena Kotas // Calculate the size of a legacy cbuffer type in bytes based on 17641f0574cSXiang Li // https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-packing-rules 17741f0574cSXiang Li static unsigned calculateLegacyCbufferSize(const ASTContext &Context, 17841f0574cSXiang Li QualType T) { 17941f0574cSXiang Li unsigned Size = 0; 180c123d0c1SHelena Kotas constexpr unsigned CBufferAlign = 16; 18141f0574cSXiang Li if (const RecordType *RT = T->getAs<RecordType>()) { 18241f0574cSXiang Li const RecordDecl *RD = RT->getDecl(); 18341f0574cSXiang Li for (const FieldDecl *Field : RD->fields()) { 18441f0574cSXiang Li QualType Ty = Field->getType(); 18541f0574cSXiang Li unsigned FieldSize = calculateLegacyCbufferSize(Context, Ty); 186c123d0c1SHelena Kotas // FIXME: This is not the correct alignment, it does not work for 16-bit 187c123d0c1SHelena Kotas // types. See llvm/llvm-project#119641. 188c123d0c1SHelena Kotas unsigned FieldAlign = 4; 18941f0574cSXiang Li if (Ty->isAggregateType()) 19041f0574cSXiang Li FieldAlign = CBufferAlign; 19141f0574cSXiang Li Size = llvm::alignTo(Size, FieldAlign); 19241f0574cSXiang Li Size += FieldSize; 19341f0574cSXiang Li } 19441f0574cSXiang Li } else if (const ConstantArrayType *AT = Context.getAsConstantArrayType(T)) { 19541f0574cSXiang Li if (unsigned ElementCount = AT->getSize().getZExtValue()) { 19641f0574cSXiang Li unsigned ElementSize = 19741f0574cSXiang Li calculateLegacyCbufferSize(Context, AT->getElementType()); 19841f0574cSXiang Li unsigned AlignedElementSize = llvm::alignTo(ElementSize, CBufferAlign); 19941f0574cSXiang Li Size = AlignedElementSize * (ElementCount - 1) + ElementSize; 20041f0574cSXiang Li } 20141f0574cSXiang Li } else if (const VectorType *VT = T->getAs<VectorType>()) { 20241f0574cSXiang Li unsigned ElementCount = VT->getNumElements(); 20341f0574cSXiang Li unsigned ElementSize = 20441f0574cSXiang Li calculateLegacyCbufferSize(Context, VT->getElementType()); 20541f0574cSXiang Li Size = ElementSize * ElementCount; 20641f0574cSXiang Li } else { 207c123d0c1SHelena Kotas Size = Context.getTypeSize(T) / 8; 20841f0574cSXiang Li } 20941f0574cSXiang Li return Size; 21041f0574cSXiang Li } 21141f0574cSXiang Li 212c123d0c1SHelena Kotas // Validate packoffset: 213c123d0c1SHelena Kotas // - if packoffset it used it must be set on all declarations inside the buffer 214c123d0c1SHelena Kotas // - packoffset ranges must not overlap 215c123d0c1SHelena Kotas static void validatePackoffset(Sema &S, HLSLBufferDecl *BufDecl) { 21641f0574cSXiang Li llvm::SmallVector<std::pair<VarDecl *, HLSLPackOffsetAttr *>> PackOffsetVec; 217c123d0c1SHelena Kotas 218c123d0c1SHelena Kotas // Make sure the packoffset annotations are either on all declarations 219c123d0c1SHelena Kotas // or on none. 22041f0574cSXiang Li bool HasPackOffset = false; 22141f0574cSXiang Li bool HasNonPackOffset = false; 22241f0574cSXiang Li for (auto *Field : BufDecl->decls()) { 22341f0574cSXiang Li VarDecl *Var = dyn_cast<VarDecl>(Field); 22441f0574cSXiang Li if (!Var) 22541f0574cSXiang Li continue; 22641f0574cSXiang Li if (Field->hasAttr<HLSLPackOffsetAttr>()) { 22741f0574cSXiang Li PackOffsetVec.emplace_back(Var, Field->getAttr<HLSLPackOffsetAttr>()); 22841f0574cSXiang Li HasPackOffset = true; 22941f0574cSXiang Li } else { 23041f0574cSXiang Li HasNonPackOffset = true; 23141f0574cSXiang Li } 23241f0574cSXiang Li } 23341f0574cSXiang Li 234c123d0c1SHelena Kotas if (!HasPackOffset) 235c123d0c1SHelena Kotas return; 23641f0574cSXiang Li 237c123d0c1SHelena Kotas if (HasNonPackOffset) 238c123d0c1SHelena Kotas S.Diag(BufDecl->getLocation(), diag::warn_hlsl_packoffset_mix); 239c123d0c1SHelena Kotas 240c123d0c1SHelena Kotas // Make sure there is no overlap in packoffset - sort PackOffsetVec by offset 241c123d0c1SHelena Kotas // and compare adjacent values. 242c123d0c1SHelena Kotas ASTContext &Context = S.getASTContext(); 24341f0574cSXiang Li std::sort(PackOffsetVec.begin(), PackOffsetVec.end(), 24441f0574cSXiang Li [](const std::pair<VarDecl *, HLSLPackOffsetAttr *> &LHS, 24541f0574cSXiang Li const std::pair<VarDecl *, HLSLPackOffsetAttr *> &RHS) { 246c123d0c1SHelena Kotas return LHS.second->getOffsetInBytes() < 247c123d0c1SHelena Kotas RHS.second->getOffsetInBytes(); 24841f0574cSXiang Li }); 24941f0574cSXiang Li for (unsigned i = 0; i < PackOffsetVec.size() - 1; i++) { 25041f0574cSXiang Li VarDecl *Var = PackOffsetVec[i].first; 25141f0574cSXiang Li HLSLPackOffsetAttr *Attr = PackOffsetVec[i].second; 25241f0574cSXiang Li unsigned Size = calculateLegacyCbufferSize(Context, Var->getType()); 253c123d0c1SHelena Kotas unsigned Begin = Attr->getOffsetInBytes(); 25441f0574cSXiang Li unsigned End = Begin + Size; 255c123d0c1SHelena Kotas unsigned NextBegin = PackOffsetVec[i + 1].second->getOffsetInBytes(); 25641f0574cSXiang Li if (End > NextBegin) { 25741f0574cSXiang Li VarDecl *NextVar = PackOffsetVec[i + 1].first; 258c123d0c1SHelena Kotas S.Diag(NextVar->getLocation(), diag::err_hlsl_packoffset_overlap) 25941f0574cSXiang Li << NextVar << Var; 26041f0574cSXiang Li } 26141f0574cSXiang Li } 26241f0574cSXiang Li } 26341f0574cSXiang Li 264825e7129SHelena Kotas // Returns true if the array has a zero size = if any of the dimensions is 0 265825e7129SHelena Kotas static bool isZeroSizedArray(const ConstantArrayType *CAT) { 266825e7129SHelena Kotas while (CAT && !CAT->isZeroSize()) 267825e7129SHelena Kotas CAT = dyn_cast<ConstantArrayType>( 268825e7129SHelena Kotas CAT->getElementType()->getUnqualifiedDesugaredType()); 269825e7129SHelena Kotas return CAT != nullptr; 270825e7129SHelena Kotas } 271825e7129SHelena Kotas 272825e7129SHelena Kotas // Returns true if the record type is an HLSL resource class 273825e7129SHelena Kotas static bool isResourceRecordType(const Type *Ty) { 274825e7129SHelena Kotas return HLSLAttributedResourceType::findHandleTypeOnResource(Ty) != nullptr; 275825e7129SHelena Kotas } 276825e7129SHelena Kotas 277825e7129SHelena Kotas // Returns true if the type is a leaf element type that is not valid to be 278825e7129SHelena Kotas // included in HLSL Buffer, such as a resource class, empty struct, zero-sized 279825e7129SHelena Kotas // array, or a builtin intangible type. Returns false it is a valid leaf element 280825e7129SHelena Kotas // type or if it is a record type that needs to be inspected further. 281825e7129SHelena Kotas static bool isInvalidConstantBufferLeafElementType(const Type *Ty) { 282825e7129SHelena Kotas if (Ty->isRecordType()) { 283825e7129SHelena Kotas if (isResourceRecordType(Ty) || Ty->getAsCXXRecordDecl()->isEmpty()) 284825e7129SHelena Kotas return true; 285825e7129SHelena Kotas return false; 286825e7129SHelena Kotas } 287825e7129SHelena Kotas if (Ty->isConstantArrayType() && 288825e7129SHelena Kotas isZeroSizedArray(cast<ConstantArrayType>(Ty))) 289825e7129SHelena Kotas return true; 290825e7129SHelena Kotas if (Ty->isHLSLBuiltinIntangibleType()) 291825e7129SHelena Kotas return true; 292825e7129SHelena Kotas return false; 293825e7129SHelena Kotas } 294825e7129SHelena Kotas 295825e7129SHelena Kotas // Returns true if the struct contains at least one element that prevents it 296825e7129SHelena Kotas // from being included inside HLSL Buffer as is, such as an intangible type, 297825e7129SHelena Kotas // empty struct, or zero-sized array. If it does, a new implicit layout struct 298825e7129SHelena Kotas // needs to be created for HLSL Buffer use that will exclude these unwanted 299825e7129SHelena Kotas // declarations (see createHostLayoutStruct function). 300825e7129SHelena Kotas static bool requiresImplicitBufferLayoutStructure(const CXXRecordDecl *RD) { 301825e7129SHelena Kotas if (RD->getTypeForDecl()->isHLSLIntangibleType() || RD->isEmpty()) 302825e7129SHelena Kotas return true; 303825e7129SHelena Kotas // check fields 304825e7129SHelena Kotas for (const FieldDecl *Field : RD->fields()) { 305825e7129SHelena Kotas QualType Ty = Field->getType(); 306825e7129SHelena Kotas if (isInvalidConstantBufferLeafElementType(Ty.getTypePtr())) 307825e7129SHelena Kotas return true; 308825e7129SHelena Kotas if (Ty->isRecordType() && 309825e7129SHelena Kotas requiresImplicitBufferLayoutStructure(Ty->getAsCXXRecordDecl())) 310825e7129SHelena Kotas return true; 311825e7129SHelena Kotas } 312825e7129SHelena Kotas // check bases 313825e7129SHelena Kotas for (const CXXBaseSpecifier &Base : RD->bases()) 314825e7129SHelena Kotas if (requiresImplicitBufferLayoutStructure( 315825e7129SHelena Kotas Base.getType()->getAsCXXRecordDecl())) 316825e7129SHelena Kotas return true; 317825e7129SHelena Kotas return false; 318825e7129SHelena Kotas } 319825e7129SHelena Kotas 320825e7129SHelena Kotas static CXXRecordDecl *findRecordDeclInContext(IdentifierInfo *II, 321825e7129SHelena Kotas DeclContext *DC) { 322825e7129SHelena Kotas CXXRecordDecl *RD = nullptr; 323825e7129SHelena Kotas for (NamedDecl *Decl : 324825e7129SHelena Kotas DC->getNonTransparentContext()->lookup(DeclarationName(II))) { 325825e7129SHelena Kotas if (CXXRecordDecl *FoundRD = dyn_cast<CXXRecordDecl>(Decl)) { 326825e7129SHelena Kotas assert(RD == nullptr && 327825e7129SHelena Kotas "there should be at most 1 record by a given name in a scope"); 328825e7129SHelena Kotas RD = FoundRD; 329825e7129SHelena Kotas } 330825e7129SHelena Kotas } 331825e7129SHelena Kotas return RD; 332825e7129SHelena Kotas } 333825e7129SHelena Kotas 334825e7129SHelena Kotas // Creates a name for buffer layout struct using the provide name base. 335825e7129SHelena Kotas // If the name must be unique (not previously defined), a suffix is added 336825e7129SHelena Kotas // until a unique name is found. 337825e7129SHelena Kotas static IdentifierInfo *getHostLayoutStructName(Sema &S, NamedDecl *BaseDecl, 338825e7129SHelena Kotas bool MustBeUnique) { 339825e7129SHelena Kotas ASTContext &AST = S.getASTContext(); 340825e7129SHelena Kotas 341825e7129SHelena Kotas IdentifierInfo *NameBaseII = BaseDecl->getIdentifier(); 342825e7129SHelena Kotas llvm::SmallString<64> Name("__layout_"); 343825e7129SHelena Kotas if (NameBaseII) { 344825e7129SHelena Kotas Name.append(NameBaseII->getName()); 345825e7129SHelena Kotas } else { 346825e7129SHelena Kotas // anonymous struct 347825e7129SHelena Kotas Name.append("anon"); 348825e7129SHelena Kotas MustBeUnique = true; 349825e7129SHelena Kotas } 350825e7129SHelena Kotas 351825e7129SHelena Kotas size_t NameLength = Name.size(); 352825e7129SHelena Kotas IdentifierInfo *II = &AST.Idents.get(Name, tok::TokenKind::identifier); 353825e7129SHelena Kotas if (!MustBeUnique) 354825e7129SHelena Kotas return II; 355825e7129SHelena Kotas 356825e7129SHelena Kotas unsigned suffix = 0; 357825e7129SHelena Kotas while (true) { 358825e7129SHelena Kotas if (suffix != 0) { 359825e7129SHelena Kotas Name.append("_"); 360825e7129SHelena Kotas Name.append(llvm::Twine(suffix).str()); 361825e7129SHelena Kotas II = &AST.Idents.get(Name, tok::TokenKind::identifier); 362825e7129SHelena Kotas } 363825e7129SHelena Kotas if (!findRecordDeclInContext(II, BaseDecl->getDeclContext())) 364825e7129SHelena Kotas return II; 365825e7129SHelena Kotas // declaration with that name already exists - increment suffix and try 366825e7129SHelena Kotas // again until unique name is found 367825e7129SHelena Kotas suffix++; 368825e7129SHelena Kotas Name.truncate(NameLength); 369825e7129SHelena Kotas }; 370825e7129SHelena Kotas } 371825e7129SHelena Kotas 372825e7129SHelena Kotas // Creates a field declaration of given name and type for HLSL buffer layout 373825e7129SHelena Kotas // struct. Returns nullptr if the type cannot be use in HLSL Buffer layout. 374825e7129SHelena Kotas static FieldDecl *createFieldForHostLayoutStruct(Sema &S, const Type *Ty, 375825e7129SHelena Kotas IdentifierInfo *II, 376825e7129SHelena Kotas CXXRecordDecl *LayoutStruct) { 377825e7129SHelena Kotas if (isInvalidConstantBufferLeafElementType(Ty)) 378825e7129SHelena Kotas return nullptr; 379825e7129SHelena Kotas 380825e7129SHelena Kotas if (Ty->isRecordType()) { 381825e7129SHelena Kotas CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); 382825e7129SHelena Kotas if (requiresImplicitBufferLayoutStructure(RD)) { 383825e7129SHelena Kotas RD = createHostLayoutStruct(S, RD); 384825e7129SHelena Kotas if (!RD) 385825e7129SHelena Kotas return nullptr; 386825e7129SHelena Kotas Ty = RD->getTypeForDecl(); 387825e7129SHelena Kotas } 388825e7129SHelena Kotas } 389825e7129SHelena Kotas 390825e7129SHelena Kotas QualType QT = QualType(Ty, 0); 391825e7129SHelena Kotas ASTContext &AST = S.getASTContext(); 392825e7129SHelena Kotas TypeSourceInfo *TSI = AST.getTrivialTypeSourceInfo(QT, SourceLocation()); 393825e7129SHelena Kotas auto *Field = FieldDecl::Create(AST, LayoutStruct, SourceLocation(), 394825e7129SHelena Kotas SourceLocation(), II, QT, TSI, nullptr, false, 395825e7129SHelena Kotas InClassInitStyle::ICIS_NoInit); 396825e7129SHelena Kotas Field->setAccess(AccessSpecifier::AS_private); 397825e7129SHelena Kotas return Field; 398825e7129SHelena Kotas } 399825e7129SHelena Kotas 400825e7129SHelena Kotas // Creates host layout struct for a struct included in HLSL Buffer. 401825e7129SHelena Kotas // The layout struct will include only fields that are allowed in HLSL buffer. 402825e7129SHelena Kotas // These fields will be filtered out: 403825e7129SHelena Kotas // - resource classes 404825e7129SHelena Kotas // - empty structs 405825e7129SHelena Kotas // - zero-sized arrays 406825e7129SHelena Kotas // Returns nullptr if the resulting layout struct would be empty. 407825e7129SHelena Kotas static CXXRecordDecl *createHostLayoutStruct(Sema &S, 408825e7129SHelena Kotas CXXRecordDecl *StructDecl) { 409825e7129SHelena Kotas assert(requiresImplicitBufferLayoutStructure(StructDecl) && 410825e7129SHelena Kotas "struct is already HLSL buffer compatible"); 411825e7129SHelena Kotas 412825e7129SHelena Kotas ASTContext &AST = S.getASTContext(); 413825e7129SHelena Kotas DeclContext *DC = StructDecl->getDeclContext(); 414825e7129SHelena Kotas IdentifierInfo *II = getHostLayoutStructName(S, StructDecl, false); 415825e7129SHelena Kotas 416825e7129SHelena Kotas // reuse existing if the layout struct if it already exists 417825e7129SHelena Kotas if (CXXRecordDecl *RD = findRecordDeclInContext(II, DC)) 418825e7129SHelena Kotas return RD; 419825e7129SHelena Kotas 420825e7129SHelena Kotas CXXRecordDecl *LS = CXXRecordDecl::Create( 421825e7129SHelena Kotas AST, TagDecl::TagKind::Class, DC, SourceLocation(), SourceLocation(), II); 422825e7129SHelena Kotas LS->setImplicit(true); 423825e7129SHelena Kotas LS->startDefinition(); 424825e7129SHelena Kotas 425825e7129SHelena Kotas // copy base struct, create HLSL Buffer compatible version if needed 426825e7129SHelena Kotas if (unsigned NumBases = StructDecl->getNumBases()) { 427825e7129SHelena Kotas assert(NumBases == 1 && "HLSL supports only one base type"); 4287974f12bSNAKAMURA Takumi (void)NumBases; 429825e7129SHelena Kotas CXXBaseSpecifier Base = *StructDecl->bases_begin(); 430825e7129SHelena Kotas CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl(); 431825e7129SHelena Kotas if (requiresImplicitBufferLayoutStructure(BaseDecl)) { 432825e7129SHelena Kotas BaseDecl = createHostLayoutStruct(S, BaseDecl); 433825e7129SHelena Kotas if (BaseDecl) { 434825e7129SHelena Kotas TypeSourceInfo *TSI = AST.getTrivialTypeSourceInfo( 435825e7129SHelena Kotas QualType(BaseDecl->getTypeForDecl(), 0)); 436825e7129SHelena Kotas Base = CXXBaseSpecifier(SourceRange(), false, StructDecl->isClass(), 437825e7129SHelena Kotas AS_none, TSI, SourceLocation()); 438825e7129SHelena Kotas } 439825e7129SHelena Kotas } 440825e7129SHelena Kotas if (BaseDecl) { 441825e7129SHelena Kotas const CXXBaseSpecifier *BasesArray[1] = {&Base}; 442825e7129SHelena Kotas LS->setBases(BasesArray, 1); 443825e7129SHelena Kotas } 444825e7129SHelena Kotas } 445825e7129SHelena Kotas 446825e7129SHelena Kotas // filter struct fields 447825e7129SHelena Kotas for (const FieldDecl *FD : StructDecl->fields()) { 448825e7129SHelena Kotas const Type *Ty = FD->getType()->getUnqualifiedDesugaredType(); 449825e7129SHelena Kotas if (FieldDecl *NewFD = 450825e7129SHelena Kotas createFieldForHostLayoutStruct(S, Ty, FD->getIdentifier(), LS)) 451825e7129SHelena Kotas LS->addDecl(NewFD); 452825e7129SHelena Kotas } 453825e7129SHelena Kotas LS->completeDefinition(); 454825e7129SHelena Kotas 455825e7129SHelena Kotas if (LS->field_empty() && LS->getNumBases() == 0) 456825e7129SHelena Kotas return nullptr; 457825e7129SHelena Kotas 458825e7129SHelena Kotas DC->addDecl(LS); 459825e7129SHelena Kotas return LS; 460825e7129SHelena Kotas } 461825e7129SHelena Kotas 462825e7129SHelena Kotas // Creates host layout struct for HLSL Buffer. The struct will include only 463825e7129SHelena Kotas // fields of types that are allowed in HLSL buffer and it will filter out: 464825e7129SHelena Kotas // - static variable declarations 465825e7129SHelena Kotas // - resource classes 466825e7129SHelena Kotas // - empty structs 467825e7129SHelena Kotas // - zero-sized arrays 468825e7129SHelena Kotas // - non-variable declarations 469825e7129SHelena Kotas // The layour struct will be added to the HLSLBufferDecl declarations. 470825e7129SHelena Kotas void createHostLayoutStructForBuffer(Sema &S, HLSLBufferDecl *BufDecl) { 471825e7129SHelena Kotas ASTContext &AST = S.getASTContext(); 472825e7129SHelena Kotas IdentifierInfo *II = getHostLayoutStructName(S, BufDecl, true); 473825e7129SHelena Kotas 474825e7129SHelena Kotas CXXRecordDecl *LS = 475825e7129SHelena Kotas CXXRecordDecl::Create(AST, TagDecl::TagKind::Class, BufDecl, 476825e7129SHelena Kotas SourceLocation(), SourceLocation(), II); 477825e7129SHelena Kotas LS->setImplicit(true); 478825e7129SHelena Kotas LS->startDefinition(); 479825e7129SHelena Kotas 480d92bac8aSHelena Kotas for (Decl *D : BufDecl->decls()) { 481d92bac8aSHelena Kotas VarDecl *VD = dyn_cast<VarDecl>(D); 482825e7129SHelena Kotas if (!VD || VD->getStorageClass() == SC_Static) 483825e7129SHelena Kotas continue; 484825e7129SHelena Kotas const Type *Ty = VD->getType()->getUnqualifiedDesugaredType(); 485825e7129SHelena Kotas if (FieldDecl *FD = 486d92bac8aSHelena Kotas createFieldForHostLayoutStruct(S, Ty, VD->getIdentifier(), LS)) { 487d92bac8aSHelena Kotas // add the field decl to the layout struct 488825e7129SHelena Kotas LS->addDecl(FD); 489d92bac8aSHelena Kotas // update address space of the original decl to hlsl_constant 490d92bac8aSHelena Kotas QualType NewTy = 491d92bac8aSHelena Kotas AST.getAddrSpaceQualType(VD->getType(), LangAS::hlsl_constant); 492d92bac8aSHelena Kotas VD->setType(NewTy); 493d92bac8aSHelena Kotas } 494825e7129SHelena Kotas } 495825e7129SHelena Kotas LS->completeDefinition(); 496825e7129SHelena Kotas BufDecl->addDecl(LS); 497825e7129SHelena Kotas } 498825e7129SHelena Kotas 499825e7129SHelena Kotas // Handle end of cbuffer/tbuffer declaration 500c123d0c1SHelena Kotas void SemaHLSL::ActOnFinishBuffer(Decl *Dcl, SourceLocation RBrace) { 501c123d0c1SHelena Kotas auto *BufDecl = cast<HLSLBufferDecl>(Dcl); 502c123d0c1SHelena Kotas BufDecl->setRBraceLoc(RBrace); 503c123d0c1SHelena Kotas 504c123d0c1SHelena Kotas validatePackoffset(SemaRef, BufDecl); 505c123d0c1SHelena Kotas 506825e7129SHelena Kotas // create buffer layout struct 507825e7129SHelena Kotas createHostLayoutStructForBuffer(SemaRef, BufDecl); 508825e7129SHelena Kotas 509d345f6a2SVlad Serebrennikov SemaRef.PopDeclContext(); 510782ac218SXiang Li } 511b45c9c31SVlad Serebrennikov 512b45c9c31SVlad Serebrennikov HLSLNumThreadsAttr *SemaHLSL::mergeNumThreadsAttr(Decl *D, 513b45c9c31SVlad Serebrennikov const AttributeCommonInfo &AL, 514b45c9c31SVlad Serebrennikov int X, int Y, int Z) { 515b45c9c31SVlad Serebrennikov if (HLSLNumThreadsAttr *NT = D->getAttr<HLSLNumThreadsAttr>()) { 516b45c9c31SVlad Serebrennikov if (NT->getX() != X || NT->getY() != Y || NT->getZ() != Z) { 517b45c9c31SVlad Serebrennikov Diag(NT->getLocation(), diag::err_hlsl_attribute_param_mismatch) << AL; 518b45c9c31SVlad Serebrennikov Diag(AL.getLoc(), diag::note_conflicting_attribute); 519b45c9c31SVlad Serebrennikov } 520b45c9c31SVlad Serebrennikov return nullptr; 521b45c9c31SVlad Serebrennikov } 522b45c9c31SVlad Serebrennikov return ::new (getASTContext()) 523b45c9c31SVlad Serebrennikov HLSLNumThreadsAttr(getASTContext(), AL, X, Y, Z); 524b45c9c31SVlad Serebrennikov } 525b45c9c31SVlad Serebrennikov 526e41579a3SXiang Li HLSLWaveSizeAttr *SemaHLSL::mergeWaveSizeAttr(Decl *D, 527e41579a3SXiang Li const AttributeCommonInfo &AL, 528e41579a3SXiang Li int Min, int Max, int Preferred, 529e41579a3SXiang Li int SpelledArgsCount) { 530e41579a3SXiang Li if (HLSLWaveSizeAttr *WS = D->getAttr<HLSLWaveSizeAttr>()) { 531e41579a3SXiang Li if (WS->getMin() != Min || WS->getMax() != Max || 532e41579a3SXiang Li WS->getPreferred() != Preferred || 533e41579a3SXiang Li WS->getSpelledArgsCount() != SpelledArgsCount) { 534e41579a3SXiang Li Diag(WS->getLocation(), diag::err_hlsl_attribute_param_mismatch) << AL; 535e41579a3SXiang Li Diag(AL.getLoc(), diag::note_conflicting_attribute); 536e41579a3SXiang Li } 537e41579a3SXiang Li return nullptr; 538e41579a3SXiang Li } 539e41579a3SXiang Li HLSLWaveSizeAttr *Result = ::new (getASTContext()) 540e41579a3SXiang Li HLSLWaveSizeAttr(getASTContext(), AL, Min, Max, Preferred); 541e41579a3SXiang Li Result->setSpelledArgsCount(SpelledArgsCount); 542e41579a3SXiang Li return Result; 543e41579a3SXiang Li } 544e41579a3SXiang Li 545b45c9c31SVlad Serebrennikov HLSLShaderAttr * 546b45c9c31SVlad Serebrennikov SemaHLSL::mergeShaderAttr(Decl *D, const AttributeCommonInfo &AL, 5475d87ba1cSHelena Kotas llvm::Triple::EnvironmentType ShaderType) { 548b45c9c31SVlad Serebrennikov if (HLSLShaderAttr *NT = D->getAttr<HLSLShaderAttr>()) { 549b45c9c31SVlad Serebrennikov if (NT->getType() != ShaderType) { 550b45c9c31SVlad Serebrennikov Diag(NT->getLocation(), diag::err_hlsl_attribute_param_mismatch) << AL; 551b45c9c31SVlad Serebrennikov Diag(AL.getLoc(), diag::note_conflicting_attribute); 552b45c9c31SVlad Serebrennikov } 553b45c9c31SVlad Serebrennikov return nullptr; 554b45c9c31SVlad Serebrennikov } 555b45c9c31SVlad Serebrennikov return HLSLShaderAttr::Create(getASTContext(), ShaderType, AL); 556b45c9c31SVlad Serebrennikov } 557b45c9c31SVlad Serebrennikov 558b45c9c31SVlad Serebrennikov HLSLParamModifierAttr * 559b45c9c31SVlad Serebrennikov SemaHLSL::mergeParamModifierAttr(Decl *D, const AttributeCommonInfo &AL, 560b45c9c31SVlad Serebrennikov HLSLParamModifierAttr::Spelling Spelling) { 561b45c9c31SVlad Serebrennikov // We can only merge an `in` attribute with an `out` attribute. All other 562b45c9c31SVlad Serebrennikov // combinations of duplicated attributes are ill-formed. 563b45c9c31SVlad Serebrennikov if (HLSLParamModifierAttr *PA = D->getAttr<HLSLParamModifierAttr>()) { 564b45c9c31SVlad Serebrennikov if ((PA->isIn() && Spelling == HLSLParamModifierAttr::Keyword_out) || 565b45c9c31SVlad Serebrennikov (PA->isOut() && Spelling == HLSLParamModifierAttr::Keyword_in)) { 566b45c9c31SVlad Serebrennikov D->dropAttr<HLSLParamModifierAttr>(); 567b45c9c31SVlad Serebrennikov SourceRange AdjustedRange = {PA->getLocation(), AL.getRange().getEnd()}; 568b45c9c31SVlad Serebrennikov return HLSLParamModifierAttr::Create( 569b45c9c31SVlad Serebrennikov getASTContext(), /*MergedSpelling=*/true, AdjustedRange, 570b45c9c31SVlad Serebrennikov HLSLParamModifierAttr::Keyword_inout); 571b45c9c31SVlad Serebrennikov } 572b45c9c31SVlad Serebrennikov Diag(AL.getLoc(), diag::err_hlsl_duplicate_parameter_modifier) << AL; 573b45c9c31SVlad Serebrennikov Diag(PA->getLocation(), diag::note_conflicting_attribute); 574b45c9c31SVlad Serebrennikov return nullptr; 575b45c9c31SVlad Serebrennikov } 576b45c9c31SVlad Serebrennikov return HLSLParamModifierAttr::Create(getASTContext(), AL); 577b45c9c31SVlad Serebrennikov } 578b45c9c31SVlad Serebrennikov 579b45c9c31SVlad Serebrennikov void SemaHLSL::ActOnTopLevelFunction(FunctionDecl *FD) { 580b45c9c31SVlad Serebrennikov auto &TargetInfo = getASTContext().getTargetInfo(); 581b45c9c31SVlad Serebrennikov 582b45c9c31SVlad Serebrennikov if (FD->getName() != TargetInfo.getTargetOpts().HLSLEntry) 583b45c9c31SVlad Serebrennikov return; 584b45c9c31SVlad Serebrennikov 5855d87ba1cSHelena Kotas llvm::Triple::EnvironmentType Env = TargetInfo.getTriple().getEnvironment(); 5865d87ba1cSHelena Kotas if (HLSLShaderAttr::isValidShaderType(Env) && Env != llvm::Triple::Library) { 587b45c9c31SVlad Serebrennikov if (const auto *Shader = FD->getAttr<HLSLShaderAttr>()) { 588b45c9c31SVlad Serebrennikov // The entry point is already annotated - check that it matches the 589b45c9c31SVlad Serebrennikov // triple. 5905d87ba1cSHelena Kotas if (Shader->getType() != Env) { 591b45c9c31SVlad Serebrennikov Diag(Shader->getLocation(), diag::err_hlsl_entry_shader_attr_mismatch) 592b45c9c31SVlad Serebrennikov << Shader; 593b45c9c31SVlad Serebrennikov FD->setInvalidDecl(); 594b45c9c31SVlad Serebrennikov } 595b45c9c31SVlad Serebrennikov } else { 596b45c9c31SVlad Serebrennikov // Implicitly add the shader attribute if the entry function isn't 597b45c9c31SVlad Serebrennikov // explicitly annotated. 5985d87ba1cSHelena Kotas FD->addAttr(HLSLShaderAttr::CreateImplicit(getASTContext(), Env, 599b45c9c31SVlad Serebrennikov FD->getBeginLoc())); 600b45c9c31SVlad Serebrennikov } 601b45c9c31SVlad Serebrennikov } else { 6025d87ba1cSHelena Kotas switch (Env) { 603b45c9c31SVlad Serebrennikov case llvm::Triple::UnknownEnvironment: 604b45c9c31SVlad Serebrennikov case llvm::Triple::Library: 605b45c9c31SVlad Serebrennikov break; 606b45c9c31SVlad Serebrennikov default: 607b45c9c31SVlad Serebrennikov llvm_unreachable("Unhandled environment in triple"); 608b45c9c31SVlad Serebrennikov } 609b45c9c31SVlad Serebrennikov } 610b45c9c31SVlad Serebrennikov } 611b45c9c31SVlad Serebrennikov 612b45c9c31SVlad Serebrennikov void SemaHLSL::CheckEntryPoint(FunctionDecl *FD) { 613b45c9c31SVlad Serebrennikov const auto *ShaderAttr = FD->getAttr<HLSLShaderAttr>(); 614b45c9c31SVlad Serebrennikov assert(ShaderAttr && "Entry point has no shader attribute"); 6155d87ba1cSHelena Kotas llvm::Triple::EnvironmentType ST = ShaderAttr->getType(); 616e41579a3SXiang Li auto &TargetInfo = getASTContext().getTargetInfo(); 617e41579a3SXiang Li VersionTuple Ver = TargetInfo.getTriple().getOSVersion(); 618b45c9c31SVlad Serebrennikov switch (ST) { 6195d87ba1cSHelena Kotas case llvm::Triple::Pixel: 6205d87ba1cSHelena Kotas case llvm::Triple::Vertex: 6215d87ba1cSHelena Kotas case llvm::Triple::Geometry: 6225d87ba1cSHelena Kotas case llvm::Triple::Hull: 6235d87ba1cSHelena Kotas case llvm::Triple::Domain: 6245d87ba1cSHelena Kotas case llvm::Triple::RayGeneration: 6255d87ba1cSHelena Kotas case llvm::Triple::Intersection: 6265d87ba1cSHelena Kotas case llvm::Triple::AnyHit: 6275d87ba1cSHelena Kotas case llvm::Triple::ClosestHit: 6285d87ba1cSHelena Kotas case llvm::Triple::Miss: 6295d87ba1cSHelena Kotas case llvm::Triple::Callable: 630b45c9c31SVlad Serebrennikov if (const auto *NT = FD->getAttr<HLSLNumThreadsAttr>()) { 631b45c9c31SVlad Serebrennikov DiagnoseAttrStageMismatch(NT, ST, 6325d87ba1cSHelena Kotas {llvm::Triple::Compute, 6335d87ba1cSHelena Kotas llvm::Triple::Amplification, 6345d87ba1cSHelena Kotas llvm::Triple::Mesh}); 635b45c9c31SVlad Serebrennikov FD->setInvalidDecl(); 636b45c9c31SVlad Serebrennikov } 637e41579a3SXiang Li if (const auto *WS = FD->getAttr<HLSLWaveSizeAttr>()) { 638e41579a3SXiang Li DiagnoseAttrStageMismatch(WS, ST, 639e41579a3SXiang Li {llvm::Triple::Compute, 640e41579a3SXiang Li llvm::Triple::Amplification, 641e41579a3SXiang Li llvm::Triple::Mesh}); 642e41579a3SXiang Li FD->setInvalidDecl(); 643e41579a3SXiang Li } 644b45c9c31SVlad Serebrennikov break; 645b45c9c31SVlad Serebrennikov 6465d87ba1cSHelena Kotas case llvm::Triple::Compute: 6475d87ba1cSHelena Kotas case llvm::Triple::Amplification: 6485d87ba1cSHelena Kotas case llvm::Triple::Mesh: 649b45c9c31SVlad Serebrennikov if (!FD->hasAttr<HLSLNumThreadsAttr>()) { 650b45c9c31SVlad Serebrennikov Diag(FD->getLocation(), diag::err_hlsl_missing_numthreads) 6515d87ba1cSHelena Kotas << llvm::Triple::getEnvironmentTypeName(ST); 652b45c9c31SVlad Serebrennikov FD->setInvalidDecl(); 653b45c9c31SVlad Serebrennikov } 654e41579a3SXiang Li if (const auto *WS = FD->getAttr<HLSLWaveSizeAttr>()) { 655e41579a3SXiang Li if (Ver < VersionTuple(6, 6)) { 656e41579a3SXiang Li Diag(WS->getLocation(), diag::err_hlsl_attribute_in_wrong_shader_model) 657e41579a3SXiang Li << WS << "6.6"; 658e41579a3SXiang Li FD->setInvalidDecl(); 659e41579a3SXiang Li } else if (WS->getSpelledArgsCount() > 1 && Ver < VersionTuple(6, 8)) { 660e41579a3SXiang Li Diag( 661e41579a3SXiang Li WS->getLocation(), 662e41579a3SXiang Li diag::err_hlsl_attribute_number_arguments_insufficient_shader_model) 663e41579a3SXiang Li << WS << WS->getSpelledArgsCount() << "6.8"; 664e41579a3SXiang Li FD->setInvalidDecl(); 665e41579a3SXiang Li } 666e41579a3SXiang Li } 667b45c9c31SVlad Serebrennikov break; 6685d87ba1cSHelena Kotas default: 6695d87ba1cSHelena Kotas llvm_unreachable("Unhandled environment in triple"); 670b45c9c31SVlad Serebrennikov } 671b45c9c31SVlad Serebrennikov 672b45c9c31SVlad Serebrennikov for (ParmVarDecl *Param : FD->parameters()) { 673b45c9c31SVlad Serebrennikov if (const auto *AnnotationAttr = Param->getAttr<HLSLAnnotationAttr>()) { 674b45c9c31SVlad Serebrennikov CheckSemanticAnnotation(FD, Param, AnnotationAttr); 675b45c9c31SVlad Serebrennikov } else { 676b45c9c31SVlad Serebrennikov // FIXME: Handle struct parameters where annotations are on struct fields. 677b45c9c31SVlad Serebrennikov // See: https://github.com/llvm/llvm-project/issues/57875 678b45c9c31SVlad Serebrennikov Diag(FD->getLocation(), diag::err_hlsl_missing_semantic_annotation); 679b45c9c31SVlad Serebrennikov Diag(Param->getLocation(), diag::note_previous_decl) << Param; 680b45c9c31SVlad Serebrennikov FD->setInvalidDecl(); 681b45c9c31SVlad Serebrennikov } 682b45c9c31SVlad Serebrennikov } 683b45c9c31SVlad Serebrennikov // FIXME: Verify return type semantic annotation. 684b45c9c31SVlad Serebrennikov } 685b45c9c31SVlad Serebrennikov 686b45c9c31SVlad Serebrennikov void SemaHLSL::CheckSemanticAnnotation( 687b45c9c31SVlad Serebrennikov FunctionDecl *EntryPoint, const Decl *Param, 688b45c9c31SVlad Serebrennikov const HLSLAnnotationAttr *AnnotationAttr) { 689b45c9c31SVlad Serebrennikov auto *ShaderAttr = EntryPoint->getAttr<HLSLShaderAttr>(); 690b45c9c31SVlad Serebrennikov assert(ShaderAttr && "Entry point has no shader attribute"); 6915d87ba1cSHelena Kotas llvm::Triple::EnvironmentType ST = ShaderAttr->getType(); 692b45c9c31SVlad Serebrennikov 693b45c9c31SVlad Serebrennikov switch (AnnotationAttr->getKind()) { 694b45c9c31SVlad Serebrennikov case attr::HLSLSV_DispatchThreadID: 695b45c9c31SVlad Serebrennikov case attr::HLSLSV_GroupIndex: 696951a284fSZhengxing li case attr::HLSLSV_GroupThreadID: 6975fd4f32fSZhengxing li case attr::HLSLSV_GroupID: 6985d87ba1cSHelena Kotas if (ST == llvm::Triple::Compute) 699b45c9c31SVlad Serebrennikov return; 7005d87ba1cSHelena Kotas DiagnoseAttrStageMismatch(AnnotationAttr, ST, {llvm::Triple::Compute}); 701b45c9c31SVlad Serebrennikov break; 702b45c9c31SVlad Serebrennikov default: 703b45c9c31SVlad Serebrennikov llvm_unreachable("Unknown HLSLAnnotationAttr"); 704b45c9c31SVlad Serebrennikov } 705b45c9c31SVlad Serebrennikov } 706b45c9c31SVlad Serebrennikov 707b45c9c31SVlad Serebrennikov void SemaHLSL::DiagnoseAttrStageMismatch( 7085d87ba1cSHelena Kotas const Attr *A, llvm::Triple::EnvironmentType Stage, 7095d87ba1cSHelena Kotas std::initializer_list<llvm::Triple::EnvironmentType> AllowedStages) { 710b45c9c31SVlad Serebrennikov SmallVector<StringRef, 8> StageStrings; 711b45c9c31SVlad Serebrennikov llvm::transform(AllowedStages, std::back_inserter(StageStrings), 7125d87ba1cSHelena Kotas [](llvm::Triple::EnvironmentType ST) { 713b45c9c31SVlad Serebrennikov return StringRef( 7145d87ba1cSHelena Kotas HLSLShaderAttr::ConvertEnvironmentTypeToStr(ST)); 715b45c9c31SVlad Serebrennikov }); 716b45c9c31SVlad Serebrennikov Diag(A->getLoc(), diag::err_hlsl_attr_unsupported_in_stage) 7175d87ba1cSHelena Kotas << A << llvm::Triple::getEnvironmentTypeName(Stage) 718b45c9c31SVlad Serebrennikov << (AllowedStages.size() != 1) << join(StageStrings, ", "); 719b45c9c31SVlad Serebrennikov } 7208890209eSHelena Kotas 7214407cf95SChris B template <CastKind Kind> 7224407cf95SChris B static void castVector(Sema &S, ExprResult &E, QualType &Ty, unsigned Sz) { 7234407cf95SChris B if (const auto *VTy = Ty->getAs<VectorType>()) 7244407cf95SChris B Ty = VTy->getElementType(); 7254407cf95SChris B Ty = S.getASTContext().getExtVectorType(Ty, Sz); 7264407cf95SChris B E = S.ImpCastExprToType(E.get(), Ty, Kind); 7274407cf95SChris B } 7284407cf95SChris B 7294407cf95SChris B template <CastKind Kind> 7304407cf95SChris B static QualType castElement(Sema &S, ExprResult &E, QualType Ty) { 7314407cf95SChris B E = S.ImpCastExprToType(E.get(), Ty, Kind); 7324407cf95SChris B return Ty; 7334407cf95SChris B } 7344407cf95SChris B 7354407cf95SChris B static QualType handleFloatVectorBinOpConversion( 7364407cf95SChris B Sema &SemaRef, ExprResult &LHS, ExprResult &RHS, QualType LHSType, 7374407cf95SChris B QualType RHSType, QualType LElTy, QualType RElTy, bool IsCompAssign) { 7384407cf95SChris B bool LHSFloat = LElTy->isRealFloatingType(); 7394407cf95SChris B bool RHSFloat = RElTy->isRealFloatingType(); 7404407cf95SChris B 7414407cf95SChris B if (LHSFloat && RHSFloat) { 7424407cf95SChris B if (IsCompAssign || 7434407cf95SChris B SemaRef.getASTContext().getFloatingTypeOrder(LElTy, RElTy) > 0) 7444407cf95SChris B return castElement<CK_FloatingCast>(SemaRef, RHS, LHSType); 7454407cf95SChris B 7464407cf95SChris B return castElement<CK_FloatingCast>(SemaRef, LHS, RHSType); 7474407cf95SChris B } 7484407cf95SChris B 7494407cf95SChris B if (LHSFloat) 7504407cf95SChris B return castElement<CK_IntegralToFloating>(SemaRef, RHS, LHSType); 7514407cf95SChris B 7524407cf95SChris B assert(RHSFloat); 7534407cf95SChris B if (IsCompAssign) 7544407cf95SChris B return castElement<clang::CK_FloatingToIntegral>(SemaRef, RHS, LHSType); 7554407cf95SChris B 7564407cf95SChris B return castElement<CK_IntegralToFloating>(SemaRef, LHS, RHSType); 7574407cf95SChris B } 7584407cf95SChris B 7594407cf95SChris B static QualType handleIntegerVectorBinOpConversion( 7604407cf95SChris B Sema &SemaRef, ExprResult &LHS, ExprResult &RHS, QualType LHSType, 7614407cf95SChris B QualType RHSType, QualType LElTy, QualType RElTy, bool IsCompAssign) { 7624407cf95SChris B 7634407cf95SChris B int IntOrder = SemaRef.Context.getIntegerTypeOrder(LElTy, RElTy); 7644407cf95SChris B bool LHSSigned = LElTy->hasSignedIntegerRepresentation(); 7654407cf95SChris B bool RHSSigned = RElTy->hasSignedIntegerRepresentation(); 7664407cf95SChris B auto &Ctx = SemaRef.getASTContext(); 7674407cf95SChris B 7684407cf95SChris B // If both types have the same signedness, use the higher ranked type. 7694407cf95SChris B if (LHSSigned == RHSSigned) { 7704407cf95SChris B if (IsCompAssign || IntOrder >= 0) 7714407cf95SChris B return castElement<CK_IntegralCast>(SemaRef, RHS, LHSType); 7724407cf95SChris B 7734407cf95SChris B return castElement<CK_IntegralCast>(SemaRef, LHS, RHSType); 7744407cf95SChris B } 7754407cf95SChris B 7764407cf95SChris B // If the unsigned type has greater than or equal rank of the signed type, use 7774407cf95SChris B // the unsigned type. 7784407cf95SChris B if (IntOrder != (LHSSigned ? 1 : -1)) { 7794407cf95SChris B if (IsCompAssign || RHSSigned) 7804407cf95SChris B return castElement<CK_IntegralCast>(SemaRef, RHS, LHSType); 7814407cf95SChris B return castElement<CK_IntegralCast>(SemaRef, LHS, RHSType); 7824407cf95SChris B } 7834407cf95SChris B 7844407cf95SChris B // At this point the signed type has higher rank than the unsigned type, which 7854407cf95SChris B // means it will be the same size or bigger. If the signed type is bigger, it 7864407cf95SChris B // can represent all the values of the unsigned type, so select it. 7874407cf95SChris B if (Ctx.getIntWidth(LElTy) != Ctx.getIntWidth(RElTy)) { 7884407cf95SChris B if (IsCompAssign || LHSSigned) 7894407cf95SChris B return castElement<CK_IntegralCast>(SemaRef, RHS, LHSType); 7904407cf95SChris B return castElement<CK_IntegralCast>(SemaRef, LHS, RHSType); 7914407cf95SChris B } 7924407cf95SChris B 7934407cf95SChris B // This is a bit of an odd duck case in HLSL. It shouldn't happen, but can due 7944407cf95SChris B // to C/C++ leaking through. The place this happens today is long vs long 7954407cf95SChris B // long. When arguments are vector<unsigned long, N> and vector<long long, N>, 7964407cf95SChris B // the long long has higher rank than long even though they are the same size. 7974407cf95SChris B 7984407cf95SChris B // If this is a compound assignment cast the right hand side to the left hand 7994407cf95SChris B // side's type. 8004407cf95SChris B if (IsCompAssign) 8014407cf95SChris B return castElement<CK_IntegralCast>(SemaRef, RHS, LHSType); 8024407cf95SChris B 8034407cf95SChris B // If this isn't a compound assignment we convert to unsigned long long. 8044407cf95SChris B QualType ElTy = Ctx.getCorrespondingUnsignedType(LHSSigned ? LElTy : RElTy); 8054407cf95SChris B QualType NewTy = Ctx.getExtVectorType( 8064407cf95SChris B ElTy, RHSType->castAs<VectorType>()->getNumElements()); 8074407cf95SChris B (void)castElement<CK_IntegralCast>(SemaRef, RHS, NewTy); 8084407cf95SChris B 8094407cf95SChris B return castElement<CK_IntegralCast>(SemaRef, LHS, NewTy); 8104407cf95SChris B } 8114407cf95SChris B 8124407cf95SChris B static CastKind getScalarCastKind(ASTContext &Ctx, QualType DestTy, 8134407cf95SChris B QualType SrcTy) { 8144407cf95SChris B if (DestTy->isRealFloatingType() && SrcTy->isRealFloatingType()) 8154407cf95SChris B return CK_FloatingCast; 8164407cf95SChris B if (DestTy->isIntegralType(Ctx) && SrcTy->isIntegralType(Ctx)) 8174407cf95SChris B return CK_IntegralCast; 8184407cf95SChris B if (DestTy->isRealFloatingType()) 8194407cf95SChris B return CK_IntegralToFloating; 8204407cf95SChris B assert(SrcTy->isRealFloatingType() && DestTy->isIntegralType(Ctx)); 8214407cf95SChris B return CK_FloatingToIntegral; 8224407cf95SChris B } 8234407cf95SChris B 8244407cf95SChris B QualType SemaHLSL::handleVectorBinOpConversion(ExprResult &LHS, ExprResult &RHS, 8254407cf95SChris B QualType LHSType, 8264407cf95SChris B QualType RHSType, 8274407cf95SChris B bool IsCompAssign) { 8284407cf95SChris B const auto *LVecTy = LHSType->getAs<VectorType>(); 8294407cf95SChris B const auto *RVecTy = RHSType->getAs<VectorType>(); 8304407cf95SChris B auto &Ctx = getASTContext(); 8314407cf95SChris B 8324407cf95SChris B // If the LHS is not a vector and this is a compound assignment, we truncate 8334407cf95SChris B // the argument to a scalar then convert it to the LHS's type. 8344407cf95SChris B if (!LVecTy && IsCompAssign) { 8354407cf95SChris B QualType RElTy = RHSType->castAs<VectorType>()->getElementType(); 8364407cf95SChris B RHS = SemaRef.ImpCastExprToType(RHS.get(), RElTy, CK_HLSLVectorTruncation); 8374407cf95SChris B RHSType = RHS.get()->getType(); 8384407cf95SChris B if (Ctx.hasSameUnqualifiedType(LHSType, RHSType)) 8394407cf95SChris B return LHSType; 8404407cf95SChris B RHS = SemaRef.ImpCastExprToType(RHS.get(), LHSType, 8414407cf95SChris B getScalarCastKind(Ctx, LHSType, RHSType)); 8424407cf95SChris B return LHSType; 8434407cf95SChris B } 8444407cf95SChris B 8454407cf95SChris B unsigned EndSz = std::numeric_limits<unsigned>::max(); 8464407cf95SChris B unsigned LSz = 0; 8474407cf95SChris B if (LVecTy) 8484407cf95SChris B LSz = EndSz = LVecTy->getNumElements(); 8494407cf95SChris B if (RVecTy) 8504407cf95SChris B EndSz = std::min(RVecTy->getNumElements(), EndSz); 8514407cf95SChris B assert(EndSz != std::numeric_limits<unsigned>::max() && 8524407cf95SChris B "one of the above should have had a value"); 8534407cf95SChris B 8544407cf95SChris B // In a compound assignment, the left operand does not change type, the right 8554407cf95SChris B // operand is converted to the type of the left operand. 8564407cf95SChris B if (IsCompAssign && LSz != EndSz) { 8574407cf95SChris B Diag(LHS.get()->getBeginLoc(), 8584407cf95SChris B diag::err_hlsl_vector_compound_assignment_truncation) 8594407cf95SChris B << LHSType << RHSType; 8604407cf95SChris B return QualType(); 8614407cf95SChris B } 8624407cf95SChris B 8634407cf95SChris B if (RVecTy && RVecTy->getNumElements() > EndSz) 8644407cf95SChris B castVector<CK_HLSLVectorTruncation>(SemaRef, RHS, RHSType, EndSz); 8654407cf95SChris B if (!IsCompAssign && LVecTy && LVecTy->getNumElements() > EndSz) 8664407cf95SChris B castVector<CK_HLSLVectorTruncation>(SemaRef, LHS, LHSType, EndSz); 8674407cf95SChris B 8684407cf95SChris B if (!RVecTy) 8694407cf95SChris B castVector<CK_VectorSplat>(SemaRef, RHS, RHSType, EndSz); 8704407cf95SChris B if (!IsCompAssign && !LVecTy) 8714407cf95SChris B castVector<CK_VectorSplat>(SemaRef, LHS, LHSType, EndSz); 8724407cf95SChris B 8734407cf95SChris B // If we're at the same type after resizing we can stop here. 8744407cf95SChris B if (Ctx.hasSameUnqualifiedType(LHSType, RHSType)) 8754407cf95SChris B return Ctx.getCommonSugaredType(LHSType, RHSType); 8764407cf95SChris B 8774407cf95SChris B QualType LElTy = LHSType->castAs<VectorType>()->getElementType(); 8784407cf95SChris B QualType RElTy = RHSType->castAs<VectorType>()->getElementType(); 8794407cf95SChris B 8804407cf95SChris B // Handle conversion for floating point vectors. 8814407cf95SChris B if (LElTy->isRealFloatingType() || RElTy->isRealFloatingType()) 8824407cf95SChris B return handleFloatVectorBinOpConversion(SemaRef, LHS, RHS, LHSType, RHSType, 8834407cf95SChris B LElTy, RElTy, IsCompAssign); 8844407cf95SChris B 8854407cf95SChris B assert(LElTy->isIntegralType(Ctx) && RElTy->isIntegralType(Ctx) && 8864407cf95SChris B "HLSL Vectors can only contain integer or floating point types"); 8874407cf95SChris B return handleIntegerVectorBinOpConversion(SemaRef, LHS, RHS, LHSType, RHSType, 8884407cf95SChris B LElTy, RElTy, IsCompAssign); 8894407cf95SChris B } 8904407cf95SChris B 8914407cf95SChris B void SemaHLSL::emitLogicalOperatorFixIt(Expr *LHS, Expr *RHS, 8924407cf95SChris B BinaryOperatorKind Opc) { 8934407cf95SChris B assert((Opc == BO_LOr || Opc == BO_LAnd) && 8944407cf95SChris B "Called with non-logical operator"); 8954407cf95SChris B llvm::SmallVector<char, 256> Buff; 8964407cf95SChris B llvm::raw_svector_ostream OS(Buff); 8974407cf95SChris B PrintingPolicy PP(SemaRef.getLangOpts()); 8984407cf95SChris B StringRef NewFnName = Opc == BO_LOr ? "or" : "and"; 8994407cf95SChris B OS << NewFnName << "("; 9004407cf95SChris B LHS->printPretty(OS, nullptr, PP); 9014407cf95SChris B OS << ", "; 9024407cf95SChris B RHS->printPretty(OS, nullptr, PP); 9034407cf95SChris B OS << ")"; 9044407cf95SChris B SourceRange FullRange = SourceRange(LHS->getBeginLoc(), RHS->getEndLoc()); 9054407cf95SChris B SemaRef.Diag(LHS->getBeginLoc(), diag::note_function_suggestion) 9064407cf95SChris B << NewFnName << FixItHint::CreateReplacement(FullRange, OS.str()); 9074407cf95SChris B } 9084407cf95SChris B 9096b755b0cSVlad Serebrennikov void SemaHLSL::handleNumThreadsAttr(Decl *D, const ParsedAttr &AL) { 9106b755b0cSVlad Serebrennikov llvm::VersionTuple SMVersion = 9116b755b0cSVlad Serebrennikov getASTContext().getTargetInfo().getTriple().getOSVersion(); 9126b755b0cSVlad Serebrennikov uint32_t ZMax = 1024; 9136b755b0cSVlad Serebrennikov uint32_t ThreadMax = 1024; 9146b755b0cSVlad Serebrennikov if (SMVersion.getMajor() <= 4) { 9156b755b0cSVlad Serebrennikov ZMax = 1; 9166b755b0cSVlad Serebrennikov ThreadMax = 768; 9176b755b0cSVlad Serebrennikov } else if (SMVersion.getMajor() == 5) { 9186b755b0cSVlad Serebrennikov ZMax = 64; 9196b755b0cSVlad Serebrennikov ThreadMax = 1024; 9206b755b0cSVlad Serebrennikov } 9216b755b0cSVlad Serebrennikov 9226b755b0cSVlad Serebrennikov uint32_t X; 9236b755b0cSVlad Serebrennikov if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), X)) 9246b755b0cSVlad Serebrennikov return; 9256b755b0cSVlad Serebrennikov if (X > 1024) { 9266b755b0cSVlad Serebrennikov Diag(AL.getArgAsExpr(0)->getExprLoc(), 9276b755b0cSVlad Serebrennikov diag::err_hlsl_numthreads_argument_oor) 9286b755b0cSVlad Serebrennikov << 0 << 1024; 9296b755b0cSVlad Serebrennikov return; 9306b755b0cSVlad Serebrennikov } 9316b755b0cSVlad Serebrennikov uint32_t Y; 9326b755b0cSVlad Serebrennikov if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(1), Y)) 9336b755b0cSVlad Serebrennikov return; 9346b755b0cSVlad Serebrennikov if (Y > 1024) { 9356b755b0cSVlad Serebrennikov Diag(AL.getArgAsExpr(1)->getExprLoc(), 9366b755b0cSVlad Serebrennikov diag::err_hlsl_numthreads_argument_oor) 9376b755b0cSVlad Serebrennikov << 1 << 1024; 9386b755b0cSVlad Serebrennikov return; 9396b755b0cSVlad Serebrennikov } 9406b755b0cSVlad Serebrennikov uint32_t Z; 9416b755b0cSVlad Serebrennikov if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(2), Z)) 9426b755b0cSVlad Serebrennikov return; 9436b755b0cSVlad Serebrennikov if (Z > ZMax) { 9446b755b0cSVlad Serebrennikov SemaRef.Diag(AL.getArgAsExpr(2)->getExprLoc(), 9456b755b0cSVlad Serebrennikov diag::err_hlsl_numthreads_argument_oor) 9466b755b0cSVlad Serebrennikov << 2 << ZMax; 9476b755b0cSVlad Serebrennikov return; 9486b755b0cSVlad Serebrennikov } 9496b755b0cSVlad Serebrennikov 9506b755b0cSVlad Serebrennikov if (X * Y * Z > ThreadMax) { 9516b755b0cSVlad Serebrennikov Diag(AL.getLoc(), diag::err_hlsl_numthreads_invalid) << ThreadMax; 9526b755b0cSVlad Serebrennikov return; 9536b755b0cSVlad Serebrennikov } 9546b755b0cSVlad Serebrennikov 9556b755b0cSVlad Serebrennikov HLSLNumThreadsAttr *NewAttr = mergeNumThreadsAttr(D, AL, X, Y, Z); 9566b755b0cSVlad Serebrennikov if (NewAttr) 9576b755b0cSVlad Serebrennikov D->addAttr(NewAttr); 9586b755b0cSVlad Serebrennikov } 9596b755b0cSVlad Serebrennikov 960e41579a3SXiang Li static bool isValidWaveSizeValue(unsigned Value) { 961e41579a3SXiang Li return llvm::isPowerOf2_32(Value) && Value >= 4 && Value <= 128; 962e41579a3SXiang Li } 963e41579a3SXiang Li 964e41579a3SXiang Li void SemaHLSL::handleWaveSizeAttr(Decl *D, const ParsedAttr &AL) { 965e41579a3SXiang Li // validate that the wavesize argument is a power of 2 between 4 and 128 966e41579a3SXiang Li // inclusive 967e41579a3SXiang Li unsigned SpelledArgsCount = AL.getNumArgs(); 968e41579a3SXiang Li if (SpelledArgsCount == 0 || SpelledArgsCount > 3) 969e41579a3SXiang Li return; 970e41579a3SXiang Li 971e41579a3SXiang Li uint32_t Min; 972e41579a3SXiang Li if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), Min)) 973e41579a3SXiang Li return; 974e41579a3SXiang Li 975e41579a3SXiang Li uint32_t Max = 0; 976e41579a3SXiang Li if (SpelledArgsCount > 1 && 977e41579a3SXiang Li !SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(1), Max)) 978e41579a3SXiang Li return; 979e41579a3SXiang Li 980e41579a3SXiang Li uint32_t Preferred = 0; 981e41579a3SXiang Li if (SpelledArgsCount > 2 && 982e41579a3SXiang Li !SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(2), Preferred)) 983e41579a3SXiang Li return; 984e41579a3SXiang Li 985e41579a3SXiang Li if (SpelledArgsCount > 2) { 986e41579a3SXiang Li if (!isValidWaveSizeValue(Preferred)) { 987e41579a3SXiang Li Diag(AL.getArgAsExpr(2)->getExprLoc(), 988e41579a3SXiang Li diag::err_attribute_power_of_two_in_range) 989e41579a3SXiang Li << AL << llvm::dxil::MinWaveSize << llvm::dxil::MaxWaveSize 990e41579a3SXiang Li << Preferred; 991e41579a3SXiang Li return; 992e41579a3SXiang Li } 993e41579a3SXiang Li // Preferred not in range. 994e41579a3SXiang Li if (Preferred < Min || Preferred > Max) { 995e41579a3SXiang Li Diag(AL.getArgAsExpr(2)->getExprLoc(), 996e41579a3SXiang Li diag::err_attribute_power_of_two_in_range) 997e41579a3SXiang Li << AL << Min << Max << Preferred; 998e41579a3SXiang Li return; 999e41579a3SXiang Li } 1000e41579a3SXiang Li } else if (SpelledArgsCount > 1) { 1001e41579a3SXiang Li if (!isValidWaveSizeValue(Max)) { 1002e41579a3SXiang Li Diag(AL.getArgAsExpr(1)->getExprLoc(), 1003e41579a3SXiang Li diag::err_attribute_power_of_two_in_range) 1004e41579a3SXiang Li << AL << llvm::dxil::MinWaveSize << llvm::dxil::MaxWaveSize << Max; 1005e41579a3SXiang Li return; 1006e41579a3SXiang Li } 1007e41579a3SXiang Li if (Max < Min) { 1008e41579a3SXiang Li Diag(AL.getLoc(), diag::err_attribute_argument_invalid) << AL << 1; 1009e41579a3SXiang Li return; 1010e41579a3SXiang Li } else if (Max == Min) { 1011e41579a3SXiang Li Diag(AL.getLoc(), diag::warn_attr_min_eq_max) << AL; 1012e41579a3SXiang Li } 1013e41579a3SXiang Li } else { 1014e41579a3SXiang Li if (!isValidWaveSizeValue(Min)) { 1015e41579a3SXiang Li Diag(AL.getArgAsExpr(0)->getExprLoc(), 1016e41579a3SXiang Li diag::err_attribute_power_of_two_in_range) 1017e41579a3SXiang Li << AL << llvm::dxil::MinWaveSize << llvm::dxil::MaxWaveSize << Min; 1018e41579a3SXiang Li return; 1019e41579a3SXiang Li } 1020e41579a3SXiang Li } 1021e41579a3SXiang Li 1022e41579a3SXiang Li HLSLWaveSizeAttr *NewAttr = 1023e41579a3SXiang Li mergeWaveSizeAttr(D, AL, Min, Max, Preferred, SpelledArgsCount); 1024e41579a3SXiang Li if (NewAttr) 1025e41579a3SXiang Li D->addAttr(NewAttr); 1026e41579a3SXiang Li } 1027e41579a3SXiang Li 10285fd4f32fSZhengxing li bool SemaHLSL::diagnoseInputIDType(QualType T, const ParsedAttr &AL) { 10295fd4f32fSZhengxing li const auto *VT = T->getAs<VectorType>(); 10305fd4f32fSZhengxing li 10315fd4f32fSZhengxing li if (!T->hasUnsignedIntegerRepresentation() || 10325fd4f32fSZhengxing li (VT && VT->getNumElements() > 3)) { 10335fd4f32fSZhengxing li Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type) 10345fd4f32fSZhengxing li << AL << "uint/uint2/uint3"; 10356b755b0cSVlad Serebrennikov return false; 10365fd4f32fSZhengxing li } 10375fd4f32fSZhengxing li 10386b755b0cSVlad Serebrennikov return true; 10396b755b0cSVlad Serebrennikov } 10406b755b0cSVlad Serebrennikov 10416b755b0cSVlad Serebrennikov void SemaHLSL::handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL) { 10426b755b0cSVlad Serebrennikov auto *VD = cast<ValueDecl>(D); 10435fd4f32fSZhengxing li if (!diagnoseInputIDType(VD->getType(), AL)) 10446b755b0cSVlad Serebrennikov return; 10456b755b0cSVlad Serebrennikov 10466b755b0cSVlad Serebrennikov D->addAttr(::new (getASTContext()) 10476b755b0cSVlad Serebrennikov HLSLSV_DispatchThreadIDAttr(getASTContext(), AL)); 10486b755b0cSVlad Serebrennikov } 10496b755b0cSVlad Serebrennikov 1050951a284fSZhengxing li void SemaHLSL::handleSV_GroupThreadIDAttr(Decl *D, const ParsedAttr &AL) { 1051951a284fSZhengxing li auto *VD = cast<ValueDecl>(D); 1052951a284fSZhengxing li if (!diagnoseInputIDType(VD->getType(), AL)) 1053951a284fSZhengxing li return; 1054951a284fSZhengxing li 1055951a284fSZhengxing li D->addAttr(::new (getASTContext()) 1056951a284fSZhengxing li HLSLSV_GroupThreadIDAttr(getASTContext(), AL)); 1057951a284fSZhengxing li } 1058951a284fSZhengxing li 10595fd4f32fSZhengxing li void SemaHLSL::handleSV_GroupIDAttr(Decl *D, const ParsedAttr &AL) { 10605fd4f32fSZhengxing li auto *VD = cast<ValueDecl>(D); 10615fd4f32fSZhengxing li if (!diagnoseInputIDType(VD->getType(), AL)) 10625fd4f32fSZhengxing li return; 10635fd4f32fSZhengxing li 10645fd4f32fSZhengxing li D->addAttr(::new (getASTContext()) HLSLSV_GroupIDAttr(getASTContext(), AL)); 10655fd4f32fSZhengxing li } 10665fd4f32fSZhengxing li 10676b755b0cSVlad Serebrennikov void SemaHLSL::handlePackOffsetAttr(Decl *D, const ParsedAttr &AL) { 10686b755b0cSVlad Serebrennikov if (!isa<VarDecl>(D) || !isa<HLSLBufferDecl>(D->getDeclContext())) { 10696b755b0cSVlad Serebrennikov Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_ast_node) 10706b755b0cSVlad Serebrennikov << AL << "shader constant in a constant buffer"; 10716b755b0cSVlad Serebrennikov return; 10726b755b0cSVlad Serebrennikov } 10736b755b0cSVlad Serebrennikov 10746b755b0cSVlad Serebrennikov uint32_t SubComponent; 10756b755b0cSVlad Serebrennikov if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), SubComponent)) 10766b755b0cSVlad Serebrennikov return; 10776b755b0cSVlad Serebrennikov uint32_t Component; 10786b755b0cSVlad Serebrennikov if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(1), Component)) 10796b755b0cSVlad Serebrennikov return; 10806b755b0cSVlad Serebrennikov 10816b755b0cSVlad Serebrennikov QualType T = cast<VarDecl>(D)->getType().getCanonicalType(); 10826b755b0cSVlad Serebrennikov // Check if T is an array or struct type. 10836b755b0cSVlad Serebrennikov // TODO: mark matrix type as aggregate type. 10846b755b0cSVlad Serebrennikov bool IsAggregateTy = (T->isArrayType() || T->isStructureType()); 10856b755b0cSVlad Serebrennikov 10866b755b0cSVlad Serebrennikov // Check Component is valid for T. 10876b755b0cSVlad Serebrennikov if (Component) { 10886b755b0cSVlad Serebrennikov unsigned Size = getASTContext().getTypeSize(T); 10896b755b0cSVlad Serebrennikov if (IsAggregateTy || Size > 128) { 10906b755b0cSVlad Serebrennikov Diag(AL.getLoc(), diag::err_hlsl_packoffset_cross_reg_boundary); 10916b755b0cSVlad Serebrennikov return; 10926b755b0cSVlad Serebrennikov } else { 10936b755b0cSVlad Serebrennikov // Make sure Component + sizeof(T) <= 4. 10946b755b0cSVlad Serebrennikov if ((Component * 32 + Size) > 128) { 10956b755b0cSVlad Serebrennikov Diag(AL.getLoc(), diag::err_hlsl_packoffset_cross_reg_boundary); 10966b755b0cSVlad Serebrennikov return; 10976b755b0cSVlad Serebrennikov } 10986b755b0cSVlad Serebrennikov QualType EltTy = T; 10996b755b0cSVlad Serebrennikov if (const auto *VT = T->getAs<VectorType>()) 11006b755b0cSVlad Serebrennikov EltTy = VT->getElementType(); 11016b755b0cSVlad Serebrennikov unsigned Align = getASTContext().getTypeAlign(EltTy); 11026b755b0cSVlad Serebrennikov if (Align > 32 && Component == 1) { 11036b755b0cSVlad Serebrennikov // NOTE: Component 3 will hit err_hlsl_packoffset_cross_reg_boundary. 11046b755b0cSVlad Serebrennikov // So we only need to check Component 1 here. 11056b755b0cSVlad Serebrennikov Diag(AL.getLoc(), diag::err_hlsl_packoffset_alignment_mismatch) 11066b755b0cSVlad Serebrennikov << Align << EltTy; 11076b755b0cSVlad Serebrennikov return; 11086b755b0cSVlad Serebrennikov } 11096b755b0cSVlad Serebrennikov } 11106b755b0cSVlad Serebrennikov } 11116b755b0cSVlad Serebrennikov 11126b755b0cSVlad Serebrennikov D->addAttr(::new (getASTContext()) HLSLPackOffsetAttr( 11136b755b0cSVlad Serebrennikov getASTContext(), AL, SubComponent, Component)); 11146b755b0cSVlad Serebrennikov } 11156b755b0cSVlad Serebrennikov 11166b755b0cSVlad Serebrennikov void SemaHLSL::handleShaderAttr(Decl *D, const ParsedAttr &AL) { 11176b755b0cSVlad Serebrennikov StringRef Str; 11186b755b0cSVlad Serebrennikov SourceLocation ArgLoc; 11196b755b0cSVlad Serebrennikov if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc)) 11206b755b0cSVlad Serebrennikov return; 11216b755b0cSVlad Serebrennikov 11225d87ba1cSHelena Kotas llvm::Triple::EnvironmentType ShaderType; 11235d87ba1cSHelena Kotas if (!HLSLShaderAttr::ConvertStrToEnvironmentType(Str, ShaderType)) { 11246b755b0cSVlad Serebrennikov Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) 11256b755b0cSVlad Serebrennikov << AL << Str << ArgLoc; 11266b755b0cSVlad Serebrennikov return; 11276b755b0cSVlad Serebrennikov } 11286b755b0cSVlad Serebrennikov 11296b755b0cSVlad Serebrennikov // FIXME: check function match the shader stage. 11306b755b0cSVlad Serebrennikov 11316b755b0cSVlad Serebrennikov HLSLShaderAttr *NewAttr = mergeShaderAttr(D, AL, ShaderType); 11326b755b0cSVlad Serebrennikov if (NewAttr) 11336b755b0cSVlad Serebrennikov D->addAttr(NewAttr); 11346b755b0cSVlad Serebrennikov } 11356b755b0cSVlad Serebrennikov 11360a7a1ef2SHelena Kotas bool clang::CreateHLSLAttributedResourceType( 11370a7a1ef2SHelena Kotas Sema &S, QualType Wrapped, ArrayRef<const Attr *> AttrList, 11380a7a1ef2SHelena Kotas QualType &ResType, HLSLAttributedResourceLocInfo *LocInfo) { 11398e35c869SHelena Kotas assert(AttrList.size() && "expected list of resource attributes"); 11408e35c869SHelena Kotas 11410a7a1ef2SHelena Kotas QualType ContainedTy = QualType(); 1142cb98fd97SAaron Ballman TypeSourceInfo *ContainedTyInfo = nullptr; 11430a7a1ef2SHelena Kotas SourceLocation LocBegin = AttrList[0]->getRange().getBegin(); 11440a7a1ef2SHelena Kotas SourceLocation LocEnd = AttrList[0]->getRange().getEnd(); 11450a7a1ef2SHelena Kotas 11465df1b793SHelena Kotas HLSLAttributedResourceType::Attributes ResAttrs; 11478e35c869SHelena Kotas 11488e35c869SHelena Kotas bool HasResourceClass = false; 11498e35c869SHelena Kotas for (const Attr *A : AttrList) { 11508e35c869SHelena Kotas if (!A) 11518e35c869SHelena Kotas continue; 11520a7a1ef2SHelena Kotas LocEnd = A->getRange().getEnd(); 11538e35c869SHelena Kotas switch (A->getKind()) { 11548e35c869SHelena Kotas case attr::HLSLResourceClass: { 1155f2128267SHelena Kotas ResourceClass RC = cast<HLSLResourceClassAttr>(A)->getResourceClass(); 11568e35c869SHelena Kotas if (HasResourceClass) { 11578e35c869SHelena Kotas S.Diag(A->getLocation(), ResAttrs.ResourceClass == RC 11588e35c869SHelena Kotas ? diag::warn_duplicate_attribute_exact 11598e35c869SHelena Kotas : diag::warn_duplicate_attribute) 11608e35c869SHelena Kotas << A; 11618e35c869SHelena Kotas return false; 11628e35c869SHelena Kotas } 11638e35c869SHelena Kotas ResAttrs.ResourceClass = RC; 11648e35c869SHelena Kotas HasResourceClass = true; 11658e35c869SHelena Kotas break; 11668e35c869SHelena Kotas } 11678e35c869SHelena Kotas case attr::HLSLROV: 116861372fc5SHelena Kotas if (ResAttrs.IsROV) { 116961372fc5SHelena Kotas S.Diag(A->getLocation(), diag::warn_duplicate_attribute_exact) << A; 117061372fc5SHelena Kotas return false; 117161372fc5SHelena Kotas } 11728e35c869SHelena Kotas ResAttrs.IsROV = true; 11738e35c869SHelena Kotas break; 11745df1b793SHelena Kotas case attr::HLSLRawBuffer: 11755df1b793SHelena Kotas if (ResAttrs.RawBuffer) { 11765df1b793SHelena Kotas S.Diag(A->getLocation(), diag::warn_duplicate_attribute_exact) << A; 11775df1b793SHelena Kotas return false; 11785df1b793SHelena Kotas } 11795df1b793SHelena Kotas ResAttrs.RawBuffer = true; 11805df1b793SHelena Kotas break; 11810a7a1ef2SHelena Kotas case attr::HLSLContainedType: { 11820a7a1ef2SHelena Kotas const HLSLContainedTypeAttr *CTAttr = cast<HLSLContainedTypeAttr>(A); 11830a7a1ef2SHelena Kotas QualType Ty = CTAttr->getType(); 11840a7a1ef2SHelena Kotas if (!ContainedTy.isNull()) { 11850a7a1ef2SHelena Kotas S.Diag(A->getLocation(), ContainedTy == Ty 11860a7a1ef2SHelena Kotas ? diag::warn_duplicate_attribute_exact 11870a7a1ef2SHelena Kotas : diag::warn_duplicate_attribute) 11880a7a1ef2SHelena Kotas << A; 11890a7a1ef2SHelena Kotas return false; 11900a7a1ef2SHelena Kotas } 11910a7a1ef2SHelena Kotas ContainedTy = Ty; 11920a7a1ef2SHelena Kotas ContainedTyInfo = CTAttr->getTypeLoc(); 11930a7a1ef2SHelena Kotas break; 11940a7a1ef2SHelena Kotas } 11958e35c869SHelena Kotas default: 11968e35c869SHelena Kotas llvm_unreachable("unhandled resource attribute type"); 11978e35c869SHelena Kotas } 11988e35c869SHelena Kotas } 11998e35c869SHelena Kotas 12008e35c869SHelena Kotas if (!HasResourceClass) { 12018e35c869SHelena Kotas S.Diag(AttrList.back()->getRange().getEnd(), 12028e35c869SHelena Kotas diag::err_hlsl_missing_resource_class); 12038e35c869SHelena Kotas return false; 12048e35c869SHelena Kotas } 12058e35c869SHelena Kotas 12060a7a1ef2SHelena Kotas ResType = S.getASTContext().getHLSLAttributedResourceType( 12070a7a1ef2SHelena Kotas Wrapped, ContainedTy, ResAttrs); 12080a7a1ef2SHelena Kotas 1209cb98fd97SAaron Ballman if (LocInfo && ContainedTyInfo) { 12100a7a1ef2SHelena Kotas LocInfo->Range = SourceRange(LocBegin, LocEnd); 12110a7a1ef2SHelena Kotas LocInfo->ContainedTyInfo = ContainedTyInfo; 12120a7a1ef2SHelena Kotas } 12138e35c869SHelena Kotas return true; 12148e35c869SHelena Kotas } 12158e35c869SHelena Kotas 12168e35c869SHelena Kotas // Validates and creates an HLSL attribute that is applied as type attribute on 12178e35c869SHelena Kotas // HLSL resource. The attributes are collected in HLSLResourcesTypeAttrs and at 12188e35c869SHelena Kotas // the end of the declaration they are applied to the declaration type by 12198e35c869SHelena Kotas // wrapping it in HLSLAttributedResourceType. 12201d8fad9fSHelena Kotas bool SemaHLSL::handleResourceTypeAttr(QualType T, const ParsedAttr &AL) { 12211d8fad9fSHelena Kotas // only allow resource type attributes on intangible types 12221d8fad9fSHelena Kotas if (!T->isHLSLResourceType()) { 12231d8fad9fSHelena Kotas Diag(AL.getLoc(), diag::err_hlsl_attribute_needs_intangible_type) 12241d8fad9fSHelena Kotas << AL << getASTContext().HLSLResourceTy; 12251d8fad9fSHelena Kotas return false; 12261d8fad9fSHelena Kotas } 12278e35c869SHelena Kotas 12288e35c869SHelena Kotas // validate number of arguments 12298e35c869SHelena Kotas if (!AL.checkExactlyNumArgs(SemaRef, AL.getMinArgs())) 12308e35c869SHelena Kotas return false; 12318e35c869SHelena Kotas 12321d8fad9fSHelena Kotas Attr *A = nullptr; 12338e35c869SHelena Kotas switch (AL.getKind()) { 12348e35c869SHelena Kotas case ParsedAttr::AT_HLSLResourceClass: { 12355dc371e2SJoshua Batista if (!AL.isArgIdent(0)) { 12365dc371e2SJoshua Batista Diag(AL.getLoc(), diag::err_attribute_argument_type) 12375dc371e2SJoshua Batista << AL << AANT_ArgumentIdentifier; 12388e35c869SHelena Kotas return false; 12395dc371e2SJoshua Batista } 12405dc371e2SJoshua Batista 12415dc371e2SJoshua Batista IdentifierLoc *Loc = AL.getArgAsIdent(0); 12425dc371e2SJoshua Batista StringRef Identifier = Loc->Ident->getName(); 12435dc371e2SJoshua Batista SourceLocation ArgLoc = Loc->Loc; 12445dc371e2SJoshua Batista 12458e35c869SHelena Kotas // Validate resource class value 1246f2128267SHelena Kotas ResourceClass RC; 12475dc371e2SJoshua Batista if (!HLSLResourceClassAttr::ConvertStrToResourceClass(Identifier, RC)) { 12485dc371e2SJoshua Batista Diag(ArgLoc, diag::warn_attribute_type_not_supported) 12495dc371e2SJoshua Batista << "ResourceClass" << Identifier; 12508e35c869SHelena Kotas return false; 12518e35c869SHelena Kotas } 12528e35c869SHelena Kotas A = HLSLResourceClassAttr::Create(getASTContext(), RC, AL.getLoc()); 12538e35c869SHelena Kotas break; 12548e35c869SHelena Kotas } 12550a7a1ef2SHelena Kotas 12568e35c869SHelena Kotas case ParsedAttr::AT_HLSLROV: 12578e35c869SHelena Kotas A = HLSLROVAttr::Create(getASTContext(), AL.getLoc()); 12588e35c869SHelena Kotas break; 12590a7a1ef2SHelena Kotas 12605df1b793SHelena Kotas case ParsedAttr::AT_HLSLRawBuffer: 12615df1b793SHelena Kotas A = HLSLRawBufferAttr::Create(getASTContext(), AL.getLoc()); 12625df1b793SHelena Kotas break; 12635df1b793SHelena Kotas 12640a7a1ef2SHelena Kotas case ParsedAttr::AT_HLSLContainedType: { 12650a7a1ef2SHelena Kotas if (AL.getNumArgs() != 1 && !AL.hasParsedType()) { 12660a7a1ef2SHelena Kotas Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1; 12670a7a1ef2SHelena Kotas return false; 12680a7a1ef2SHelena Kotas } 12690a7a1ef2SHelena Kotas 12700a7a1ef2SHelena Kotas TypeSourceInfo *TSI = nullptr; 12710a7a1ef2SHelena Kotas QualType QT = SemaRef.GetTypeFromParser(AL.getTypeArg(), &TSI); 12720a7a1ef2SHelena Kotas assert(TSI && "no type source info for attribute argument"); 12730a7a1ef2SHelena Kotas if (SemaRef.RequireCompleteType(TSI->getTypeLoc().getBeginLoc(), QT, 12740a7a1ef2SHelena Kotas diag::err_incomplete_type)) 12750a7a1ef2SHelena Kotas return false; 12760a7a1ef2SHelena Kotas A = HLSLContainedTypeAttr::Create(getASTContext(), TSI, AL.getLoc()); 12770a7a1ef2SHelena Kotas break; 12780a7a1ef2SHelena Kotas } 12790a7a1ef2SHelena Kotas 12808e35c869SHelena Kotas default: 12818e35c869SHelena Kotas llvm_unreachable("unhandled HLSL attribute"); 12825dc371e2SJoshua Batista } 12835dc371e2SJoshua Batista 12848e35c869SHelena Kotas HLSLResourcesTypeAttrs.emplace_back(A); 1285e00e9a3fSHelena Kotas return true; 1286e00e9a3fSHelena Kotas } 1287e00e9a3fSHelena Kotas 12888e35c869SHelena Kotas // Combines all resource type attributes and creates HLSLAttributedResourceType. 1289e00e9a3fSHelena Kotas QualType SemaHLSL::ProcessResourceTypeAttributes(QualType CurrentType) { 12908e35c869SHelena Kotas if (!HLSLResourcesTypeAttrs.size()) 1291e00e9a3fSHelena Kotas return CurrentType; 12928e35c869SHelena Kotas 12938e35c869SHelena Kotas QualType QT = CurrentType; 12940a7a1ef2SHelena Kotas HLSLAttributedResourceLocInfo LocInfo; 12958e35c869SHelena Kotas if (CreateHLSLAttributedResourceType(SemaRef, CurrentType, 12960a7a1ef2SHelena Kotas HLSLResourcesTypeAttrs, QT, &LocInfo)) { 12978e35c869SHelena Kotas const HLSLAttributedResourceType *RT = 12980a7a1ef2SHelena Kotas cast<HLSLAttributedResourceType>(QT.getTypePtr()); 12990a7a1ef2SHelena Kotas 13000a7a1ef2SHelena Kotas // Temporarily store TypeLoc information for the new type. 13010a7a1ef2SHelena Kotas // It will be transferred to HLSLAttributesResourceTypeLoc 13020a7a1ef2SHelena Kotas // shortly after the type is created by TypeSpecLocFiller which 13030a7a1ef2SHelena Kotas // will call the TakeLocForHLSLAttribute method below. 13040a7a1ef2SHelena Kotas LocsForHLSLAttributedResources.insert(std::pair(RT, LocInfo)); 13058e35c869SHelena Kotas } 13068e35c869SHelena Kotas HLSLResourcesTypeAttrs.clear(); 13078e35c869SHelena Kotas return QT; 1308e00e9a3fSHelena Kotas } 1309e00e9a3fSHelena Kotas 1310e00e9a3fSHelena Kotas // Returns source location for the HLSLAttributedResourceType 13110a7a1ef2SHelena Kotas HLSLAttributedResourceLocInfo 1312e00e9a3fSHelena Kotas SemaHLSL::TakeLocForHLSLAttribute(const HLSLAttributedResourceType *RT) { 13130a7a1ef2SHelena Kotas HLSLAttributedResourceLocInfo LocInfo = {}; 13148e35c869SHelena Kotas auto I = LocsForHLSLAttributedResources.find(RT); 13158e35c869SHelena Kotas if (I != LocsForHLSLAttributedResources.end()) { 13160a7a1ef2SHelena Kotas LocInfo = I->second; 13178e35c869SHelena Kotas LocsForHLSLAttributedResources.erase(I); 13180a7a1ef2SHelena Kotas return LocInfo; 13198e35c869SHelena Kotas } 13200a7a1ef2SHelena Kotas LocInfo.Range = SourceRange(); 13210a7a1ef2SHelena Kotas return LocInfo; 1322e00e9a3fSHelena Kotas } 1323e00e9a3fSHelena Kotas 13244512bbe7SHelena Kotas // Walks though the global variable declaration, collects all resource binding 13254512bbe7SHelena Kotas // requirements and adds them to Bindings 13264512bbe7SHelena Kotas void SemaHLSL::collectResourcesOnUserRecordDecl(const VarDecl *VD, 13274512bbe7SHelena Kotas const RecordType *RT) { 1328334d1238SHelena Kotas const RecordDecl *RD = RT->getDecl(); 1329334d1238SHelena Kotas for (FieldDecl *FD : RD->fields()) { 13304512bbe7SHelena Kotas const Type *Ty = FD->getType()->getUnqualifiedDesugaredType(); 13314512bbe7SHelena Kotas 13324512bbe7SHelena Kotas // Unwrap arrays 13334512bbe7SHelena Kotas // FIXME: Calculate array size while unwrapping 13344512bbe7SHelena Kotas assert(!Ty->isIncompleteArrayType() && 13354512bbe7SHelena Kotas "incomplete arrays inside user defined types are not supported"); 13364512bbe7SHelena Kotas while (Ty->isConstantArrayType()) { 13374512bbe7SHelena Kotas const ConstantArrayType *CAT = cast<ConstantArrayType>(Ty); 13384512bbe7SHelena Kotas Ty = CAT->getElementType()->getUnqualifiedDesugaredType(); 1339f2128267SHelena Kotas } 1340ebc4a66eSJoshua Batista 13414512bbe7SHelena Kotas if (!Ty->isRecordType()) 13424512bbe7SHelena Kotas continue; 13434512bbe7SHelena Kotas 13444512bbe7SHelena Kotas if (const HLSLAttributedResourceType *AttrResType = 13457dbfa7b9SHelena Kotas HLSLAttributedResourceType::findHandleTypeOnResource(Ty)) { 13464512bbe7SHelena Kotas // Add a new DeclBindingInfo to Bindings if it does not already exist 13474512bbe7SHelena Kotas ResourceClass RC = AttrResType->getAttrs().ResourceClass; 13484512bbe7SHelena Kotas DeclBindingInfo *DBI = Bindings.getDeclBindingInfo(VD, RC); 13494512bbe7SHelena Kotas if (!DBI) 13504512bbe7SHelena Kotas Bindings.addDeclBindingInfo(VD, RC); 13514512bbe7SHelena Kotas } else if (const RecordType *RT = dyn_cast<RecordType>(Ty)) { 13524512bbe7SHelena Kotas // Recursively scan embedded struct or class; it would be nice to do this 13534512bbe7SHelena Kotas // without recursion, but tricky to correctly calculate the size of the 13544512bbe7SHelena Kotas // binding, which is something we are probably going to need to do later 13554512bbe7SHelena Kotas // on. Hopefully nesting of structs in structs too many levels is 13564512bbe7SHelena Kotas // unlikely. 13574512bbe7SHelena Kotas collectResourcesOnUserRecordDecl(VD, RT); 13584512bbe7SHelena Kotas } 13594512bbe7SHelena Kotas } 13604512bbe7SHelena Kotas } 13614512bbe7SHelena Kotas 13624512bbe7SHelena Kotas // Diagnore localized register binding errors for a single binding; does not 13634512bbe7SHelena Kotas // diagnose resource binding on user record types, that will be done later 13644512bbe7SHelena Kotas // in processResourceBindingOnDecl based on the information collected in 13654512bbe7SHelena Kotas // collectResourcesOnVarDecl. 13664512bbe7SHelena Kotas // Returns false if the register binding is not valid. 13674512bbe7SHelena Kotas static bool DiagnoseLocalRegisterBinding(Sema &S, SourceLocation &ArgLoc, 1368f2128267SHelena Kotas Decl *D, RegisterType RegType, 1369f2128267SHelena Kotas bool SpecifiedSpace) { 1370f2128267SHelena Kotas int RegTypeNum = static_cast<int>(RegType); 1371ebc4a66eSJoshua Batista 1372ebc4a66eSJoshua Batista // check if the decl type is groupshared 1373f2128267SHelena Kotas if (D->hasAttr<HLSLGroupSharedAddressSpaceAttr>()) { 1374f2128267SHelena Kotas S.Diag(ArgLoc, diag::err_hlsl_binding_type_mismatch) << RegTypeNum; 13754512bbe7SHelena Kotas return false; 1376ebc4a66eSJoshua Batista } 1377ebc4a66eSJoshua Batista 1378334d1238SHelena Kotas // Cbuffers and Tbuffers are HLSLBufferDecl types 1379f2128267SHelena Kotas if (HLSLBufferDecl *CBufferOrTBuffer = dyn_cast<HLSLBufferDecl>(D)) { 1380f2128267SHelena Kotas ResourceClass RC = CBufferOrTBuffer->isCBuffer() ? ResourceClass::CBuffer 1381f2128267SHelena Kotas : ResourceClass::SRV; 13824512bbe7SHelena Kotas if (RegType == getRegisterType(RC)) 13834512bbe7SHelena Kotas return true; 13844512bbe7SHelena Kotas 1385f2128267SHelena Kotas S.Diag(D->getLocation(), diag::err_hlsl_binding_type_mismatch) 1386f2128267SHelena Kotas << RegTypeNum; 13874512bbe7SHelena Kotas return false; 1388334d1238SHelena Kotas } 1389f2128267SHelena Kotas 1390334d1238SHelena Kotas // Samplers, UAVs, and SRVs are VarDecl types 1391f2128267SHelena Kotas assert(isa<VarDecl>(D) && "D is expected to be VarDecl or HLSLBufferDecl"); 1392f2128267SHelena Kotas VarDecl *VD = cast<VarDecl>(D); 1393f2128267SHelena Kotas 1394f2128267SHelena Kotas // Resource 13958e35c869SHelena Kotas if (const HLSLAttributedResourceType *AttrResType = 13967dbfa7b9SHelena Kotas HLSLAttributedResourceType::findHandleTypeOnResource( 13977dbfa7b9SHelena Kotas VD->getType().getTypePtr())) { 13984512bbe7SHelena Kotas if (RegType == getRegisterType(AttrResType->getAttrs().ResourceClass)) 13994512bbe7SHelena Kotas return true; 14004512bbe7SHelena Kotas 1401f2128267SHelena Kotas S.Diag(D->getLocation(), diag::err_hlsl_binding_type_mismatch) 1402f2128267SHelena Kotas << RegTypeNum; 14034512bbe7SHelena Kotas return false; 1404f2128267SHelena Kotas } 1405f2128267SHelena Kotas 1406f2128267SHelena Kotas const clang::Type *Ty = VD->getType().getTypePtr(); 1407f2128267SHelena Kotas while (Ty->isArrayType()) 1408f2128267SHelena Kotas Ty = Ty->getArrayElementTypeNoTypeQual(); 1409f2128267SHelena Kotas 1410f2128267SHelena Kotas // Basic types 1411f2128267SHelena Kotas if (Ty->isArithmeticType()) { 1412f2128267SHelena Kotas bool DeclaredInCOrTBuffer = isa<HLSLBufferDecl>(D->getDeclContext()); 1413f2128267SHelena Kotas if (SpecifiedSpace && !DeclaredInCOrTBuffer) 1414f2128267SHelena Kotas S.Diag(ArgLoc, diag::err_hlsl_space_on_global_constant); 1415f2128267SHelena Kotas 1416f2128267SHelena Kotas if (!DeclaredInCOrTBuffer && 1417f2128267SHelena Kotas (Ty->isIntegralType(S.getASTContext()) || Ty->isFloatingType())) { 1418f2128267SHelena Kotas // Default Globals 1419f2128267SHelena Kotas if (RegType == RegisterType::CBuffer) 1420f2128267SHelena Kotas S.Diag(ArgLoc, diag::warn_hlsl_deprecated_register_type_b); 1421f2128267SHelena Kotas else if (RegType != RegisterType::C) 1422f2128267SHelena Kotas S.Diag(ArgLoc, diag::err_hlsl_binding_type_mismatch) << RegTypeNum; 1423ebc4a66eSJoshua Batista } else { 1424f2128267SHelena Kotas if (RegType == RegisterType::C) 1425f2128267SHelena Kotas S.Diag(ArgLoc, diag::warn_hlsl_register_type_c_packoffset); 1426f2128267SHelena Kotas else 1427f2128267SHelena Kotas S.Diag(ArgLoc, diag::err_hlsl_binding_type_mismatch) << RegTypeNum; 1428ebc4a66eSJoshua Batista } 14294512bbe7SHelena Kotas return false; 14304512bbe7SHelena Kotas } 14314512bbe7SHelena Kotas if (Ty->isRecordType()) 14324512bbe7SHelena Kotas // RecordTypes will be diagnosed in processResourceBindingOnDecl 14334512bbe7SHelena Kotas // that is called from ActOnVariableDeclarator 14344512bbe7SHelena Kotas return true; 14354512bbe7SHelena Kotas 1436f2128267SHelena Kotas // Anything else is an error 1437f2128267SHelena Kotas S.Diag(ArgLoc, diag::err_hlsl_binding_type_mismatch) << RegTypeNum; 14384512bbe7SHelena Kotas return false; 1439ebc4a66eSJoshua Batista } 1440ebc4a66eSJoshua Batista 14414512bbe7SHelena Kotas static bool ValidateMultipleRegisterAnnotations(Sema &S, Decl *TheDecl, 1442ebc4a66eSJoshua Batista RegisterType regType) { 1443ebc4a66eSJoshua Batista // make sure that there are no two register annotations 1444ebc4a66eSJoshua Batista // applied to the decl with the same register type 1445ebc4a66eSJoshua Batista bool RegisterTypesDetected[5] = {false}; 1446ebc4a66eSJoshua Batista RegisterTypesDetected[static_cast<int>(regType)] = true; 1447ebc4a66eSJoshua Batista 1448ebc4a66eSJoshua Batista for (auto it = TheDecl->attr_begin(); it != TheDecl->attr_end(); ++it) { 1449ebc4a66eSJoshua Batista if (HLSLResourceBindingAttr *attr = 1450ebc4a66eSJoshua Batista dyn_cast<HLSLResourceBindingAttr>(*it)) { 1451ebc4a66eSJoshua Batista 14524512bbe7SHelena Kotas RegisterType otherRegType = attr->getRegisterType(); 1453ebc4a66eSJoshua Batista if (RegisterTypesDetected[static_cast<int>(otherRegType)]) { 1454ebc4a66eSJoshua Batista int otherRegTypeNum = static_cast<int>(otherRegType); 1455ebc4a66eSJoshua Batista S.Diag(TheDecl->getLocation(), 1456ebc4a66eSJoshua Batista diag::err_hlsl_duplicate_register_annotation) 1457ebc4a66eSJoshua Batista << otherRegTypeNum; 14584512bbe7SHelena Kotas return false; 14594512bbe7SHelena Kotas } 1460ebc4a66eSJoshua Batista RegisterTypesDetected[static_cast<int>(otherRegType)] = true; 1461ebc4a66eSJoshua Batista } 1462ebc4a66eSJoshua Batista } 14634512bbe7SHelena Kotas return true; 1464ebc4a66eSJoshua Batista } 1465ebc4a66eSJoshua Batista 14664512bbe7SHelena Kotas static bool DiagnoseHLSLRegisterAttribute(Sema &S, SourceLocation &ArgLoc, 1467f2128267SHelena Kotas Decl *D, RegisterType RegType, 1468f2128267SHelena Kotas bool SpecifiedSpace) { 1469ebc4a66eSJoshua Batista 1470ebc4a66eSJoshua Batista // exactly one of these two types should be set 1471f2128267SHelena Kotas assert(((isa<VarDecl>(D) && !isa<HLSLBufferDecl>(D)) || 1472f2128267SHelena Kotas (!isa<VarDecl>(D) && isa<HLSLBufferDecl>(D))) && 147341c11ea2SHelena Kotas "expecting VarDecl or HLSLBufferDecl"); 1474ebc4a66eSJoshua Batista 1475f2128267SHelena Kotas // check if the declaration contains resource matching the register type 14764512bbe7SHelena Kotas if (!DiagnoseLocalRegisterBinding(S, ArgLoc, D, RegType, SpecifiedSpace)) 14774512bbe7SHelena Kotas return false; 1478ebc4a66eSJoshua Batista 1479ebc4a66eSJoshua Batista // next, if multiple register annotations exist, check that none conflict. 14804512bbe7SHelena Kotas return ValidateMultipleRegisterAnnotations(S, D, RegType); 1481ebc4a66eSJoshua Batista } 1482ebc4a66eSJoshua Batista 1483ebc4a66eSJoshua Batista void SemaHLSL::handleResourceBindingAttr(Decl *TheDecl, const ParsedAttr &AL) { 1484334d1238SHelena Kotas if (isa<VarDecl>(TheDecl)) { 1485ebc4a66eSJoshua Batista if (SemaRef.RequireCompleteType(TheDecl->getBeginLoc(), 1486ebc4a66eSJoshua Batista cast<ValueDecl>(TheDecl)->getType(), 1487ebc4a66eSJoshua Batista diag::err_incomplete_type)) 1488ebc4a66eSJoshua Batista return; 1489ebc4a66eSJoshua Batista } 14906b755b0cSVlad Serebrennikov StringRef Space = "space0"; 14916b755b0cSVlad Serebrennikov StringRef Slot = ""; 14926b755b0cSVlad Serebrennikov 14936b755b0cSVlad Serebrennikov if (!AL.isArgIdent(0)) { 14946b755b0cSVlad Serebrennikov Diag(AL.getLoc(), diag::err_attribute_argument_type) 14956b755b0cSVlad Serebrennikov << AL << AANT_ArgumentIdentifier; 14966b755b0cSVlad Serebrennikov return; 14976b755b0cSVlad Serebrennikov } 14986b755b0cSVlad Serebrennikov 14996b755b0cSVlad Serebrennikov IdentifierLoc *Loc = AL.getArgAsIdent(0); 15006b755b0cSVlad Serebrennikov StringRef Str = Loc->Ident->getName(); 15016b755b0cSVlad Serebrennikov SourceLocation ArgLoc = Loc->Loc; 15026b755b0cSVlad Serebrennikov 15036b755b0cSVlad Serebrennikov SourceLocation SpaceArgLoc; 1504905de9b0SJoshua Batista bool SpecifiedSpace = false; 15056b755b0cSVlad Serebrennikov if (AL.getNumArgs() == 2) { 1506905de9b0SJoshua Batista SpecifiedSpace = true; 15076b755b0cSVlad Serebrennikov Slot = Str; 15086b755b0cSVlad Serebrennikov if (!AL.isArgIdent(1)) { 15096b755b0cSVlad Serebrennikov Diag(AL.getLoc(), diag::err_attribute_argument_type) 15106b755b0cSVlad Serebrennikov << AL << AANT_ArgumentIdentifier; 15116b755b0cSVlad Serebrennikov return; 15126b755b0cSVlad Serebrennikov } 15136b755b0cSVlad Serebrennikov 15146b755b0cSVlad Serebrennikov IdentifierLoc *Loc = AL.getArgAsIdent(1); 15156b755b0cSVlad Serebrennikov Space = Loc->Ident->getName(); 15166b755b0cSVlad Serebrennikov SpaceArgLoc = Loc->Loc; 15176b755b0cSVlad Serebrennikov } else { 15186b755b0cSVlad Serebrennikov Slot = Str; 15196b755b0cSVlad Serebrennikov } 15206b755b0cSVlad Serebrennikov 15214512bbe7SHelena Kotas RegisterType RegType; 15224512bbe7SHelena Kotas unsigned SlotNum = 0; 15234512bbe7SHelena Kotas unsigned SpaceNum = 0; 1524ebc4a66eSJoshua Batista 15256b755b0cSVlad Serebrennikov // Validate. 15266b755b0cSVlad Serebrennikov if (!Slot.empty()) { 15274512bbe7SHelena Kotas if (!convertToRegisterType(Slot, &RegType)) { 1528ebc4a66eSJoshua Batista Diag(ArgLoc, diag::err_hlsl_binding_type_invalid) << Slot.substr(0, 1); 15296b755b0cSVlad Serebrennikov return; 15306b755b0cSVlad Serebrennikov } 15314512bbe7SHelena Kotas if (RegType == RegisterType::I) { 15324512bbe7SHelena Kotas Diag(ArgLoc, diag::warn_hlsl_deprecated_register_type_i); 15334512bbe7SHelena Kotas return; 15344512bbe7SHelena Kotas } 15356b755b0cSVlad Serebrennikov 15364512bbe7SHelena Kotas StringRef SlotNumStr = Slot.substr(1); 15374512bbe7SHelena Kotas if (SlotNumStr.getAsInteger(10, SlotNum)) { 15386b755b0cSVlad Serebrennikov Diag(ArgLoc, diag::err_hlsl_unsupported_register_number); 15396b755b0cSVlad Serebrennikov return; 15406b755b0cSVlad Serebrennikov } 15416b755b0cSVlad Serebrennikov } 15426b755b0cSVlad Serebrennikov 15436b755b0cSVlad Serebrennikov if (!Space.starts_with("space")) { 15446b755b0cSVlad Serebrennikov Diag(SpaceArgLoc, diag::err_hlsl_expected_space) << Space; 15456b755b0cSVlad Serebrennikov return; 15466b755b0cSVlad Serebrennikov } 15474512bbe7SHelena Kotas StringRef SpaceNumStr = Space.substr(5); 15484512bbe7SHelena Kotas if (SpaceNumStr.getAsInteger(10, SpaceNum)) { 15496b755b0cSVlad Serebrennikov Diag(SpaceArgLoc, diag::err_hlsl_expected_space) << Space; 15506b755b0cSVlad Serebrennikov return; 15516b755b0cSVlad Serebrennikov } 15526b755b0cSVlad Serebrennikov 15534512bbe7SHelena Kotas if (!DiagnoseHLSLRegisterAttribute(SemaRef, ArgLoc, TheDecl, RegType, 15544512bbe7SHelena Kotas SpecifiedSpace)) 15554512bbe7SHelena Kotas return; 1556ebc4a66eSJoshua Batista 15576b755b0cSVlad Serebrennikov HLSLResourceBindingAttr *NewAttr = 15586b755b0cSVlad Serebrennikov HLSLResourceBindingAttr::Create(getASTContext(), Slot, Space, AL); 15594512bbe7SHelena Kotas if (NewAttr) { 15604512bbe7SHelena Kotas NewAttr->setBinding(RegType, SlotNum, SpaceNum); 1561ebc4a66eSJoshua Batista TheDecl->addAttr(NewAttr); 15626b755b0cSVlad Serebrennikov } 15634512bbe7SHelena Kotas } 15646b755b0cSVlad Serebrennikov 15656b755b0cSVlad Serebrennikov void SemaHLSL::handleParamModifierAttr(Decl *D, const ParsedAttr &AL) { 15666b755b0cSVlad Serebrennikov HLSLParamModifierAttr *NewAttr = mergeParamModifierAttr( 15676b755b0cSVlad Serebrennikov D, AL, 15686b755b0cSVlad Serebrennikov static_cast<HLSLParamModifierAttr::Spelling>(AL.getSemanticSpelling())); 15696b755b0cSVlad Serebrennikov if (NewAttr) 15706b755b0cSVlad Serebrennikov D->addAttr(NewAttr); 15716b755b0cSVlad Serebrennikov } 15726b755b0cSVlad Serebrennikov 15738890209eSHelena Kotas namespace { 15748890209eSHelena Kotas 15758890209eSHelena Kotas /// This class implements HLSL availability diagnostics for default 15768890209eSHelena Kotas /// and relaxed mode 15778890209eSHelena Kotas /// 15788890209eSHelena Kotas /// The goal of this diagnostic is to emit an error or warning when an 15798890209eSHelena Kotas /// unavailable API is found in code that is reachable from the shader 15808890209eSHelena Kotas /// entry function or from an exported function (when compiling a shader 15818890209eSHelena Kotas /// library). 15828890209eSHelena Kotas /// 15838890209eSHelena Kotas /// This is done by traversing the AST of all shader entry point functions 158430efdce7SHelena Kotas /// and of all exported functions, and any functions that are referenced 15858890209eSHelena Kotas /// from this AST. In other words, any functions that are reachable from 15868890209eSHelena Kotas /// the entry points. 1587dde802b1SSirraide class DiagnoseHLSLAvailability : public DynamicRecursiveASTVisitor { 15888890209eSHelena Kotas Sema &SemaRef; 15898890209eSHelena Kotas 15908890209eSHelena Kotas // Stack of functions to be scaned 15918890209eSHelena Kotas llvm::SmallVector<const FunctionDecl *, 8> DeclsToScan; 15928890209eSHelena Kotas 15938890209eSHelena Kotas // Tracks which environments functions have been scanned in. 15948890209eSHelena Kotas // 15958890209eSHelena Kotas // Maps FunctionDecl to an unsigned number that represents the set of shader 15968890209eSHelena Kotas // environments the function has been scanned for. 15975d87ba1cSHelena Kotas // The llvm::Triple::EnvironmentType enum values for shader stages guaranteed 15985d87ba1cSHelena Kotas // to be numbered from llvm::Triple::Pixel to llvm::Triple::Amplification 15995d87ba1cSHelena Kotas // (verified by static_asserts in Triple.cpp), we can use it to index 16005d87ba1cSHelena Kotas // individual bits in the set, as long as we shift the values to start with 0 16015d87ba1cSHelena Kotas // by subtracting the value of llvm::Triple::Pixel first. 16025d87ba1cSHelena Kotas // 16038890209eSHelena Kotas // The N'th bit in the set will be set if the function has been scanned 16045d87ba1cSHelena Kotas // in shader environment whose llvm::Triple::EnvironmentType integer value 16055d87ba1cSHelena Kotas // equals (llvm::Triple::Pixel + N). 16065d87ba1cSHelena Kotas // 16078890209eSHelena Kotas // For example, if a function has been scanned in compute and pixel stage 16085d87ba1cSHelena Kotas // environment, the value will be 0x21 (100001 binary) because: 16095d87ba1cSHelena Kotas // 16105d87ba1cSHelena Kotas // (int)(llvm::Triple::Pixel - llvm::Triple::Pixel) == 0 16115d87ba1cSHelena Kotas // (int)(llvm::Triple::Compute - llvm::Triple::Pixel) == 5 16125d87ba1cSHelena Kotas // 16138890209eSHelena Kotas // A FunctionDecl is mapped to 0 (or not included in the map) if it has not 16148890209eSHelena Kotas // been scanned in any environment. 16158890209eSHelena Kotas llvm::DenseMap<const FunctionDecl *, unsigned> ScannedDecls; 16168890209eSHelena Kotas 16178890209eSHelena Kotas // Do not access these directly, use the get/set methods below to make 16188890209eSHelena Kotas // sure the values are in sync 16198890209eSHelena Kotas llvm::Triple::EnvironmentType CurrentShaderEnvironment; 16208890209eSHelena Kotas unsigned CurrentShaderStageBit; 16218890209eSHelena Kotas 16228890209eSHelena Kotas // True if scanning a function that was already scanned in a different 16238890209eSHelena Kotas // shader stage context, and therefore we should not report issues that 16248890209eSHelena Kotas // depend only on shader model version because they would be duplicate. 16258890209eSHelena Kotas bool ReportOnlyShaderStageIssues; 16268890209eSHelena Kotas 16278890209eSHelena Kotas // Helper methods for dealing with current stage context / environment 16285d87ba1cSHelena Kotas void SetShaderStageContext(llvm::Triple::EnvironmentType ShaderType) { 16298890209eSHelena Kotas static_assert(sizeof(unsigned) >= 4); 16305d87ba1cSHelena Kotas assert(HLSLShaderAttr::isValidShaderType(ShaderType)); 16315d87ba1cSHelena Kotas assert((unsigned)(ShaderType - llvm::Triple::Pixel) < 31 && 16325d87ba1cSHelena Kotas "ShaderType is too big for this bitmap"); // 31 is reserved for 16335d87ba1cSHelena Kotas // "unknown" 16348890209eSHelena Kotas 16355d87ba1cSHelena Kotas unsigned bitmapIndex = ShaderType - llvm::Triple::Pixel; 16365d87ba1cSHelena Kotas CurrentShaderEnvironment = ShaderType; 16375d87ba1cSHelena Kotas CurrentShaderStageBit = (1 << bitmapIndex); 16388890209eSHelena Kotas } 16398890209eSHelena Kotas 16408890209eSHelena Kotas void SetUnknownShaderStageContext() { 16418890209eSHelena Kotas CurrentShaderEnvironment = llvm::Triple::UnknownEnvironment; 16428890209eSHelena Kotas CurrentShaderStageBit = (1 << 31); 16438890209eSHelena Kotas } 16448890209eSHelena Kotas 16458890209eSHelena Kotas llvm::Triple::EnvironmentType GetCurrentShaderEnvironment() const { 16468890209eSHelena Kotas return CurrentShaderEnvironment; 16478890209eSHelena Kotas } 16488890209eSHelena Kotas 16498890209eSHelena Kotas bool InUnknownShaderStageContext() const { 16508890209eSHelena Kotas return CurrentShaderEnvironment == llvm::Triple::UnknownEnvironment; 16518890209eSHelena Kotas } 16528890209eSHelena Kotas 16538890209eSHelena Kotas // Helper methods for dealing with shader stage bitmap 16548890209eSHelena Kotas void AddToScannedFunctions(const FunctionDecl *FD) { 165559a3b415SKazu Hirata unsigned &ScannedStages = ScannedDecls[FD]; 16568890209eSHelena Kotas ScannedStages |= CurrentShaderStageBit; 16578890209eSHelena Kotas } 16588890209eSHelena Kotas 165959a3b415SKazu Hirata unsigned GetScannedStages(const FunctionDecl *FD) { return ScannedDecls[FD]; } 16608890209eSHelena Kotas 16618890209eSHelena Kotas bool WasAlreadyScannedInCurrentStage(const FunctionDecl *FD) { 16628890209eSHelena Kotas return WasAlreadyScannedInCurrentStage(GetScannedStages(FD)); 16638890209eSHelena Kotas } 16648890209eSHelena Kotas 16658890209eSHelena Kotas bool WasAlreadyScannedInCurrentStage(unsigned ScannerStages) { 16668890209eSHelena Kotas return ScannerStages & CurrentShaderStageBit; 16678890209eSHelena Kotas } 16688890209eSHelena Kotas 16698890209eSHelena Kotas static bool NeverBeenScanned(unsigned ScannedStages) { 16708890209eSHelena Kotas return ScannedStages == 0; 16718890209eSHelena Kotas } 16728890209eSHelena Kotas 16738890209eSHelena Kotas // Scanning methods 16748890209eSHelena Kotas void HandleFunctionOrMethodRef(FunctionDecl *FD, Expr *RefExpr); 16758890209eSHelena Kotas void CheckDeclAvailability(NamedDecl *D, const AvailabilityAttr *AA, 16768890209eSHelena Kotas SourceRange Range); 16778890209eSHelena Kotas const AvailabilityAttr *FindAvailabilityAttr(const Decl *D); 16788890209eSHelena Kotas bool HasMatchingEnvironmentOrNone(const AvailabilityAttr *AA); 16798890209eSHelena Kotas 16808890209eSHelena Kotas public: 1681cc7aef97SHelena Kotas DiagnoseHLSLAvailability(Sema &SemaRef) 1682cc7aef97SHelena Kotas : SemaRef(SemaRef), 1683cc7aef97SHelena Kotas CurrentShaderEnvironment(llvm::Triple::UnknownEnvironment), 1684cc7aef97SHelena Kotas CurrentShaderStageBit(0), ReportOnlyShaderStageIssues(false) {} 16858890209eSHelena Kotas 16868890209eSHelena Kotas // AST traversal methods 16878890209eSHelena Kotas void RunOnTranslationUnit(const TranslationUnitDecl *TU); 16888890209eSHelena Kotas void RunOnFunction(const FunctionDecl *FD); 16898890209eSHelena Kotas 1690dde802b1SSirraide bool VisitDeclRefExpr(DeclRefExpr *DRE) override { 16918890209eSHelena Kotas FunctionDecl *FD = llvm::dyn_cast<FunctionDecl>(DRE->getDecl()); 16928890209eSHelena Kotas if (FD) 16938890209eSHelena Kotas HandleFunctionOrMethodRef(FD, DRE); 16948890209eSHelena Kotas return true; 16958890209eSHelena Kotas } 16968890209eSHelena Kotas 1697dde802b1SSirraide bool VisitMemberExpr(MemberExpr *ME) override { 16988890209eSHelena Kotas FunctionDecl *FD = llvm::dyn_cast<FunctionDecl>(ME->getMemberDecl()); 16998890209eSHelena Kotas if (FD) 17008890209eSHelena Kotas HandleFunctionOrMethodRef(FD, ME); 17018890209eSHelena Kotas return true; 17028890209eSHelena Kotas } 17038890209eSHelena Kotas }; 17048890209eSHelena Kotas 17058890209eSHelena Kotas void DiagnoseHLSLAvailability::HandleFunctionOrMethodRef(FunctionDecl *FD, 17068890209eSHelena Kotas Expr *RefExpr) { 17078890209eSHelena Kotas assert((isa<DeclRefExpr>(RefExpr) || isa<MemberExpr>(RefExpr)) && 17088890209eSHelena Kotas "expected DeclRefExpr or MemberExpr"); 17098890209eSHelena Kotas 17108890209eSHelena Kotas // has a definition -> add to stack to be scanned 17118890209eSHelena Kotas const FunctionDecl *FDWithBody = nullptr; 17128890209eSHelena Kotas if (FD->hasBody(FDWithBody)) { 17138890209eSHelena Kotas if (!WasAlreadyScannedInCurrentStage(FDWithBody)) 17148890209eSHelena Kotas DeclsToScan.push_back(FDWithBody); 17158890209eSHelena Kotas return; 17168890209eSHelena Kotas } 17178890209eSHelena Kotas 17188890209eSHelena Kotas // no body -> diagnose availability 17198890209eSHelena Kotas const AvailabilityAttr *AA = FindAvailabilityAttr(FD); 17208890209eSHelena Kotas if (AA) 17218890209eSHelena Kotas CheckDeclAvailability( 17228890209eSHelena Kotas FD, AA, SourceRange(RefExpr->getBeginLoc(), RefExpr->getEndLoc())); 17238890209eSHelena Kotas } 17248890209eSHelena Kotas 17258890209eSHelena Kotas void DiagnoseHLSLAvailability::RunOnTranslationUnit( 17268890209eSHelena Kotas const TranslationUnitDecl *TU) { 17275196a91bSHelena Kotas 17288890209eSHelena Kotas // Iterate over all shader entry functions and library exports, and for those 17298890209eSHelena Kotas // that have a body (definiton), run diag scan on each, setting appropriate 17308890209eSHelena Kotas // shader environment context based on whether it is a shader entry function 17315196a91bSHelena Kotas // or an exported function. Exported functions can be in namespaces and in 17325196a91bSHelena Kotas // export declarations so we need to scan those declaration contexts as well. 17335196a91bSHelena Kotas llvm::SmallVector<const DeclContext *, 8> DeclContextsToScan; 17345196a91bSHelena Kotas DeclContextsToScan.push_back(TU); 17355196a91bSHelena Kotas 17365196a91bSHelena Kotas while (!DeclContextsToScan.empty()) { 17375196a91bSHelena Kotas const DeclContext *DC = DeclContextsToScan.pop_back_val(); 17385196a91bSHelena Kotas for (auto &D : DC->decls()) { 17395196a91bSHelena Kotas // do not scan implicit declaration generated by the implementation 17405196a91bSHelena Kotas if (D->isImplicit()) 17415196a91bSHelena Kotas continue; 17425196a91bSHelena Kotas 17435196a91bSHelena Kotas // for namespace or export declaration add the context to the list to be 17445196a91bSHelena Kotas // scanned later 17455196a91bSHelena Kotas if (llvm::dyn_cast<NamespaceDecl>(D) || llvm::dyn_cast<ExportDecl>(D)) { 17465196a91bSHelena Kotas DeclContextsToScan.push_back(llvm::dyn_cast<DeclContext>(D)); 17475196a91bSHelena Kotas continue; 17485196a91bSHelena Kotas } 17495196a91bSHelena Kotas 17505196a91bSHelena Kotas // skip over other decls or function decls without body 17518890209eSHelena Kotas const FunctionDecl *FD = llvm::dyn_cast<FunctionDecl>(D); 17528890209eSHelena Kotas if (!FD || !FD->isThisDeclarationADefinition()) 17538890209eSHelena Kotas continue; 17548890209eSHelena Kotas 17558890209eSHelena Kotas // shader entry point 17565196a91bSHelena Kotas if (HLSLShaderAttr *ShaderAttr = FD->getAttr<HLSLShaderAttr>()) { 17578890209eSHelena Kotas SetShaderStageContext(ShaderAttr->getType()); 17588890209eSHelena Kotas RunOnFunction(FD); 17598890209eSHelena Kotas continue; 17608890209eSHelena Kotas } 17615196a91bSHelena Kotas // exported library function 17625196a91bSHelena Kotas // FIXME: replace this loop with external linkage check once issue #92071 17635196a91bSHelena Kotas // is resolved 17645196a91bSHelena Kotas bool isExport = FD->isInExportDeclContext(); 17655196a91bSHelena Kotas if (!isExport) { 17665196a91bSHelena Kotas for (const auto *Redecl : FD->redecls()) { 17675196a91bSHelena Kotas if (Redecl->isInExportDeclContext()) { 17685196a91bSHelena Kotas isExport = true; 17695196a91bSHelena Kotas break; 17705196a91bSHelena Kotas } 17715196a91bSHelena Kotas } 17725196a91bSHelena Kotas } 17735196a91bSHelena Kotas if (isExport) { 17748890209eSHelena Kotas SetUnknownShaderStageContext(); 17758890209eSHelena Kotas RunOnFunction(FD); 17765196a91bSHelena Kotas continue; 17778890209eSHelena Kotas } 17785196a91bSHelena Kotas } 17798890209eSHelena Kotas } 17808890209eSHelena Kotas } 17818890209eSHelena Kotas 17828890209eSHelena Kotas void DiagnoseHLSLAvailability::RunOnFunction(const FunctionDecl *FD) { 17838890209eSHelena Kotas assert(DeclsToScan.empty() && "DeclsToScan should be empty"); 17848890209eSHelena Kotas DeclsToScan.push_back(FD); 17858890209eSHelena Kotas 17868890209eSHelena Kotas while (!DeclsToScan.empty()) { 17878890209eSHelena Kotas // Take one decl from the stack and check it by traversing its AST. 17888890209eSHelena Kotas // For any CallExpr found during the traversal add it's callee to the top of 17898890209eSHelena Kotas // the stack to be processed next. Functions already processed are stored in 17908890209eSHelena Kotas // ScannedDecls. 17915196a91bSHelena Kotas const FunctionDecl *FD = DeclsToScan.pop_back_val(); 17928890209eSHelena Kotas 17938890209eSHelena Kotas // Decl was already scanned 17948890209eSHelena Kotas const unsigned ScannedStages = GetScannedStages(FD); 17958890209eSHelena Kotas if (WasAlreadyScannedInCurrentStage(ScannedStages)) 17968890209eSHelena Kotas continue; 17978890209eSHelena Kotas 17988890209eSHelena Kotas ReportOnlyShaderStageIssues = !NeverBeenScanned(ScannedStages); 17998890209eSHelena Kotas 18008890209eSHelena Kotas AddToScannedFunctions(FD); 18018890209eSHelena Kotas TraverseStmt(FD->getBody()); 18028890209eSHelena Kotas } 18038890209eSHelena Kotas } 18048890209eSHelena Kotas 18058890209eSHelena Kotas bool DiagnoseHLSLAvailability::HasMatchingEnvironmentOrNone( 18068890209eSHelena Kotas const AvailabilityAttr *AA) { 18078890209eSHelena Kotas IdentifierInfo *IIEnvironment = AA->getEnvironment(); 18088890209eSHelena Kotas if (!IIEnvironment) 18098890209eSHelena Kotas return true; 18108890209eSHelena Kotas 18118890209eSHelena Kotas llvm::Triple::EnvironmentType CurrentEnv = GetCurrentShaderEnvironment(); 18128890209eSHelena Kotas if (CurrentEnv == llvm::Triple::UnknownEnvironment) 18138890209eSHelena Kotas return false; 18148890209eSHelena Kotas 18158890209eSHelena Kotas llvm::Triple::EnvironmentType AttrEnv = 18168890209eSHelena Kotas AvailabilityAttr::getEnvironmentType(IIEnvironment->getName()); 18178890209eSHelena Kotas 18188890209eSHelena Kotas return CurrentEnv == AttrEnv; 18198890209eSHelena Kotas } 18208890209eSHelena Kotas 18218890209eSHelena Kotas const AvailabilityAttr * 18228890209eSHelena Kotas DiagnoseHLSLAvailability::FindAvailabilityAttr(const Decl *D) { 18238890209eSHelena Kotas AvailabilityAttr const *PartialMatch = nullptr; 18248890209eSHelena Kotas // Check each AvailabilityAttr to find the one for this platform. 18258890209eSHelena Kotas // For multiple attributes with the same platform try to find one for this 18268890209eSHelena Kotas // environment. 18278890209eSHelena Kotas for (const auto *A : D->attrs()) { 18288890209eSHelena Kotas if (const auto *Avail = dyn_cast<AvailabilityAttr>(A)) { 18298890209eSHelena Kotas StringRef AttrPlatform = Avail->getPlatform()->getName(); 18308890209eSHelena Kotas StringRef TargetPlatform = 18318890209eSHelena Kotas SemaRef.getASTContext().getTargetInfo().getPlatformName(); 18328890209eSHelena Kotas 18338890209eSHelena Kotas // Match the platform name. 18348890209eSHelena Kotas if (AttrPlatform == TargetPlatform) { 18358890209eSHelena Kotas // Find the best matching attribute for this environment 18368890209eSHelena Kotas if (HasMatchingEnvironmentOrNone(Avail)) 18378890209eSHelena Kotas return Avail; 18388890209eSHelena Kotas PartialMatch = Avail; 18398890209eSHelena Kotas } 18408890209eSHelena Kotas } 18418890209eSHelena Kotas } 18428890209eSHelena Kotas return PartialMatch; 18438890209eSHelena Kotas } 18448890209eSHelena Kotas 18458890209eSHelena Kotas // Check availability against target shader model version and current shader 18468890209eSHelena Kotas // stage and emit diagnostic 18478890209eSHelena Kotas void DiagnoseHLSLAvailability::CheckDeclAvailability(NamedDecl *D, 18488890209eSHelena Kotas const AvailabilityAttr *AA, 18498890209eSHelena Kotas SourceRange Range) { 185030efdce7SHelena Kotas 185130efdce7SHelena Kotas IdentifierInfo *IIEnv = AA->getEnvironment(); 185230efdce7SHelena Kotas 185330efdce7SHelena Kotas if (!IIEnv) { 185430efdce7SHelena Kotas // The availability attribute does not have environment -> it depends only 185530efdce7SHelena Kotas // on shader model version and not on specific the shader stage. 185630efdce7SHelena Kotas 185730efdce7SHelena Kotas // Skip emitting the diagnostics if the diagnostic mode is set to 185830efdce7SHelena Kotas // strict (-fhlsl-strict-availability) because all relevant diagnostics 185930efdce7SHelena Kotas // were already emitted in the DiagnoseUnguardedAvailability scan 186030efdce7SHelena Kotas // (SemaAvailability.cpp). 186130efdce7SHelena Kotas if (SemaRef.getLangOpts().HLSLStrictAvailability) 18628890209eSHelena Kotas return; 18638890209eSHelena Kotas 186430efdce7SHelena Kotas // Do not report shader-stage-independent issues if scanning a function 186530efdce7SHelena Kotas // that was already scanned in a different shader stage context (they would 186630efdce7SHelena Kotas // be duplicate) 186730efdce7SHelena Kotas if (ReportOnlyShaderStageIssues) 186830efdce7SHelena Kotas return; 186930efdce7SHelena Kotas 187030efdce7SHelena Kotas } else { 187130efdce7SHelena Kotas // The availability attribute has environment -> we need to know 187230efdce7SHelena Kotas // the current stage context to property diagnose it. 187330efdce7SHelena Kotas if (InUnknownShaderStageContext()) 187430efdce7SHelena Kotas return; 187530efdce7SHelena Kotas } 187630efdce7SHelena Kotas 187730efdce7SHelena Kotas // Check introduced version and if environment matches 18788890209eSHelena Kotas bool EnvironmentMatches = HasMatchingEnvironmentOrNone(AA); 18798890209eSHelena Kotas VersionTuple Introduced = AA->getIntroduced(); 18808890209eSHelena Kotas VersionTuple TargetVersion = 18818890209eSHelena Kotas SemaRef.Context.getTargetInfo().getPlatformMinVersion(); 18828890209eSHelena Kotas 18838890209eSHelena Kotas if (TargetVersion >= Introduced && EnvironmentMatches) 18848890209eSHelena Kotas return; 18858890209eSHelena Kotas 18868890209eSHelena Kotas // Emit diagnostic message 18878890209eSHelena Kotas const TargetInfo &TI = SemaRef.getASTContext().getTargetInfo(); 18888890209eSHelena Kotas llvm::StringRef PlatformName( 18898890209eSHelena Kotas AvailabilityAttr::getPrettyPlatformName(TI.getPlatformName())); 18908890209eSHelena Kotas 18918890209eSHelena Kotas llvm::StringRef CurrentEnvStr = 189230efdce7SHelena Kotas llvm::Triple::getEnvironmentTypeName(GetCurrentShaderEnvironment()); 18938890209eSHelena Kotas 189430efdce7SHelena Kotas llvm::StringRef AttrEnvStr = 189530efdce7SHelena Kotas AA->getEnvironment() ? AA->getEnvironment()->getName() : ""; 18968890209eSHelena Kotas bool UseEnvironment = !AttrEnvStr.empty(); 18978890209eSHelena Kotas 18988890209eSHelena Kotas if (EnvironmentMatches) { 18998890209eSHelena Kotas SemaRef.Diag(Range.getBegin(), diag::warn_hlsl_availability) 19008890209eSHelena Kotas << Range << D << PlatformName << Introduced.getAsString() 19018890209eSHelena Kotas << UseEnvironment << CurrentEnvStr; 19028890209eSHelena Kotas } else { 19038890209eSHelena Kotas SemaRef.Diag(Range.getBegin(), diag::warn_hlsl_availability_unavailable) 19048890209eSHelena Kotas << Range << D; 19058890209eSHelena Kotas } 19068890209eSHelena Kotas 19078890209eSHelena Kotas SemaRef.Diag(D->getLocation(), diag::note_partial_availability_specified_here) 19088890209eSHelena Kotas << D << PlatformName << Introduced.getAsString() 19098890209eSHelena Kotas << SemaRef.Context.getTargetInfo().getPlatformMinVersion().getAsString() 19108890209eSHelena Kotas << UseEnvironment << AttrEnvStr << CurrentEnvStr; 19118890209eSHelena Kotas } 19128890209eSHelena Kotas 19138890209eSHelena Kotas } // namespace 19148890209eSHelena Kotas 19158890209eSHelena Kotas void SemaHLSL::DiagnoseAvailabilityViolations(TranslationUnitDecl *TU) { 191630efdce7SHelena Kotas // Skip running the diagnostics scan if the diagnostic mode is 191730efdce7SHelena Kotas // strict (-fhlsl-strict-availability) and the target shader stage is known 191830efdce7SHelena Kotas // because all relevant diagnostics were already emitted in the 191930efdce7SHelena Kotas // DiagnoseUnguardedAvailability scan (SemaAvailability.cpp). 192030efdce7SHelena Kotas const TargetInfo &TI = SemaRef.getASTContext().getTargetInfo(); 192130efdce7SHelena Kotas if (SemaRef.getLangOpts().HLSLStrictAvailability && 192230efdce7SHelena Kotas TI.getTriple().getEnvironment() != llvm::Triple::EnvironmentType::Library) 192330efdce7SHelena Kotas return; 192430efdce7SHelena Kotas 19258890209eSHelena Kotas DiagnoseHLSLAvailability(SemaRef).RunOnTranslationUnit(TU); 19268890209eSHelena Kotas } 1927f1c54d72SVlad Serebrennikov 1928f1c54d72SVlad Serebrennikov // Helper function for CheckHLSLBuiltinFunctionCall 1929eddbd4ebSCongcong Cai static bool CheckVectorElementCallArgs(Sema *S, CallExpr *TheCall) { 1930f1c54d72SVlad Serebrennikov assert(TheCall->getNumArgs() > 1); 1931f1c54d72SVlad Serebrennikov ExprResult A = TheCall->getArg(0); 1932f1c54d72SVlad Serebrennikov 1933f1c54d72SVlad Serebrennikov QualType ArgTyA = A.get()->getType(); 1934f1c54d72SVlad Serebrennikov 1935f1c54d72SVlad Serebrennikov auto *VecTyA = ArgTyA->getAs<VectorType>(); 1936f1c54d72SVlad Serebrennikov SourceLocation BuiltinLoc = TheCall->getBeginLoc(); 1937f1c54d72SVlad Serebrennikov 19385a735a28SFarzon Lotfi bool AllBArgAreVectors = true; 1939f1c54d72SVlad Serebrennikov for (unsigned i = 1; i < TheCall->getNumArgs(); ++i) { 1940f1c54d72SVlad Serebrennikov ExprResult B = TheCall->getArg(i); 1941f1c54d72SVlad Serebrennikov QualType ArgTyB = B.get()->getType(); 1942f1c54d72SVlad Serebrennikov auto *VecTyB = ArgTyB->getAs<VectorType>(); 19435a735a28SFarzon Lotfi if (VecTyB == nullptr) 19445a735a28SFarzon Lotfi AllBArgAreVectors &= false; 19455a735a28SFarzon Lotfi if (VecTyA && VecTyB == nullptr) { 19465a735a28SFarzon Lotfi // Note: if we get here 'B' is scalar which 19475a735a28SFarzon Lotfi // requires a VectorSplat on ArgN 19485a735a28SFarzon Lotfi S->Diag(BuiltinLoc, diag::err_vec_builtin_non_vector) 19495a735a28SFarzon Lotfi << TheCall->getDirectCallee() << /*useAllTerminology*/ true 19505a735a28SFarzon Lotfi << SourceRange(A.get()->getBeginLoc(), B.get()->getEndLoc()); 19515a735a28SFarzon Lotfi return true; 19525a735a28SFarzon Lotfi } 1953f1c54d72SVlad Serebrennikov if (VecTyA && VecTyB) { 1954f1c54d72SVlad Serebrennikov bool retValue = false; 1955f1c54d72SVlad Serebrennikov if (VecTyA->getElementType() != VecTyB->getElementType()) { 1956f1c54d72SVlad Serebrennikov // Note: type promotion is intended to be handeled via the intrinsics 1957f1c54d72SVlad Serebrennikov // and not the builtin itself. 1958f1c54d72SVlad Serebrennikov S->Diag(TheCall->getBeginLoc(), 1959f1c54d72SVlad Serebrennikov diag::err_vec_builtin_incompatible_vector) 1960f1c54d72SVlad Serebrennikov << TheCall->getDirectCallee() << /*useAllTerminology*/ true 1961f1c54d72SVlad Serebrennikov << SourceRange(A.get()->getBeginLoc(), B.get()->getEndLoc()); 1962f1c54d72SVlad Serebrennikov retValue = true; 1963f1c54d72SVlad Serebrennikov } 1964f1c54d72SVlad Serebrennikov if (VecTyA->getNumElements() != VecTyB->getNumElements()) { 1965f1c54d72SVlad Serebrennikov // You should only be hitting this case if you are calling the builtin 1966f1c54d72SVlad Serebrennikov // directly. HLSL intrinsics should avoid this case via a 1967f1c54d72SVlad Serebrennikov // HLSLVectorTruncation. 1968f1c54d72SVlad Serebrennikov S->Diag(BuiltinLoc, diag::err_vec_builtin_incompatible_vector) 1969f1c54d72SVlad Serebrennikov << TheCall->getDirectCallee() << /*useAllTerminology*/ true 19705a735a28SFarzon Lotfi << SourceRange(A.get()->getBeginLoc(), B.get()->getEndLoc()); 1971f1c54d72SVlad Serebrennikov retValue = true; 1972f1c54d72SVlad Serebrennikov } 19735a735a28SFarzon Lotfi if (retValue) 1974f1c54d72SVlad Serebrennikov return retValue; 1975f1c54d72SVlad Serebrennikov } 1976f1c54d72SVlad Serebrennikov } 1977f1c54d72SVlad Serebrennikov 19785a735a28SFarzon Lotfi if (VecTyA == nullptr && AllBArgAreVectors) { 19795a735a28SFarzon Lotfi // Note: if we get here 'A' is a scalar which 19805a735a28SFarzon Lotfi // requires a VectorSplat on Arg0 1981f1c54d72SVlad Serebrennikov S->Diag(BuiltinLoc, diag::err_vec_builtin_non_vector) 1982f1c54d72SVlad Serebrennikov << TheCall->getDirectCallee() << /*useAllTerminology*/ true 19835a735a28SFarzon Lotfi << SourceRange(A.get()->getBeginLoc(), A.get()->getEndLoc()); 1984f1c54d72SVlad Serebrennikov return true; 1985f1c54d72SVlad Serebrennikov } 19865a735a28SFarzon Lotfi return false; 19875a735a28SFarzon Lotfi } 1988f1c54d72SVlad Serebrennikov 1989cac97833SHelena Kotas static bool CheckArgTypeMatches(Sema *S, Expr *Arg, QualType ExpectedType) { 1990cac97833SHelena Kotas QualType ArgType = Arg->getType(); 1991cac97833SHelena Kotas if (!S->getASTContext().hasSameUnqualifiedType(ArgType, ExpectedType)) { 1992cac97833SHelena Kotas S->Diag(Arg->getBeginLoc(), diag::err_typecheck_convert_incompatible) 1993cac97833SHelena Kotas << ArgType << ExpectedType << 1 << 0 << 0; 1994cac97833SHelena Kotas return true; 1995cac97833SHelena Kotas } 1996cac97833SHelena Kotas return false; 1997cac97833SHelena Kotas } 1998cac97833SHelena Kotas 1999cbdd14eeSCongcong Cai static bool CheckArgTypeIsCorrect( 2000481bce01Sjoaosaffran Sema *S, Expr *Arg, QualType ExpectedType, 2001f1c54d72SVlad Serebrennikov llvm::function_ref<bool(clang::QualType PassedType)> Check) { 2002481bce01Sjoaosaffran QualType PassedType = Arg->getType(); 2003f1c54d72SVlad Serebrennikov if (Check(PassedType)) { 2004f1c54d72SVlad Serebrennikov if (auto *VecTyA = PassedType->getAs<VectorType>()) 2005f1c54d72SVlad Serebrennikov ExpectedType = S->Context.getVectorType( 2006f1c54d72SVlad Serebrennikov ExpectedType, VecTyA->getNumElements(), VecTyA->getVectorKind()); 2007481bce01Sjoaosaffran S->Diag(Arg->getBeginLoc(), diag::err_typecheck_convert_incompatible) 2008f1c54d72SVlad Serebrennikov << PassedType << ExpectedType << 1 << 0 << 0; 2009f1c54d72SVlad Serebrennikov return true; 2010f1c54d72SVlad Serebrennikov } 2011481bce01Sjoaosaffran return false; 2012481bce01Sjoaosaffran } 2013481bce01Sjoaosaffran 2014cbdd14eeSCongcong Cai static bool CheckAllArgTypesAreCorrect( 2015481bce01Sjoaosaffran Sema *S, CallExpr *TheCall, QualType ExpectedType, 2016481bce01Sjoaosaffran llvm::function_ref<bool(clang::QualType PassedType)> Check) { 2017481bce01Sjoaosaffran for (unsigned i = 0; i < TheCall->getNumArgs(); ++i) { 2018481bce01Sjoaosaffran Expr *Arg = TheCall->getArg(i); 2019481bce01Sjoaosaffran if (CheckArgTypeIsCorrect(S, Arg, ExpectedType, Check)) { 2020481bce01Sjoaosaffran return true; 2021481bce01Sjoaosaffran } 2022f1c54d72SVlad Serebrennikov } 2023f1c54d72SVlad Serebrennikov return false; 2024f1c54d72SVlad Serebrennikov } 2025f1c54d72SVlad Serebrennikov 2026eddbd4ebSCongcong Cai static bool CheckAllArgsHaveFloatRepresentation(Sema *S, CallExpr *TheCall) { 2027f1c54d72SVlad Serebrennikov auto checkAllFloatTypes = [](clang::QualType PassedType) -> bool { 2028f1c54d72SVlad Serebrennikov return !PassedType->hasFloatingRepresentation(); 2029f1c54d72SVlad Serebrennikov }; 2030481bce01Sjoaosaffran return CheckAllArgTypesAreCorrect(S, TheCall, S->Context.FloatTy, 2031f1c54d72SVlad Serebrennikov checkAllFloatTypes); 2032f1c54d72SVlad Serebrennikov } 2033f1c54d72SVlad Serebrennikov 2034eddbd4ebSCongcong Cai static bool CheckFloatOrHalfRepresentations(Sema *S, CallExpr *TheCall) { 2035f1c54d72SVlad Serebrennikov auto checkFloatorHalf = [](clang::QualType PassedType) -> bool { 2036f1c54d72SVlad Serebrennikov clang::QualType BaseType = 2037f1c54d72SVlad Serebrennikov PassedType->isVectorType() 2038f1c54d72SVlad Serebrennikov ? PassedType->getAs<clang::VectorType>()->getElementType() 2039f1c54d72SVlad Serebrennikov : PassedType; 2040f1c54d72SVlad Serebrennikov return !BaseType->isHalfType() && !BaseType->isFloat32Type(); 2041f1c54d72SVlad Serebrennikov }; 2042481bce01Sjoaosaffran return CheckAllArgTypesAreCorrect(S, TheCall, S->Context.FloatTy, 2043f1c54d72SVlad Serebrennikov checkFloatorHalf); 2044f1c54d72SVlad Serebrennikov } 2045f1c54d72SVlad Serebrennikov 2046481bce01Sjoaosaffran static bool CheckModifiableLValue(Sema *S, CallExpr *TheCall, 2047481bce01Sjoaosaffran unsigned ArgIndex) { 2048481bce01Sjoaosaffran auto *Arg = TheCall->getArg(ArgIndex); 2049481bce01Sjoaosaffran SourceLocation OrigLoc = Arg->getExprLoc(); 2050481bce01Sjoaosaffran if (Arg->IgnoreCasts()->isModifiableLvalue(S->Context, &OrigLoc) == 2051481bce01Sjoaosaffran Expr::MLV_Valid) 2052481bce01Sjoaosaffran return false; 2053481bce01Sjoaosaffran S->Diag(OrigLoc, diag::error_hlsl_inout_lvalue) << Arg << 0; 2054481bce01Sjoaosaffran return true; 2055481bce01Sjoaosaffran } 2056481bce01Sjoaosaffran 2057eddbd4ebSCongcong Cai static bool CheckNoDoubleVectors(Sema *S, CallExpr *TheCall) { 2058f1c54d72SVlad Serebrennikov auto checkDoubleVector = [](clang::QualType PassedType) -> bool { 2059f1c54d72SVlad Serebrennikov if (const auto *VecTy = PassedType->getAs<VectorType>()) 2060f1c54d72SVlad Serebrennikov return VecTy->getElementType()->isDoubleType(); 2061f1c54d72SVlad Serebrennikov return false; 2062f1c54d72SVlad Serebrennikov }; 2063481bce01Sjoaosaffran return CheckAllArgTypesAreCorrect(S, TheCall, S->Context.FloatTy, 2064f1c54d72SVlad Serebrennikov checkDoubleVector); 2065f1c54d72SVlad Serebrennikov } 206699608f11STim Gymnich static bool CheckFloatingOrIntRepresentation(Sema *S, CallExpr *TheCall) { 2067dce50397STim Gymnich auto checkAllSignedTypes = [](clang::QualType PassedType) -> bool { 206899608f11STim Gymnich return !PassedType->hasIntegerRepresentation() && 2069dce50397STim Gymnich !PassedType->hasFloatingRepresentation(); 2070dce50397STim Gymnich }; 2071481bce01Sjoaosaffran return CheckAllArgTypesAreCorrect(S, TheCall, S->Context.IntTy, 2072dce50397STim Gymnich checkAllSignedTypes); 2073dce50397STim Gymnich } 2074f1c54d72SVlad Serebrennikov 2075eddbd4ebSCongcong Cai static bool CheckUnsignedIntRepresentation(Sema *S, CallExpr *TheCall) { 2076f1c54d72SVlad Serebrennikov auto checkAllUnsignedTypes = [](clang::QualType PassedType) -> bool { 2077f1c54d72SVlad Serebrennikov return !PassedType->hasUnsignedIntegerRepresentation(); 2078f1c54d72SVlad Serebrennikov }; 2079481bce01Sjoaosaffran return CheckAllArgTypesAreCorrect(S, TheCall, S->Context.UnsignedIntTy, 2080f1c54d72SVlad Serebrennikov checkAllUnsignedTypes); 2081f1c54d72SVlad Serebrennikov } 2082f1c54d72SVlad Serebrennikov 2083eddbd4ebSCongcong Cai static void SetElementTypeAsReturnType(Sema *S, CallExpr *TheCall, 2084f1c54d72SVlad Serebrennikov QualType ReturnType) { 2085f1c54d72SVlad Serebrennikov auto *VecTyA = TheCall->getArg(0)->getType()->getAs<VectorType>(); 2086f1c54d72SVlad Serebrennikov if (VecTyA) 2087f1c54d72SVlad Serebrennikov ReturnType = S->Context.getVectorType(ReturnType, VecTyA->getNumElements(), 2088f1c54d72SVlad Serebrennikov VectorKind::Generic); 2089f1c54d72SVlad Serebrennikov TheCall->setType(ReturnType); 2090f1c54d72SVlad Serebrennikov } 2091f1c54d72SVlad Serebrennikov 20920f349b7aSSarah Spall static bool CheckScalarOrVector(Sema *S, CallExpr *TheCall, QualType Scalar, 20930f349b7aSSarah Spall unsigned ArgIndex) { 20940f349b7aSSarah Spall assert(TheCall->getNumArgs() >= ArgIndex); 20950f349b7aSSarah Spall QualType ArgType = TheCall->getArg(ArgIndex)->getType(); 20960f349b7aSSarah Spall auto *VTy = ArgType->getAs<VectorType>(); 20970f349b7aSSarah Spall // not the scalar or vector<scalar> 20980f349b7aSSarah Spall if (!(S->Context.hasSameUnqualifiedType(ArgType, Scalar) || 20990f349b7aSSarah Spall (VTy && 21000f349b7aSSarah Spall S->Context.hasSameUnqualifiedType(VTy->getElementType(), Scalar)))) { 21010f349b7aSSarah Spall S->Diag(TheCall->getArg(0)->getBeginLoc(), 21020f349b7aSSarah Spall diag::err_typecheck_expect_scalar_or_vector) 21030f349b7aSSarah Spall << ArgType << Scalar; 21040f349b7aSSarah Spall return true; 21050f349b7aSSarah Spall } 21060f349b7aSSarah Spall return false; 21070f349b7aSSarah Spall } 21080f349b7aSSarah Spall 21096d13cc94SFinn Plummer static bool CheckAnyScalarOrVector(Sema *S, CallExpr *TheCall, 21106d13cc94SFinn Plummer unsigned ArgIndex) { 21116d13cc94SFinn Plummer assert(TheCall->getNumArgs() >= ArgIndex); 21126d13cc94SFinn Plummer QualType ArgType = TheCall->getArg(ArgIndex)->getType(); 21136d13cc94SFinn Plummer auto *VTy = ArgType->getAs<VectorType>(); 21146d13cc94SFinn Plummer // not the scalar or vector<scalar> 21156d13cc94SFinn Plummer if (!(ArgType->isScalarType() || 21166d13cc94SFinn Plummer (VTy && VTy->getElementType()->isScalarType()))) { 21176d13cc94SFinn Plummer S->Diag(TheCall->getArg(0)->getBeginLoc(), 21186d13cc94SFinn Plummer diag::err_typecheck_expect_any_scalar_or_vector) 21194446a984SAdam Yang << ArgType << 1; 21204446a984SAdam Yang return true; 21214446a984SAdam Yang } 21224446a984SAdam Yang return false; 21234446a984SAdam Yang } 21244446a984SAdam Yang 21254446a984SAdam Yang static bool CheckWaveActive(Sema *S, CallExpr *TheCall) { 21264446a984SAdam Yang QualType BoolType = S->getASTContext().BoolTy; 21274446a984SAdam Yang assert(TheCall->getNumArgs() >= 1); 21284446a984SAdam Yang QualType ArgType = TheCall->getArg(0)->getType(); 21294446a984SAdam Yang auto *VTy = ArgType->getAs<VectorType>(); 21304446a984SAdam Yang // is the bool or vector<bool> 21314446a984SAdam Yang if (S->Context.hasSameUnqualifiedType(ArgType, BoolType) || 21324446a984SAdam Yang (VTy && 21334446a984SAdam Yang S->Context.hasSameUnqualifiedType(VTy->getElementType(), BoolType))) { 21344446a984SAdam Yang S->Diag(TheCall->getArg(0)->getBeginLoc(), 21354446a984SAdam Yang diag::err_typecheck_expect_any_scalar_or_vector) 21364446a984SAdam Yang << ArgType << 0; 21376d13cc94SFinn Plummer return true; 21386d13cc94SFinn Plummer } 21396d13cc94SFinn Plummer return false; 21406d13cc94SFinn Plummer } 21416d13cc94SFinn Plummer 21420f349b7aSSarah Spall static bool CheckBoolSelect(Sema *S, CallExpr *TheCall) { 21430f349b7aSSarah Spall assert(TheCall->getNumArgs() == 3); 21440f349b7aSSarah Spall Expr *Arg1 = TheCall->getArg(1); 21450f349b7aSSarah Spall Expr *Arg2 = TheCall->getArg(2); 21460f349b7aSSarah Spall if (!S->Context.hasSameUnqualifiedType(Arg1->getType(), Arg2->getType())) { 21470f349b7aSSarah Spall S->Diag(TheCall->getBeginLoc(), 21480f349b7aSSarah Spall diag::err_typecheck_call_different_arg_types) 21490f349b7aSSarah Spall << Arg1->getType() << Arg2->getType() << Arg1->getSourceRange() 21500f349b7aSSarah Spall << Arg2->getSourceRange(); 21510f349b7aSSarah Spall return true; 21520f349b7aSSarah Spall } 21530f349b7aSSarah Spall 21540f349b7aSSarah Spall TheCall->setType(Arg1->getType()); 21550f349b7aSSarah Spall return false; 21560f349b7aSSarah Spall } 21570f349b7aSSarah Spall 21580f349b7aSSarah Spall static bool CheckVectorSelect(Sema *S, CallExpr *TheCall) { 21590f349b7aSSarah Spall assert(TheCall->getNumArgs() == 3); 21600f349b7aSSarah Spall Expr *Arg1 = TheCall->getArg(1); 21610f349b7aSSarah Spall Expr *Arg2 = TheCall->getArg(2); 21620f349b7aSSarah Spall if (!Arg1->getType()->isVectorType()) { 21630f349b7aSSarah Spall S->Diag(Arg1->getBeginLoc(), diag::err_builtin_non_vector_type) 21640f349b7aSSarah Spall << "Second" << TheCall->getDirectCallee() << Arg1->getType() 21650f349b7aSSarah Spall << Arg1->getSourceRange(); 21660f349b7aSSarah Spall return true; 21670f349b7aSSarah Spall } 21680f349b7aSSarah Spall 21690f349b7aSSarah Spall if (!Arg2->getType()->isVectorType()) { 21700f349b7aSSarah Spall S->Diag(Arg2->getBeginLoc(), diag::err_builtin_non_vector_type) 21710f349b7aSSarah Spall << "Third" << TheCall->getDirectCallee() << Arg2->getType() 21720f349b7aSSarah Spall << Arg2->getSourceRange(); 21730f349b7aSSarah Spall return true; 21740f349b7aSSarah Spall } 21750f349b7aSSarah Spall 21760f349b7aSSarah Spall if (!S->Context.hasSameUnqualifiedType(Arg1->getType(), Arg2->getType())) { 21770f349b7aSSarah Spall S->Diag(TheCall->getBeginLoc(), 21780f349b7aSSarah Spall diag::err_typecheck_call_different_arg_types) 21790f349b7aSSarah Spall << Arg1->getType() << Arg2->getType() << Arg1->getSourceRange() 21800f349b7aSSarah Spall << Arg2->getSourceRange(); 21810f349b7aSSarah Spall return true; 21820f349b7aSSarah Spall } 21830f349b7aSSarah Spall 21840f349b7aSSarah Spall // caller has checked that Arg0 is a vector. 21850f349b7aSSarah Spall // check all three args have the same length. 21860f349b7aSSarah Spall if (TheCall->getArg(0)->getType()->getAs<VectorType>()->getNumElements() != 21870f349b7aSSarah Spall Arg1->getType()->getAs<VectorType>()->getNumElements()) { 21880f349b7aSSarah Spall S->Diag(TheCall->getBeginLoc(), 21890f349b7aSSarah Spall diag::err_typecheck_vector_lengths_not_equal) 21900f349b7aSSarah Spall << TheCall->getArg(0)->getType() << Arg1->getType() 21910f349b7aSSarah Spall << TheCall->getArg(0)->getSourceRange() << Arg1->getSourceRange(); 21920f349b7aSSarah Spall return true; 21930f349b7aSSarah Spall } 21940f349b7aSSarah Spall TheCall->setType(Arg1->getType()); 21950f349b7aSSarah Spall return false; 21960f349b7aSSarah Spall } 21970f349b7aSSarah Spall 2198cac97833SHelena Kotas static bool CheckResourceHandle( 2199cac97833SHelena Kotas Sema *S, CallExpr *TheCall, unsigned ArgIndex, 2200cac97833SHelena Kotas llvm::function_ref<bool(const HLSLAttributedResourceType *ResType)> Check = 2201cac97833SHelena Kotas nullptr) { 2202cac97833SHelena Kotas assert(TheCall->getNumArgs() >= ArgIndex); 2203cac97833SHelena Kotas QualType ArgType = TheCall->getArg(ArgIndex)->getType(); 2204cac97833SHelena Kotas const HLSLAttributedResourceType *ResTy = 2205cac97833SHelena Kotas ArgType.getTypePtr()->getAs<HLSLAttributedResourceType>(); 2206cac97833SHelena Kotas if (!ResTy) { 2207bd92e462SJustin Bogner S->Diag(TheCall->getArg(ArgIndex)->getBeginLoc(), 2208cac97833SHelena Kotas diag::err_typecheck_expect_hlsl_resource) 2209cac97833SHelena Kotas << ArgType; 2210cac97833SHelena Kotas return true; 2211cac97833SHelena Kotas } 2212cac97833SHelena Kotas if (Check && Check(ResTy)) { 2213cac97833SHelena Kotas S->Diag(TheCall->getArg(ArgIndex)->getExprLoc(), 2214cac97833SHelena Kotas diag::err_invalid_hlsl_resource_type) 2215cac97833SHelena Kotas << ArgType; 2216cac97833SHelena Kotas return true; 2217cac97833SHelena Kotas } 2218cac97833SHelena Kotas return false; 2219cac97833SHelena Kotas } 2220cac97833SHelena Kotas 2221f1c54d72SVlad Serebrennikov // Note: returning true in this case results in CheckBuiltinFunctionCall 2222f1c54d72SVlad Serebrennikov // returning an ExprError 2223f1c54d72SVlad Serebrennikov bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { 2224f1c54d72SVlad Serebrennikov switch (BuiltinID) { 2225bd92e462SJustin Bogner case Builtin::BI__builtin_hlsl_resource_getpointer: { 2226bd92e462SJustin Bogner if (SemaRef.checkArgCount(TheCall, 2) || 2227bd92e462SJustin Bogner CheckResourceHandle(&SemaRef, TheCall, 0) || 2228bd92e462SJustin Bogner CheckArgTypeMatches(&SemaRef, TheCall->getArg(1), 2229bd92e462SJustin Bogner SemaRef.getASTContext().UnsignedIntTy)) 2230bd92e462SJustin Bogner return true; 2231bd92e462SJustin Bogner 2232bd92e462SJustin Bogner auto *ResourceTy = 2233bd92e462SJustin Bogner TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>(); 2234bd92e462SJustin Bogner QualType ContainedTy = ResourceTy->getContainedType(); 2235bd92e462SJustin Bogner // TODO: Map to an hlsl_device address space. 2236bd92e462SJustin Bogner TheCall->setType(getASTContext().getPointerType(ContainedTy)); 2237bd92e462SJustin Bogner TheCall->setValueKind(VK_LValue); 2238bd92e462SJustin Bogner 2239bd92e462SJustin Bogner break; 2240bd92e462SJustin Bogner } 224196e6255eSFarzon Lotfi case Builtin::BI__builtin_hlsl_all: 224296e6255eSFarzon Lotfi case Builtin::BI__builtin_hlsl_any: { 2243f1c54d72SVlad Serebrennikov if (SemaRef.checkArgCount(TheCall, 1)) 2244f1c54d72SVlad Serebrennikov return true; 2245f1c54d72SVlad Serebrennikov break; 2246f1c54d72SVlad Serebrennikov } 2247a5f501e3SFinn Plummer case Builtin::BI__builtin_hlsl_asdouble: { 2248a5f501e3SFinn Plummer if (SemaRef.checkArgCount(TheCall, 2)) 2249a5f501e3SFinn Plummer return true; 2250a5f501e3SFinn Plummer if (CheckUnsignedIntRepresentation(&SemaRef, TheCall)) 2251a5f501e3SFinn Plummer return true; 2252a5f501e3SFinn Plummer 2253a5f501e3SFinn Plummer SetElementTypeAsReturnType(&SemaRef, TheCall, getASTContext().DoubleTy); 2254a5f501e3SFinn Plummer break; 2255a5f501e3SFinn Plummer } 2256f1c54d72SVlad Serebrennikov case Builtin::BI__builtin_hlsl_elementwise_clamp: { 2257f1c54d72SVlad Serebrennikov if (SemaRef.checkArgCount(TheCall, 3)) 2258f1c54d72SVlad Serebrennikov return true; 2259f1c54d72SVlad Serebrennikov if (CheckVectorElementCallArgs(&SemaRef, TheCall)) 2260f1c54d72SVlad Serebrennikov return true; 2261f1c54d72SVlad Serebrennikov if (SemaRef.BuiltinElementwiseTernaryMath( 2262f1c54d72SVlad Serebrennikov TheCall, /*CheckForFloatArgs*/ 2263f1c54d72SVlad Serebrennikov TheCall->getArg(0)->getType()->hasFloatingRepresentation())) 2264f1c54d72SVlad Serebrennikov return true; 2265f1c54d72SVlad Serebrennikov break; 2266f1c54d72SVlad Serebrennikov } 2267c098435eSJoshua Batista case Builtin::BI__builtin_hlsl_cross: { 2268c098435eSJoshua Batista if (SemaRef.checkArgCount(TheCall, 2)) 2269c098435eSJoshua Batista return true; 2270c098435eSJoshua Batista if (CheckVectorElementCallArgs(&SemaRef, TheCall)) 2271c098435eSJoshua Batista return true; 2272c098435eSJoshua Batista if (CheckFloatOrHalfRepresentations(&SemaRef, TheCall)) 2273c098435eSJoshua Batista return true; 2274c098435eSJoshua Batista // ensure both args have 3 elements 2275c098435eSJoshua Batista int NumElementsArg1 = 227643892205Ssmanna12 TheCall->getArg(0)->getType()->castAs<VectorType>()->getNumElements(); 2277c098435eSJoshua Batista int NumElementsArg2 = 227843892205Ssmanna12 TheCall->getArg(1)->getType()->castAs<VectorType>()->getNumElements(); 2279c098435eSJoshua Batista 2280c098435eSJoshua Batista if (NumElementsArg1 != 3) { 2281c098435eSJoshua Batista int LessOrMore = NumElementsArg1 > 3 ? 1 : 0; 2282c098435eSJoshua Batista SemaRef.Diag(TheCall->getBeginLoc(), 2283c098435eSJoshua Batista diag::err_vector_incorrect_num_elements) 2284c098435eSJoshua Batista << LessOrMore << 3 << NumElementsArg1 << /*operand*/ 1; 2285c098435eSJoshua Batista return true; 2286c098435eSJoshua Batista } 2287c098435eSJoshua Batista if (NumElementsArg2 != 3) { 2288c098435eSJoshua Batista int LessOrMore = NumElementsArg2 > 3 ? 1 : 0; 2289c098435eSJoshua Batista 2290c098435eSJoshua Batista SemaRef.Diag(TheCall->getBeginLoc(), 2291c098435eSJoshua Batista diag::err_vector_incorrect_num_elements) 2292c098435eSJoshua Batista << LessOrMore << 3 << NumElementsArg2 << /*operand*/ 1; 2293c098435eSJoshua Batista return true; 2294c098435eSJoshua Batista } 2295c098435eSJoshua Batista 2296c098435eSJoshua Batista ExprResult A = TheCall->getArg(0); 2297c098435eSJoshua Batista QualType ArgTyA = A.get()->getType(); 2298c098435eSJoshua Batista // return type is the same as the input type 2299c098435eSJoshua Batista TheCall->setType(ArgTyA); 2300c098435eSJoshua Batista break; 2301c098435eSJoshua Batista } 2302f1c54d72SVlad Serebrennikov case Builtin::BI__builtin_hlsl_dot: { 2303f1c54d72SVlad Serebrennikov if (SemaRef.checkArgCount(TheCall, 2)) 2304f1c54d72SVlad Serebrennikov return true; 2305f1c54d72SVlad Serebrennikov if (CheckVectorElementCallArgs(&SemaRef, TheCall)) 2306f1c54d72SVlad Serebrennikov return true; 2307f1c54d72SVlad Serebrennikov if (SemaRef.BuiltinVectorToScalarMath(TheCall)) 2308f1c54d72SVlad Serebrennikov return true; 2309f1c54d72SVlad Serebrennikov if (CheckNoDoubleVectors(&SemaRef, TheCall)) 2310f1c54d72SVlad Serebrennikov return true; 2311f1c54d72SVlad Serebrennikov break; 2312f1c54d72SVlad Serebrennikov } 23134f48abffSAshley Coleman case Builtin::BI__builtin_hlsl_elementwise_firstbithigh: 23144f48abffSAshley Coleman case Builtin::BI__builtin_hlsl_elementwise_firstbitlow: { 2315fb90733eSSarah Spall if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall)) 2316fb90733eSSarah Spall return true; 2317fb90733eSSarah Spall 2318fb90733eSSarah Spall const Expr *Arg = TheCall->getArg(0); 2319fb90733eSSarah Spall QualType ArgTy = Arg->getType(); 2320fb90733eSSarah Spall QualType EltTy = ArgTy; 2321fb90733eSSarah Spall 2322fb90733eSSarah Spall QualType ResTy = SemaRef.Context.UnsignedIntTy; 2323fb90733eSSarah Spall 2324fb90733eSSarah Spall if (auto *VecTy = EltTy->getAs<VectorType>()) { 2325fb90733eSSarah Spall EltTy = VecTy->getElementType(); 2326fb90733eSSarah Spall ResTy = SemaRef.Context.getVectorType(ResTy, VecTy->getNumElements(), 2327fb90733eSSarah Spall VecTy->getVectorKind()); 2328fb90733eSSarah Spall } 2329fb90733eSSarah Spall 2330fb90733eSSarah Spall if (!EltTy->isIntegerType()) { 2331fb90733eSSarah Spall Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type) 2332fb90733eSSarah Spall << 1 << /* integer ty */ 6 << ArgTy; 2333fb90733eSSarah Spall return true; 2334fb90733eSSarah Spall } 2335fb90733eSSarah Spall 2336fb90733eSSarah Spall TheCall->setType(ResTy); 2337fb90733eSSarah Spall break; 2338fb90733eSSarah Spall } 23390f349b7aSSarah Spall case Builtin::BI__builtin_hlsl_select: { 23400f349b7aSSarah Spall if (SemaRef.checkArgCount(TheCall, 3)) 23410f349b7aSSarah Spall return true; 23420f349b7aSSarah Spall if (CheckScalarOrVector(&SemaRef, TheCall, getASTContext().BoolTy, 0)) 23430f349b7aSSarah Spall return true; 23440f349b7aSSarah Spall QualType ArgTy = TheCall->getArg(0)->getType(); 23450f349b7aSSarah Spall if (ArgTy->isBooleanType() && CheckBoolSelect(&SemaRef, TheCall)) 23460f349b7aSSarah Spall return true; 23470f349b7aSSarah Spall auto *VTy = ArgTy->getAs<VectorType>(); 23480f349b7aSSarah Spall if (VTy && VTy->getElementType()->isBooleanType() && 23490f349b7aSSarah Spall CheckVectorSelect(&SemaRef, TheCall)) 23500f349b7aSSarah Spall return true; 23510f349b7aSSarah Spall break; 23520f349b7aSSarah Spall } 23536a38e19cSS. Bharadwaj Yadavalli case Builtin::BI__builtin_hlsl_elementwise_saturate: 2354f1c54d72SVlad Serebrennikov case Builtin::BI__builtin_hlsl_elementwise_rcp: { 2355f1c54d72SVlad Serebrennikov if (CheckAllArgsHaveFloatRepresentation(&SemaRef, TheCall)) 2356f1c54d72SVlad Serebrennikov return true; 2357f1c54d72SVlad Serebrennikov if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall)) 2358f1c54d72SVlad Serebrennikov return true; 2359f1c54d72SVlad Serebrennikov break; 2360f1c54d72SVlad Serebrennikov } 236126475050SFinn Plummer case Builtin::BI__builtin_hlsl_elementwise_degrees: 23629df94e27SAdam Yang case Builtin::BI__builtin_hlsl_elementwise_radians: 2363f1c54d72SVlad Serebrennikov case Builtin::BI__builtin_hlsl_elementwise_rsqrt: 2364f1c54d72SVlad Serebrennikov case Builtin::BI__builtin_hlsl_elementwise_frac: { 2365f1c54d72SVlad Serebrennikov if (CheckFloatOrHalfRepresentations(&SemaRef, TheCall)) 2366f1c54d72SVlad Serebrennikov return true; 2367f1c54d72SVlad Serebrennikov if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall)) 2368f1c54d72SVlad Serebrennikov return true; 2369f1c54d72SVlad Serebrennikov break; 2370f1c54d72SVlad Serebrennikov } 2371f1c54d72SVlad Serebrennikov case Builtin::BI__builtin_hlsl_elementwise_isinf: { 2372f1c54d72SVlad Serebrennikov if (CheckFloatOrHalfRepresentations(&SemaRef, TheCall)) 2373f1c54d72SVlad Serebrennikov return true; 2374f1c54d72SVlad Serebrennikov if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall)) 2375f1c54d72SVlad Serebrennikov return true; 2376f1c54d72SVlad Serebrennikov SetElementTypeAsReturnType(&SemaRef, TheCall, getASTContext().BoolTy); 2377f1c54d72SVlad Serebrennikov break; 2378f1c54d72SVlad Serebrennikov } 2379f1c54d72SVlad Serebrennikov case Builtin::BI__builtin_hlsl_lerp: { 2380f1c54d72SVlad Serebrennikov if (SemaRef.checkArgCount(TheCall, 3)) 2381f1c54d72SVlad Serebrennikov return true; 2382f1c54d72SVlad Serebrennikov if (CheckVectorElementCallArgs(&SemaRef, TheCall)) 2383f1c54d72SVlad Serebrennikov return true; 2384f1c54d72SVlad Serebrennikov if (SemaRef.BuiltinElementwiseTernaryMath(TheCall)) 2385f1c54d72SVlad Serebrennikov return true; 2386f1c54d72SVlad Serebrennikov if (CheckFloatOrHalfRepresentations(&SemaRef, TheCall)) 2387f1c54d72SVlad Serebrennikov return true; 2388f1c54d72SVlad Serebrennikov break; 2389f1c54d72SVlad Serebrennikov } 2390f1c54d72SVlad Serebrennikov case Builtin::BI__builtin_hlsl_mad: { 2391f1c54d72SVlad Serebrennikov if (SemaRef.checkArgCount(TheCall, 3)) 2392f1c54d72SVlad Serebrennikov return true; 2393f1c54d72SVlad Serebrennikov if (CheckVectorElementCallArgs(&SemaRef, TheCall)) 2394f1c54d72SVlad Serebrennikov return true; 2395f1c54d72SVlad Serebrennikov if (SemaRef.BuiltinElementwiseTernaryMath( 2396f1c54d72SVlad Serebrennikov TheCall, /*CheckForFloatArgs*/ 2397f1c54d72SVlad Serebrennikov TheCall->getArg(0)->getType()->hasFloatingRepresentation())) 2398f1c54d72SVlad Serebrennikov return true; 2399f1c54d72SVlad Serebrennikov break; 2400f1c54d72SVlad Serebrennikov } 24011b2d11deSJoshua Batista case Builtin::BI__builtin_hlsl_normalize: { 24021b2d11deSJoshua Batista if (CheckFloatOrHalfRepresentations(&SemaRef, TheCall)) 24031b2d11deSJoshua Batista return true; 24041b2d11deSJoshua Batista if (SemaRef.checkArgCount(TheCall, 1)) 24051b2d11deSJoshua Batista return true; 24061b2d11deSJoshua Batista 24071b2d11deSJoshua Batista ExprResult A = TheCall->getArg(0); 24081b2d11deSJoshua Batista QualType ArgTyA = A.get()->getType(); 24091b2d11deSJoshua Batista // return type is the same as the input type 24101b2d11deSJoshua Batista TheCall->setType(ArgTyA); 24111b2d11deSJoshua Batista break; 24121b2d11deSJoshua Batista } 2413dce50397STim Gymnich case Builtin::BI__builtin_hlsl_elementwise_sign: { 241499608f11STim Gymnich if (CheckFloatingOrIntRepresentation(&SemaRef, TheCall)) 2415dce50397STim Gymnich return true; 2416dce50397STim Gymnich if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall)) 2417dce50397STim Gymnich return true; 2418dce50397STim Gymnich SetElementTypeAsReturnType(&SemaRef, TheCall, getASTContext().IntTy); 2419dce50397STim Gymnich break; 2420dce50397STim Gymnich } 24212d47a0baSJoshua Batista case Builtin::BI__builtin_hlsl_step: { 24222d47a0baSJoshua Batista if (SemaRef.checkArgCount(TheCall, 2)) 24232d47a0baSJoshua Batista return true; 24242d47a0baSJoshua Batista if (CheckFloatOrHalfRepresentations(&SemaRef, TheCall)) 24252d47a0baSJoshua Batista return true; 24262d47a0baSJoshua Batista 24272d47a0baSJoshua Batista ExprResult A = TheCall->getArg(0); 24282d47a0baSJoshua Batista QualType ArgTyA = A.get()->getType(); 24292d47a0baSJoshua Batista // return type is the same as the input type 24302d47a0baSJoshua Batista TheCall->setType(ArgTyA); 24312d47a0baSJoshua Batista break; 24322d47a0baSJoshua Batista } 2433*aab25f20SAdam Yang case Builtin::BI__builtin_hlsl_wave_active_max: 24344446a984SAdam Yang case Builtin::BI__builtin_hlsl_wave_active_sum: { 24354446a984SAdam Yang if (SemaRef.checkArgCount(TheCall, 1)) 24364446a984SAdam Yang return true; 24374446a984SAdam Yang 24384446a984SAdam Yang // Ensure input expr type is a scalar/vector and the same as the return type 24394446a984SAdam Yang if (CheckAnyScalarOrVector(&SemaRef, TheCall, 0)) 24404446a984SAdam Yang return true; 24414446a984SAdam Yang if (CheckWaveActive(&SemaRef, TheCall)) 24424446a984SAdam Yang return true; 24434446a984SAdam Yang ExprResult Expr = TheCall->getArg(0); 24444446a984SAdam Yang QualType ArgTyExpr = Expr.get()->getType(); 24454446a984SAdam Yang TheCall->setType(ArgTyExpr); 24464446a984SAdam Yang break; 24474446a984SAdam Yang } 2448f1c54d72SVlad Serebrennikov // Note these are llvm builtins that we want to catch invalid intrinsic 2449f1c54d72SVlad Serebrennikov // generation. Normal handling of these builitns will occur elsewhere. 2450f1c54d72SVlad Serebrennikov case Builtin::BI__builtin_elementwise_bitreverse: { 2451f1c54d72SVlad Serebrennikov if (CheckUnsignedIntRepresentation(&SemaRef, TheCall)) 2452f1c54d72SVlad Serebrennikov return true; 2453f1c54d72SVlad Serebrennikov break; 2454f1c54d72SVlad Serebrennikov } 24556d13cc94SFinn Plummer case Builtin::BI__builtin_hlsl_wave_read_lane_at: { 24566d13cc94SFinn Plummer if (SemaRef.checkArgCount(TheCall, 2)) 24576d13cc94SFinn Plummer return true; 24586d13cc94SFinn Plummer 24596d13cc94SFinn Plummer // Ensure index parameter type can be interpreted as a uint 24606d13cc94SFinn Plummer ExprResult Index = TheCall->getArg(1); 24616d13cc94SFinn Plummer QualType ArgTyIndex = Index.get()->getType(); 24626d13cc94SFinn Plummer if (!ArgTyIndex->isIntegerType()) { 24636d13cc94SFinn Plummer SemaRef.Diag(TheCall->getArg(1)->getBeginLoc(), 24646d13cc94SFinn Plummer diag::err_typecheck_convert_incompatible) 24656d13cc94SFinn Plummer << ArgTyIndex << SemaRef.Context.UnsignedIntTy << 1 << 0 << 0; 24666d13cc94SFinn Plummer return true; 24676d13cc94SFinn Plummer } 24686d13cc94SFinn Plummer 24696d13cc94SFinn Plummer // Ensure input expr type is a scalar/vector and the same as the return type 24706d13cc94SFinn Plummer if (CheckAnyScalarOrVector(&SemaRef, TheCall, 0)) 24716d13cc94SFinn Plummer return true; 24726d13cc94SFinn Plummer 24736d13cc94SFinn Plummer ExprResult Expr = TheCall->getArg(0); 24746d13cc94SFinn Plummer QualType ArgTyExpr = Expr.get()->getType(); 24756d13cc94SFinn Plummer TheCall->setType(ArgTyExpr); 24766d13cc94SFinn Plummer break; 24776d13cc94SFinn Plummer } 2478d36cef0bSFinn Plummer case Builtin::BI__builtin_hlsl_wave_get_lane_index: { 2479d36cef0bSFinn Plummer if (SemaRef.checkArgCount(TheCall, 0)) 2480d36cef0bSFinn Plummer return true; 2481d36cef0bSFinn Plummer break; 2482d36cef0bSFinn Plummer } 2483481bce01Sjoaosaffran case Builtin::BI__builtin_hlsl_elementwise_splitdouble: { 2484481bce01Sjoaosaffran if (SemaRef.checkArgCount(TheCall, 3)) 2485481bce01Sjoaosaffran return true; 2486481bce01Sjoaosaffran 2487481bce01Sjoaosaffran if (CheckScalarOrVector(&SemaRef, TheCall, SemaRef.Context.DoubleTy, 0) || 2488481bce01Sjoaosaffran CheckScalarOrVector(&SemaRef, TheCall, SemaRef.Context.UnsignedIntTy, 2489481bce01Sjoaosaffran 1) || 2490481bce01Sjoaosaffran CheckScalarOrVector(&SemaRef, TheCall, SemaRef.Context.UnsignedIntTy, 2491481bce01Sjoaosaffran 2)) 2492481bce01Sjoaosaffran return true; 2493481bce01Sjoaosaffran 2494481bce01Sjoaosaffran if (CheckModifiableLValue(&SemaRef, TheCall, 1) || 2495481bce01Sjoaosaffran CheckModifiableLValue(&SemaRef, TheCall, 2)) 2496481bce01Sjoaosaffran return true; 2497481bce01Sjoaosaffran break; 2498481bce01Sjoaosaffran } 2499bc6c0681Sjoaosaffran case Builtin::BI__builtin_hlsl_elementwise_clip: { 2500bc6c0681Sjoaosaffran if (SemaRef.checkArgCount(TheCall, 1)) 2501bc6c0681Sjoaosaffran return true; 2502bc6c0681Sjoaosaffran 2503bc6c0681Sjoaosaffran if (CheckScalarOrVector(&SemaRef, TheCall, SemaRef.Context.FloatTy, 0)) 2504bc6c0681Sjoaosaffran return true; 2505bc6c0681Sjoaosaffran break; 2506bc6c0681Sjoaosaffran } 2507f1c54d72SVlad Serebrennikov case Builtin::BI__builtin_elementwise_acos: 2508f1c54d72SVlad Serebrennikov case Builtin::BI__builtin_elementwise_asin: 2509f1c54d72SVlad Serebrennikov case Builtin::BI__builtin_elementwise_atan: 2510b70d3278STex Riddell case Builtin::BI__builtin_elementwise_atan2: 2511f1c54d72SVlad Serebrennikov case Builtin::BI__builtin_elementwise_ceil: 2512f1c54d72SVlad Serebrennikov case Builtin::BI__builtin_elementwise_cos: 2513f1c54d72SVlad Serebrennikov case Builtin::BI__builtin_elementwise_cosh: 2514f1c54d72SVlad Serebrennikov case Builtin::BI__builtin_elementwise_exp: 2515f1c54d72SVlad Serebrennikov case Builtin::BI__builtin_elementwise_exp2: 2516f1c54d72SVlad Serebrennikov case Builtin::BI__builtin_elementwise_floor: 25175d08f325SZhengxing li case Builtin::BI__builtin_elementwise_fmod: 2518f1c54d72SVlad Serebrennikov case Builtin::BI__builtin_elementwise_log: 2519f1c54d72SVlad Serebrennikov case Builtin::BI__builtin_elementwise_log2: 2520f1c54d72SVlad Serebrennikov case Builtin::BI__builtin_elementwise_log10: 2521f1c54d72SVlad Serebrennikov case Builtin::BI__builtin_elementwise_pow: 2522f1c54d72SVlad Serebrennikov case Builtin::BI__builtin_elementwise_roundeven: 2523f1c54d72SVlad Serebrennikov case Builtin::BI__builtin_elementwise_sin: 2524f1c54d72SVlad Serebrennikov case Builtin::BI__builtin_elementwise_sinh: 2525f1c54d72SVlad Serebrennikov case Builtin::BI__builtin_elementwise_sqrt: 2526f1c54d72SVlad Serebrennikov case Builtin::BI__builtin_elementwise_tan: 2527f1c54d72SVlad Serebrennikov case Builtin::BI__builtin_elementwise_tanh: 2528f1c54d72SVlad Serebrennikov case Builtin::BI__builtin_elementwise_trunc: { 2529f1c54d72SVlad Serebrennikov if (CheckFloatOrHalfRepresentations(&SemaRef, TheCall)) 2530f1c54d72SVlad Serebrennikov return true; 2531f1c54d72SVlad Serebrennikov break; 2532f1c54d72SVlad Serebrennikov } 2533cac97833SHelena Kotas case Builtin::BI__builtin_hlsl_buffer_update_counter: { 2534cac97833SHelena Kotas auto checkResTy = [](const HLSLAttributedResourceType *ResTy) -> bool { 2535cac97833SHelena Kotas return !(ResTy->getAttrs().ResourceClass == ResourceClass::UAV && 2536cac97833SHelena Kotas ResTy->getAttrs().RawBuffer && ResTy->hasContainedType()); 2537cac97833SHelena Kotas }; 2538cac97833SHelena Kotas if (SemaRef.checkArgCount(TheCall, 2) || 2539cac97833SHelena Kotas CheckResourceHandle(&SemaRef, TheCall, 0, checkResTy) || 2540cac97833SHelena Kotas CheckArgTypeMatches(&SemaRef, TheCall->getArg(1), 2541cac97833SHelena Kotas SemaRef.getASTContext().IntTy)) 2542cac97833SHelena Kotas return true; 2543cac97833SHelena Kotas Expr *OffsetExpr = TheCall->getArg(1); 2544cac97833SHelena Kotas std::optional<llvm::APSInt> Offset = 2545cac97833SHelena Kotas OffsetExpr->getIntegerConstantExpr(SemaRef.getASTContext()); 2546cac97833SHelena Kotas if (!Offset.has_value() || std::abs(Offset->getExtValue()) != 1) { 2547cac97833SHelena Kotas SemaRef.Diag(TheCall->getArg(1)->getBeginLoc(), 2548cac97833SHelena Kotas diag::err_hlsl_expect_arg_const_int_one_or_neg_one) 2549cac97833SHelena Kotas << 1; 2550cac97833SHelena Kotas return true; 2551cac97833SHelena Kotas } 2552cac97833SHelena Kotas break; 2553cac97833SHelena Kotas } 2554f1c54d72SVlad Serebrennikov } 2555f1c54d72SVlad Serebrennikov return false; 2556f1c54d72SVlad Serebrennikov } 25574bab0387SChris B 25584bab0387SChris B static void BuildFlattenedTypeList(QualType BaseTy, 25594bab0387SChris B llvm::SmallVectorImpl<QualType> &List) { 25604bab0387SChris B llvm::SmallVector<QualType, 16> WorkList; 25614bab0387SChris B WorkList.push_back(BaseTy); 25624bab0387SChris B while (!WorkList.empty()) { 25634bab0387SChris B QualType T = WorkList.pop_back_val(); 25644bab0387SChris B T = T.getCanonicalType().getUnqualifiedType(); 25654bab0387SChris B assert(!isa<MatrixType>(T) && "Matrix types not yet supported in HLSL"); 25664bab0387SChris B if (const auto *AT = dyn_cast<ConstantArrayType>(T)) { 25674bab0387SChris B llvm::SmallVector<QualType, 16> ElementFields; 25684bab0387SChris B // Generally I've avoided recursion in this algorithm, but arrays of 25694bab0387SChris B // structs could be time-consuming to flatten and churn through on the 25704bab0387SChris B // work list. Hopefully nesting arrays of structs containing arrays 25714bab0387SChris B // of structs too many levels deep is unlikely. 25724bab0387SChris B BuildFlattenedTypeList(AT->getElementType(), ElementFields); 25734bab0387SChris B // Repeat the element's field list n times. 25744bab0387SChris B for (uint64_t Ct = 0; Ct < AT->getZExtSize(); ++Ct) 25754bab0387SChris B List.insert(List.end(), ElementFields.begin(), ElementFields.end()); 25764bab0387SChris B continue; 25774bab0387SChris B } 25784bab0387SChris B // Vectors can only have element types that are builtin types, so this can 25794bab0387SChris B // add directly to the list instead of to the WorkList. 25804bab0387SChris B if (const auto *VT = dyn_cast<VectorType>(T)) { 25814bab0387SChris B List.insert(List.end(), VT->getNumElements(), VT->getElementType()); 25824bab0387SChris B continue; 25834bab0387SChris B } 25844bab0387SChris B if (const auto *RT = dyn_cast<RecordType>(T)) { 25854bab0387SChris B const RecordDecl *RD = RT->getDecl(); 25864bab0387SChris B if (RD->isUnion()) { 25874bab0387SChris B List.push_back(T); 25884bab0387SChris B continue; 25894bab0387SChris B } 25904bab0387SChris B const CXXRecordDecl *CXXD = dyn_cast<CXXRecordDecl>(RD); 25914bab0387SChris B 25924bab0387SChris B llvm::SmallVector<QualType, 16> FieldTypes; 25934bab0387SChris B if (CXXD && CXXD->isStandardLayout()) 25944bab0387SChris B RD = CXXD->getStandardLayoutBaseWithFields(); 25954bab0387SChris B 25964bab0387SChris B for (const auto *FD : RD->fields()) 25974bab0387SChris B FieldTypes.push_back(FD->getType()); 25984bab0387SChris B // Reverse the newly added sub-range. 25994bab0387SChris B std::reverse(FieldTypes.begin(), FieldTypes.end()); 26004bab0387SChris B WorkList.insert(WorkList.end(), FieldTypes.begin(), FieldTypes.end()); 26014bab0387SChris B 26024bab0387SChris B // If this wasn't a standard layout type we may also have some base 26034bab0387SChris B // classes to deal with. 26044bab0387SChris B if (CXXD && !CXXD->isStandardLayout()) { 26054bab0387SChris B FieldTypes.clear(); 26064bab0387SChris B for (const auto &Base : CXXD->bases()) 26074bab0387SChris B FieldTypes.push_back(Base.getType()); 26084bab0387SChris B std::reverse(FieldTypes.begin(), FieldTypes.end()); 26094bab0387SChris B WorkList.insert(WorkList.end(), FieldTypes.begin(), FieldTypes.end()); 26104bab0387SChris B } 26114bab0387SChris B continue; 26124bab0387SChris B } 26134bab0387SChris B List.push_back(T); 26144bab0387SChris B } 26154bab0387SChris B } 26164bab0387SChris B 2617b509eb77SJoshua Batista bool SemaHLSL::IsTypedResourceElementCompatible(clang::QualType QT) { 261847889cddSJoshua Batista // null and array types are not allowed. 261947889cddSJoshua Batista if (QT.isNull() || QT->isArrayType()) 2620b509eb77SJoshua Batista return false; 2621b509eb77SJoshua Batista 262247889cddSJoshua Batista // UDT types are not allowed 262347889cddSJoshua Batista if (QT->isRecordType()) 2624b509eb77SJoshua Batista return false; 2625b509eb77SJoshua Batista 262647889cddSJoshua Batista if (QT->isBooleanType() || QT->isEnumeralType()) 2627b509eb77SJoshua Batista return false; 2628b509eb77SJoshua Batista 262947889cddSJoshua Batista // the only other valid builtin types are scalars or vectors 263047889cddSJoshua Batista if (QT->isArithmeticType()) { 263147889cddSJoshua Batista if (SemaRef.Context.getTypeSize(QT) / 8 > 16) 2632b509eb77SJoshua Batista return false; 2633b509eb77SJoshua Batista return true; 2634b509eb77SJoshua Batista } 2635b509eb77SJoshua Batista 263647889cddSJoshua Batista if (const VectorType *VT = QT->getAs<VectorType>()) { 263747889cddSJoshua Batista int ArraySize = VT->getNumElements(); 263847889cddSJoshua Batista 263947889cddSJoshua Batista if (ArraySize > 4) 264047889cddSJoshua Batista return false; 264147889cddSJoshua Batista 264247889cddSJoshua Batista QualType ElTy = VT->getElementType(); 264347889cddSJoshua Batista if (ElTy->isBooleanType()) 264447889cddSJoshua Batista return false; 264547889cddSJoshua Batista 264647889cddSJoshua Batista if (SemaRef.Context.getTypeSize(QT) / 8 > 16) 264747889cddSJoshua Batista return false; 264847889cddSJoshua Batista return true; 264947889cddSJoshua Batista } 265047889cddSJoshua Batista 265147889cddSJoshua Batista return false; 265247889cddSJoshua Batista } 265347889cddSJoshua Batista 26544bab0387SChris B bool SemaHLSL::IsScalarizedLayoutCompatible(QualType T1, QualType T2) const { 26554bab0387SChris B if (T1.isNull() || T2.isNull()) 26564bab0387SChris B return false; 26574bab0387SChris B 26584bab0387SChris B T1 = T1.getCanonicalType().getUnqualifiedType(); 26594bab0387SChris B T2 = T2.getCanonicalType().getUnqualifiedType(); 26604bab0387SChris B 26614bab0387SChris B // If both types are the same canonical type, they're obviously compatible. 26624bab0387SChris B if (SemaRef.getASTContext().hasSameType(T1, T2)) 26634bab0387SChris B return true; 26644bab0387SChris B 26654bab0387SChris B llvm::SmallVector<QualType, 16> T1Types; 26664bab0387SChris B BuildFlattenedTypeList(T1, T1Types); 26674bab0387SChris B llvm::SmallVector<QualType, 16> T2Types; 26684bab0387SChris B BuildFlattenedTypeList(T2, T2Types); 26694bab0387SChris B 26704bab0387SChris B // Check the flattened type list 26714bab0387SChris B return llvm::equal(T1Types, T2Types, 26724bab0387SChris B [this](QualType LHS, QualType RHS) -> bool { 26734bab0387SChris B return SemaRef.IsLayoutCompatible(LHS, RHS); 26744bab0387SChris B }); 26754bab0387SChris B } 267689fb8490SChris B 267789fb8490SChris B bool SemaHLSL::CheckCompatibleParameterABI(FunctionDecl *New, 267889fb8490SChris B FunctionDecl *Old) { 267989fb8490SChris B if (New->getNumParams() != Old->getNumParams()) 268089fb8490SChris B return true; 268189fb8490SChris B 268289fb8490SChris B bool HadError = false; 268389fb8490SChris B 268489fb8490SChris B for (unsigned i = 0, e = New->getNumParams(); i != e; ++i) { 268589fb8490SChris B ParmVarDecl *NewParam = New->getParamDecl(i); 268689fb8490SChris B ParmVarDecl *OldParam = Old->getParamDecl(i); 268789fb8490SChris B 268889fb8490SChris B // HLSL parameter declarations for inout and out must match between 268989fb8490SChris B // declarations. In HLSL inout and out are ambiguous at the call site, 269089fb8490SChris B // but have different calling behavior, so you cannot overload a 269189fb8490SChris B // method based on a difference between inout and out annotations. 269289fb8490SChris B const auto *NDAttr = NewParam->getAttr<HLSLParamModifierAttr>(); 269389fb8490SChris B unsigned NSpellingIdx = (NDAttr ? NDAttr->getSpellingListIndex() : 0); 269489fb8490SChris B const auto *ODAttr = OldParam->getAttr<HLSLParamModifierAttr>(); 269589fb8490SChris B unsigned OSpellingIdx = (ODAttr ? ODAttr->getSpellingListIndex() : 0); 269689fb8490SChris B 269789fb8490SChris B if (NSpellingIdx != OSpellingIdx) { 269889fb8490SChris B SemaRef.Diag(NewParam->getLocation(), 269989fb8490SChris B diag::err_hlsl_param_qualifier_mismatch) 270089fb8490SChris B << NDAttr << NewParam; 270189fb8490SChris B SemaRef.Diag(OldParam->getLocation(), diag::note_previous_declaration_as) 270289fb8490SChris B << ODAttr; 270389fb8490SChris B HadError = true; 270489fb8490SChris B } 270589fb8490SChris B } 270689fb8490SChris B return HadError; 270789fb8490SChris B } 270889fb8490SChris B 270989fb8490SChris B ExprResult SemaHLSL::ActOnOutParamExpr(ParmVarDecl *Param, Expr *Arg) { 271089fb8490SChris B assert(Param->hasAttr<HLSLParamModifierAttr>() && 271189fb8490SChris B "We should not get here without a parameter modifier expression"); 271289fb8490SChris B const auto *Attr = Param->getAttr<HLSLParamModifierAttr>(); 271389fb8490SChris B if (Attr->getABI() == ParameterABI::Ordinary) 271489fb8490SChris B return ExprResult(Arg); 271589fb8490SChris B 271689fb8490SChris B bool IsInOut = Attr->getABI() == ParameterABI::HLSLInOut; 271789fb8490SChris B if (!Arg->isLValue()) { 271889fb8490SChris B SemaRef.Diag(Arg->getBeginLoc(), diag::error_hlsl_inout_lvalue) 271989fb8490SChris B << Arg << (IsInOut ? 1 : 0); 272089fb8490SChris B return ExprError(); 272189fb8490SChris B } 272289fb8490SChris B 272389fb8490SChris B ASTContext &Ctx = SemaRef.getASTContext(); 272489fb8490SChris B 272589fb8490SChris B QualType Ty = Param->getType().getNonLValueExprType(Ctx); 272689fb8490SChris B 272789fb8490SChris B // HLSL allows implicit conversions from scalars to vectors, but not the 272889fb8490SChris B // inverse, so we need to disallow `inout` with scalar->vector or 272989fb8490SChris B // scalar->matrix conversions. 273089fb8490SChris B if (Arg->getType()->isScalarType() != Ty->isScalarType()) { 273189fb8490SChris B SemaRef.Diag(Arg->getBeginLoc(), diag::error_hlsl_inout_scalar_extension) 273289fb8490SChris B << Arg << (IsInOut ? 1 : 0); 273389fb8490SChris B return ExprError(); 273489fb8490SChris B } 273589fb8490SChris B 273689fb8490SChris B auto *ArgOpV = new (Ctx) OpaqueValueExpr(Param->getBeginLoc(), Arg->getType(), 273789fb8490SChris B VK_LValue, OK_Ordinary, Arg); 273889fb8490SChris B 273989fb8490SChris B // Parameters are initialized via copy initialization. This allows for 274089fb8490SChris B // overload resolution of argument constructors. 274189fb8490SChris B InitializedEntity Entity = 274289fb8490SChris B InitializedEntity::InitializeParameter(Ctx, Ty, false); 274389fb8490SChris B ExprResult Res = 274489fb8490SChris B SemaRef.PerformCopyInitialization(Entity, Param->getBeginLoc(), ArgOpV); 274589fb8490SChris B if (Res.isInvalid()) 274689fb8490SChris B return ExprError(); 274789fb8490SChris B Expr *Base = Res.get(); 274889fb8490SChris B // After the cast, drop the reference type when creating the exprs. 274989fb8490SChris B Ty = Ty.getNonLValueExprType(Ctx); 275089fb8490SChris B auto *OpV = new (Ctx) 275189fb8490SChris B OpaqueValueExpr(Param->getBeginLoc(), Ty, VK_LValue, OK_Ordinary, Base); 275289fb8490SChris B 275389fb8490SChris B // Writebacks are performed with `=` binary operator, which allows for 275489fb8490SChris B // overload resolution on writeback result expressions. 275589fb8490SChris B Res = SemaRef.ActOnBinOp(SemaRef.getCurScope(), Param->getBeginLoc(), 275689fb8490SChris B tok::equal, ArgOpV, OpV); 275789fb8490SChris B 275889fb8490SChris B if (Res.isInvalid()) 275989fb8490SChris B return ExprError(); 276089fb8490SChris B Expr *Writeback = Res.get(); 276189fb8490SChris B auto *OutExpr = 276289fb8490SChris B HLSLOutArgExpr::Create(Ctx, Ty, ArgOpV, OpV, Writeback, IsInOut); 276389fb8490SChris B 276489fb8490SChris B return ExprResult(OutExpr); 276589fb8490SChris B } 276689fb8490SChris B 276789fb8490SChris B QualType SemaHLSL::getInoutParameterType(QualType Ty) { 276889fb8490SChris B // If HLSL gains support for references, all the cites that use this will need 276989fb8490SChris B // to be updated with semantic checking to produce errors for 277089fb8490SChris B // pointers/references. 277189fb8490SChris B assert(!Ty->isReferenceType() && 277289fb8490SChris B "Pointer and reference types cannot be inout or out parameters"); 277389fb8490SChris B Ty = SemaRef.getASTContext().getLValueReferenceType(Ty); 277489fb8490SChris B Ty.addRestrict(); 277589fb8490SChris B return Ty; 277689fb8490SChris B } 27774512bbe7SHelena Kotas 27784512bbe7SHelena Kotas void SemaHLSL::ActOnVariableDeclarator(VarDecl *VD) { 27794512bbe7SHelena Kotas if (VD->hasGlobalStorage()) { 27804512bbe7SHelena Kotas // make sure the declaration has a complete type 27814512bbe7SHelena Kotas if (SemaRef.RequireCompleteType( 27824512bbe7SHelena Kotas VD->getLocation(), 27834512bbe7SHelena Kotas SemaRef.getASTContext().getBaseElementType(VD->getType()), 27844512bbe7SHelena Kotas diag::err_typecheck_decl_incomplete_type)) { 27854512bbe7SHelena Kotas VD->setInvalidDecl(); 27864512bbe7SHelena Kotas return; 27874512bbe7SHelena Kotas } 27884512bbe7SHelena Kotas 27894512bbe7SHelena Kotas // find all resources on decl 27909b984554SHelena Kotas if (VD->getType()->isHLSLIntangibleType()) 27914512bbe7SHelena Kotas collectResourcesOnVarDecl(VD); 27924512bbe7SHelena Kotas 27934512bbe7SHelena Kotas // process explicit bindings 27944512bbe7SHelena Kotas processExplicitBindingsOnDecl(VD); 27954512bbe7SHelena Kotas } 27964512bbe7SHelena Kotas } 27974512bbe7SHelena Kotas 27984512bbe7SHelena Kotas // Walks though the global variable declaration, collects all resource binding 27994512bbe7SHelena Kotas // requirements and adds them to Bindings 28004512bbe7SHelena Kotas void SemaHLSL::collectResourcesOnVarDecl(VarDecl *VD) { 28019b984554SHelena Kotas assert(VD->hasGlobalStorage() && VD->getType()->isHLSLIntangibleType() && 28024512bbe7SHelena Kotas "expected global variable that contains HLSL resource"); 28034512bbe7SHelena Kotas 28044512bbe7SHelena Kotas // Cbuffers and Tbuffers are HLSLBufferDecl types 28054512bbe7SHelena Kotas if (const HLSLBufferDecl *CBufferOrTBuffer = dyn_cast<HLSLBufferDecl>(VD)) { 28064512bbe7SHelena Kotas Bindings.addDeclBindingInfo(VD, CBufferOrTBuffer->isCBuffer() 28074512bbe7SHelena Kotas ? ResourceClass::CBuffer 28084512bbe7SHelena Kotas : ResourceClass::SRV); 28094512bbe7SHelena Kotas return; 28104512bbe7SHelena Kotas } 28114512bbe7SHelena Kotas 28124512bbe7SHelena Kotas // Unwrap arrays 28134512bbe7SHelena Kotas // FIXME: Calculate array size while unwrapping 28144512bbe7SHelena Kotas const Type *Ty = VD->getType()->getUnqualifiedDesugaredType(); 28154512bbe7SHelena Kotas while (Ty->isConstantArrayType()) { 28164512bbe7SHelena Kotas const ConstantArrayType *CAT = cast<ConstantArrayType>(Ty); 28174512bbe7SHelena Kotas Ty = CAT->getElementType()->getUnqualifiedDesugaredType(); 28184512bbe7SHelena Kotas } 28194512bbe7SHelena Kotas 28204512bbe7SHelena Kotas // Resource (or array of resources) 28214512bbe7SHelena Kotas if (const HLSLAttributedResourceType *AttrResType = 28227dbfa7b9SHelena Kotas HLSLAttributedResourceType::findHandleTypeOnResource(Ty)) { 28234512bbe7SHelena Kotas Bindings.addDeclBindingInfo(VD, AttrResType->getAttrs().ResourceClass); 28244512bbe7SHelena Kotas return; 28254512bbe7SHelena Kotas } 28264512bbe7SHelena Kotas 28274512bbe7SHelena Kotas // User defined record type 28284512bbe7SHelena Kotas if (const RecordType *RT = dyn_cast<RecordType>(Ty)) 28294512bbe7SHelena Kotas collectResourcesOnUserRecordDecl(VD, RT); 28304512bbe7SHelena Kotas } 28314512bbe7SHelena Kotas 28324512bbe7SHelena Kotas // Walks though the explicit resource binding attributes on the declaration, 28334512bbe7SHelena Kotas // and makes sure there is a resource that matched the binding and updates 28344512bbe7SHelena Kotas // DeclBindingInfoLists 28354512bbe7SHelena Kotas void SemaHLSL::processExplicitBindingsOnDecl(VarDecl *VD) { 28364512bbe7SHelena Kotas assert(VD->hasGlobalStorage() && "expected global variable"); 28374512bbe7SHelena Kotas 28384512bbe7SHelena Kotas for (Attr *A : VD->attrs()) { 28394512bbe7SHelena Kotas HLSLResourceBindingAttr *RBA = dyn_cast<HLSLResourceBindingAttr>(A); 28404512bbe7SHelena Kotas if (!RBA) 28414512bbe7SHelena Kotas continue; 28424512bbe7SHelena Kotas 28434512bbe7SHelena Kotas RegisterType RT = RBA->getRegisterType(); 28444512bbe7SHelena Kotas assert(RT != RegisterType::I && "invalid or obsolete register type should " 28454512bbe7SHelena Kotas "never have an attribute created"); 28464512bbe7SHelena Kotas 28474512bbe7SHelena Kotas if (RT == RegisterType::C) { 28484512bbe7SHelena Kotas if (Bindings.hasBindingInfoForDecl(VD)) 28494512bbe7SHelena Kotas SemaRef.Diag(VD->getLocation(), 28504512bbe7SHelena Kotas diag::warn_hlsl_user_defined_type_missing_member) 28514512bbe7SHelena Kotas << static_cast<int>(RT); 28524512bbe7SHelena Kotas continue; 28534512bbe7SHelena Kotas } 28544512bbe7SHelena Kotas 28554512bbe7SHelena Kotas // Find DeclBindingInfo for this binding and update it, or report error 28564512bbe7SHelena Kotas // if it does not exist (user type does to contain resources with the 28574512bbe7SHelena Kotas // expected resource class). 28584512bbe7SHelena Kotas ResourceClass RC = getResourceClass(RT); 28594512bbe7SHelena Kotas if (DeclBindingInfo *BI = Bindings.getDeclBindingInfo(VD, RC)) { 28604512bbe7SHelena Kotas // update binding info 28614512bbe7SHelena Kotas BI->setBindingAttribute(RBA, BindingType::Explicit); 28624512bbe7SHelena Kotas } else { 28634512bbe7SHelena Kotas SemaRef.Diag(VD->getLocation(), 28644512bbe7SHelena Kotas diag::warn_hlsl_user_defined_type_missing_member) 28654512bbe7SHelena Kotas << static_cast<int>(RT); 28664512bbe7SHelena Kotas } 28674512bbe7SHelena Kotas } 28684512bbe7SHelena Kotas } 2869