xref: /llvm-project/clang/lib/Sema/SemaHLSL.cpp (revision aab25f20f6c06bab7aac6fb83d54705ec4cdfadd)
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