forked from OSchip/llvm-project
[HLSL] Support cbuffer/tbuffer for hlsl.
This is first part for support cbuffer/tbuffer. The format for cbuffer/tbuffer is BufferType [Name] [: register(b#)] { VariableDeclaration [: packoffset(c#.xyzw)]; ... }; More details at https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-constants New keyword 'cbuffer' and 'tbuffer' are added. New AST node HLSLBufferDecl is added. Build AST for simple cbuffer/tbuffer without attribute support. The special thing is variables declared inside cbuffer is exposed into global scope. So isTransparentContext should return true for HLSLBuffer. Reviewed By: aaron.ballman Differential Revision: https://reviews.llvm.org/D129883
This commit is contained in:
parent
1f4d3c681c
commit
782ac2182c
|
@ -4671,6 +4671,51 @@ public:
|
|||
static bool classofKind(Kind K) { return K == Empty; }
|
||||
};
|
||||
|
||||
/// HLSLBufferDecl - Represent a cbuffer or tbuffer declaration.
|
||||
class HLSLBufferDecl final : public NamedDecl, public DeclContext {
|
||||
/// LBraceLoc - The ending location of the source range.
|
||||
SourceLocation LBraceLoc;
|
||||
/// RBraceLoc - The ending location of the source range.
|
||||
SourceLocation RBraceLoc;
|
||||
/// KwLoc - The location of the cbuffer or tbuffer keyword.
|
||||
SourceLocation KwLoc;
|
||||
/// IsCBuffer - Whether the buffer is a cbuffer (and not a tbuffer).
|
||||
bool IsCBuffer;
|
||||
|
||||
HLSLBufferDecl(DeclContext *DC, bool CBuffer, SourceLocation KwLoc,
|
||||
IdentifierInfo *ID, SourceLocation IDLoc,
|
||||
SourceLocation LBrace);
|
||||
|
||||
public:
|
||||
static HLSLBufferDecl *Create(ASTContext &C, DeclContext *LexicalParent,
|
||||
bool CBuffer, SourceLocation KwLoc,
|
||||
IdentifierInfo *ID, SourceLocation IDLoc,
|
||||
SourceLocation LBrace);
|
||||
static HLSLBufferDecl *CreateDeserialized(ASTContext &C, unsigned ID);
|
||||
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(getLocStart(), RBraceLoc);
|
||||
}
|
||||
SourceLocation getLocStart() const LLVM_READONLY { return KwLoc; }
|
||||
SourceLocation getLBraceLoc() const { return LBraceLoc; }
|
||||
SourceLocation getRBraceLoc() const { return RBraceLoc; }
|
||||
void setRBraceLoc(SourceLocation L) { RBraceLoc = L; }
|
||||
bool isCBuffer() const { return IsCBuffer; }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classofKind(Kind K) { return K == HLSLBuffer; }
|
||||
static DeclContext *castToDeclContext(const HLSLBufferDecl *D) {
|
||||
return static_cast<DeclContext *>(const_cast<HLSLBufferDecl *>(D));
|
||||
}
|
||||
static HLSLBufferDecl *castFromDeclContext(const DeclContext *DC) {
|
||||
return static_cast<HLSLBufferDecl *>(const_cast<DeclContext *>(DC));
|
||||
}
|
||||
|
||||
friend class ASTDeclReader;
|
||||
friend class ASTDeclWriter;
|
||||
};
|
||||
|
||||
/// Insertion operator for diagnostics. This allows sending NamedDecl's
|
||||
/// into a diagnostic with <<.
|
||||
inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &PD,
|
||||
|
|
|
@ -246,6 +246,7 @@ public:
|
|||
void VisitEnumConstantDecl(const EnumConstantDecl *ECD);
|
||||
void VisitRecordDecl(const RecordDecl *RD);
|
||||
void VisitCXXRecordDecl(const CXXRecordDecl *RD);
|
||||
void VisitHLSLBufferDecl(const HLSLBufferDecl *D);
|
||||
void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D);
|
||||
void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D);
|
||||
void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D);
|
||||
|
|
|
@ -1538,6 +1538,8 @@ DEF_TRAVERSE_DECL(CapturedDecl, {
|
|||
|
||||
DEF_TRAVERSE_DECL(EmptyDecl, {})
|
||||
|
||||
DEF_TRAVERSE_DECL(HLSLBufferDecl, {})
|
||||
|
||||
DEF_TRAVERSE_DECL(LifetimeExtendedTemporaryDecl, {
|
||||
TRY_TO(TraverseStmt(D->getTemporaryExpr()));
|
||||
})
|
||||
|
|
|
@ -381,6 +381,7 @@ public:
|
|||
void VisitConceptDecl(const ConceptDecl *D);
|
||||
void
|
||||
VisitLifetimeExtendedTemporaryDecl(const LifetimeExtendedTemporaryDecl *D);
|
||||
void VisitHLSLBufferDecl(const HLSLBufferDecl *D);
|
||||
};
|
||||
|
||||
} // namespace clang
|
||||
|
|
|
@ -108,4 +108,4 @@ def OMPRequires : DeclNode<Decl>;
|
|||
def Empty : DeclNode<Decl>;
|
||||
def RequiresExprBody : DeclNode<Decl>, DeclContext;
|
||||
def LifetimeExtendedTemporary : DeclNode<Decl>;
|
||||
|
||||
def HLSLBuffer : DeclNode<Named, "HLSLBuffer">, DeclContext;
|
||||
|
|
|
@ -1618,6 +1618,8 @@ def note_max_tokens_total_override : Note<"total token limit set here">;
|
|||
|
||||
def err_expected_semantic_identifier : Error<
|
||||
"expected HLSL Semantic identifier">;
|
||||
def err_invalid_declaration_in_hlsl_buffer : Error<
|
||||
"invalid declaration inside %select{tbuffer|cbuffer}0">;
|
||||
def err_unknown_hlsl_semantic : Error<"unknown HLSL semantic %0">;
|
||||
def ext_hlsl_access_specifiers : ExtWarn<
|
||||
"access specifiers are a clang HLSL extension">,
|
||||
|
|
|
@ -604,6 +604,10 @@ KEYWORD(addrspace_cast , KEYOPENCLCXX)
|
|||
// CUDA/HIP function attributes
|
||||
KEYWORD(__noinline__ , KEYCUDA)
|
||||
|
||||
// HLSL keywords.
|
||||
KEYWORD(cbuffer , KEYHLSL)
|
||||
KEYWORD(tbuffer , KEYHLSL)
|
||||
|
||||
// OpenMP Type Traits
|
||||
UNARY_EXPR_OR_TYPE_TRAIT(__builtin_omp_required_simd_align, OpenMPRequiredSimdAlign, KEYALL)
|
||||
|
||||
|
|
|
@ -2821,6 +2821,7 @@ private:
|
|||
|
||||
void ParseHLSLSemantics(ParsedAttributes &Attrs,
|
||||
SourceLocation *EndLoc = nullptr);
|
||||
Decl *ParseHLSLBuffer(SourceLocation &DeclEnd);
|
||||
|
||||
void MaybeParseMicrosoftAttributes(ParsedAttributes &Attrs) {
|
||||
if ((getLangOpts().MicrosoftExt || getLangOpts().HLSL) &&
|
||||
|
|
|
@ -5962,6 +5962,12 @@ public:
|
|||
SourceLocation BuiltinLoc,
|
||||
SourceLocation RParenLoc);
|
||||
|
||||
//===---------------------------- HLSL Features -------------------------===//
|
||||
Decl *ActOnStartHLSLBuffer(Scope *BufferScope, bool CBuffer,
|
||||
SourceLocation KwLoc, IdentifierInfo *Ident,
|
||||
SourceLocation IdentLoc, SourceLocation LBrace);
|
||||
void ActOnFinishHLSLBuffer(Decl *Dcl, SourceLocation RBrace);
|
||||
|
||||
//===---------------------------- C++ Features --------------------------===//
|
||||
|
||||
// Act on C++ namespaces
|
||||
|
|
|
@ -1511,7 +1511,10 @@ enum DeclCode {
|
|||
/// A UnnamedGlobalConstantDecl record.
|
||||
DECL_UNNAMED_GLOBAL_CONSTANT,
|
||||
|
||||
DECL_LAST = DECL_UNNAMED_GLOBAL_CONSTANT
|
||||
/// A HLSLBufferDecl record.
|
||||
DECL_HLSL_BUFFER,
|
||||
|
||||
DECL_LAST = DECL_HLSL_BUFFER
|
||||
};
|
||||
|
||||
/// Record codes for each kind of statement or expression.
|
||||
|
|
|
@ -5210,6 +5210,40 @@ EmptyDecl *EmptyDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
|
|||
return new (C, ID) EmptyDecl(nullptr, SourceLocation());
|
||||
}
|
||||
|
||||
HLSLBufferDecl::HLSLBufferDecl(DeclContext *DC, bool CBuffer,
|
||||
SourceLocation KwLoc, IdentifierInfo *ID,
|
||||
SourceLocation IDLoc, SourceLocation LBrace)
|
||||
: NamedDecl(Decl::Kind::HLSLBuffer, DC, IDLoc, DeclarationName(ID)),
|
||||
DeclContext(Decl::Kind::HLSLBuffer), LBraceLoc(LBrace), KwLoc(KwLoc),
|
||||
IsCBuffer(CBuffer) {}
|
||||
|
||||
HLSLBufferDecl *HLSLBufferDecl::Create(ASTContext &C,
|
||||
DeclContext *LexicalParent, bool CBuffer,
|
||||
SourceLocation KwLoc, IdentifierInfo *ID,
|
||||
SourceLocation IDLoc,
|
||||
SourceLocation LBrace) {
|
||||
// For hlsl like this
|
||||
// cbuffer A {
|
||||
// cbuffer B {
|
||||
// }
|
||||
// }
|
||||
// compiler should treat it as
|
||||
// cbuffer A {
|
||||
// }
|
||||
// cbuffer B {
|
||||
// }
|
||||
// FIXME: support nested buffers if required for back-compat.
|
||||
DeclContext *DC = LexicalParent;
|
||||
HLSLBufferDecl *Result =
|
||||
new (C, DC) HLSLBufferDecl(DC, CBuffer, KwLoc, ID, IDLoc, LBrace);
|
||||
return Result;
|
||||
}
|
||||
|
||||
HLSLBufferDecl *HLSLBufferDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
|
||||
return new (C, ID) HLSLBufferDecl(nullptr, false, SourceLocation(), nullptr,
|
||||
SourceLocation(), SourceLocation());
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ImportDecl Implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -750,6 +750,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
|
|||
case ObjCMethod:
|
||||
case ObjCProperty:
|
||||
case MSProperty:
|
||||
case HLSLBuffer:
|
||||
return IDNS_Ordinary;
|
||||
case Label:
|
||||
return IDNS_Label;
|
||||
|
@ -1193,7 +1194,7 @@ bool DeclContext::isTransparentContext() const {
|
|||
if (getDeclKind() == Decl::Enum)
|
||||
return !cast<EnumDecl>(this)->isScoped();
|
||||
|
||||
return getDeclKind() == Decl::LinkageSpec || getDeclKind() == Decl::Export;
|
||||
return isa<LinkageSpecDecl, ExportDecl, HLSLBufferDecl>(this);
|
||||
}
|
||||
|
||||
static bool isLinkageSpecContext(const DeclContext *DC,
|
||||
|
@ -1258,6 +1259,15 @@ DeclContext *DeclContext::getPrimaryContext() {
|
|||
// There is only one DeclContext for these entities.
|
||||
return this;
|
||||
|
||||
case Decl::HLSLBuffer:
|
||||
// Each buffer, even with the same name, is a distinct construct.
|
||||
// Multiple buffers with the same name are allowed for backward
|
||||
// compatibility.
|
||||
// As long as buffers have unique resource bindings the names don't matter.
|
||||
// The names get exposed via the CPU-side reflection API which
|
||||
// supports querying bindings, so we cannot remove them.
|
||||
return this;
|
||||
|
||||
case Decl::TranslationUnit:
|
||||
return static_cast<TranslationUnitDecl *>(this)->getFirstDecl();
|
||||
case Decl::Namespace:
|
||||
|
|
|
@ -108,6 +108,7 @@ namespace {
|
|||
void VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D);
|
||||
void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *TTP);
|
||||
void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *NTTP);
|
||||
void VisitHLSLBufferDecl(HLSLBufferDecl *D);
|
||||
|
||||
void printTemplateParameters(const TemplateParameterList *Params,
|
||||
bool OmitTemplateKW = false);
|
||||
|
@ -462,12 +463,9 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) {
|
|||
Terminator = nullptr;
|
||||
else
|
||||
Terminator = ";";
|
||||
} else if (isa<NamespaceDecl>(*D) || isa<LinkageSpecDecl>(*D) ||
|
||||
isa<ObjCImplementationDecl>(*D) ||
|
||||
isa<ObjCInterfaceDecl>(*D) ||
|
||||
isa<ObjCProtocolDecl>(*D) ||
|
||||
isa<ObjCCategoryImplDecl>(*D) ||
|
||||
isa<ObjCCategoryDecl>(*D))
|
||||
} else if (isa<NamespaceDecl, LinkageSpecDecl, ObjCImplementationDecl,
|
||||
ObjCInterfaceDecl, ObjCProtocolDecl, ObjCCategoryImplDecl,
|
||||
ObjCCategoryDecl, HLSLBufferDecl>(*D))
|
||||
Terminator = nullptr;
|
||||
else if (isa<EnumConstantDecl>(*D)) {
|
||||
DeclContext::decl_iterator Next = D;
|
||||
|
@ -1658,6 +1656,21 @@ void DeclPrinter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) {
|
|||
}
|
||||
}
|
||||
|
||||
void DeclPrinter::VisitHLSLBufferDecl(HLSLBufferDecl *D) {
|
||||
if (D->isCBuffer())
|
||||
Out << "cbuffer ";
|
||||
else
|
||||
Out << "tbuffer ";
|
||||
|
||||
Out << *D;
|
||||
|
||||
prettyPrintAttributes(D);
|
||||
|
||||
Out << " {\n";
|
||||
VisitDeclContext(D);
|
||||
Indent() << "}";
|
||||
}
|
||||
|
||||
void DeclPrinter::VisitOMPAllocateDecl(OMPAllocateDecl *D) {
|
||||
Out << "#pragma omp allocate";
|
||||
if (!D->varlist_empty()) {
|
||||
|
|
|
@ -901,6 +901,11 @@ void JSONNodeDumper::VisitCXXRecordDecl(const CXXRecordDecl *RD) {
|
|||
}
|
||||
}
|
||||
|
||||
void JSONNodeDumper::VisitHLSLBufferDecl(const HLSLBufferDecl *D) {
|
||||
VisitNamedDecl(D);
|
||||
JOS.attribute("bufferKind", D->isCBuffer() ? "cbuffer" : "tbuffer");
|
||||
}
|
||||
|
||||
void JSONNodeDumper::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) {
|
||||
VisitNamedDecl(D);
|
||||
JOS.attribute("tagUsed", D->wasDeclaredWithTypename() ? "typename" : "class");
|
||||
|
|
|
@ -2388,3 +2388,11 @@ void TextNodeDumper::VisitCompoundStmt(const CompoundStmt *S) {
|
|||
if (S->hasStoredFPFeatures())
|
||||
printFPOptions(S->getStoredFPFeatures());
|
||||
}
|
||||
|
||||
void TextNodeDumper::VisitHLSLBufferDecl(const HLSLBufferDecl *D) {
|
||||
if (D->isCBuffer())
|
||||
OS << " cbuffer";
|
||||
else
|
||||
OS << " tbuffer";
|
||||
dumpName(D);
|
||||
}
|
||||
|
|
|
@ -109,7 +109,8 @@ namespace {
|
|||
KEYMSCOMPAT = 0x400000,
|
||||
KEYSYCL = 0x800000,
|
||||
KEYCUDA = 0x1000000,
|
||||
KEYMAX = KEYCUDA, // The maximum key
|
||||
KEYHLSL = 0x2000000,
|
||||
KEYMAX = KEYHLSL, // The maximum key
|
||||
KEYALLCXX = KEYCXX | KEYCXX11 | KEYCXX20,
|
||||
KEYALL = (KEYMAX | (KEYMAX-1)) & ~KEYNOMS18 &
|
||||
~KEYNOOPENCL // KEYNOMS18 and KEYNOOPENCL are used to exclude.
|
||||
|
@ -199,6 +200,8 @@ static KeywordStatus getKeywordStatusHelper(const LangOptions &LangOpts,
|
|||
return LangOpts.isSYCL() ? KS_Enabled : KS_Unknown;
|
||||
case KEYCUDA:
|
||||
return LangOpts.CUDA ? KS_Enabled : KS_Unknown;
|
||||
case KEYHLSL:
|
||||
return LangOpts.HLSL ? KS_Enabled : KS_Unknown;
|
||||
case KEYNOCXX:
|
||||
// This is enabled in all non-C++ modes, but might be enabled for other
|
||||
// reasons as well.
|
||||
|
|
|
@ -1787,6 +1787,11 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(DeclaratorContext Context,
|
|||
}
|
||||
return ParseSimpleDeclaration(Context, DeclEnd, DeclAttrs, DeclSpecAttrs,
|
||||
true, nullptr, DeclSpecStart);
|
||||
|
||||
case tok::kw_cbuffer:
|
||||
case tok::kw_tbuffer:
|
||||
SingleDecl = ParseHLSLBuffer(DeclEnd);
|
||||
break;
|
||||
case tok::kw_namespace:
|
||||
ProhibitAttributes(DeclAttrs);
|
||||
ProhibitAttributes(DeclSpecAttrs);
|
||||
|
|
|
@ -13,9 +13,89 @@
|
|||
#include "clang/Basic/AttributeCommonInfo.h"
|
||||
#include "clang/Parse/ParseDiagnostic.h"
|
||||
#include "clang/Parse/Parser.h"
|
||||
#include "clang/Parse/RAIIObjectsForParser.h"
|
||||
|
||||
using namespace clang;
|
||||
|
||||
static bool validateDeclsInsideHLSLBuffer(Parser::DeclGroupPtrTy DG,
|
||||
SourceLocation BufferLoc,
|
||||
bool IsCBuffer, Parser &P) {
|
||||
// The parse is failed, just return false.
|
||||
if (!DG)
|
||||
return false;
|
||||
DeclGroupRef Decls = DG.get();
|
||||
bool IsValid = true;
|
||||
// Only allow function, variable, record decls inside HLSLBuffer.
|
||||
for (DeclGroupRef::iterator I = Decls.begin(), E = Decls.end(); I != E; ++I) {
|
||||
Decl *D = *I;
|
||||
if (isa<CXXRecordDecl, RecordDecl, FunctionDecl, VarDecl>(D))
|
||||
continue;
|
||||
|
||||
// FIXME: support nested HLSLBuffer and namespace inside HLSLBuffer.
|
||||
if (isa<HLSLBufferDecl, NamespaceDecl>(D)) {
|
||||
P.Diag(D->getLocation(), diag::err_invalid_declaration_in_hlsl_buffer)
|
||||
<< IsCBuffer;
|
||||
IsValid = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
IsValid = false;
|
||||
P.Diag(D->getLocation(), diag::err_invalid_declaration_in_hlsl_buffer)
|
||||
<< IsCBuffer;
|
||||
}
|
||||
return IsValid;
|
||||
}
|
||||
|
||||
Decl *Parser::ParseHLSLBuffer(SourceLocation &DeclEnd) {
|
||||
assert((Tok.is(tok::kw_cbuffer) || Tok.is(tok::kw_tbuffer)) &&
|
||||
"Not a cbuffer or tbuffer!");
|
||||
bool IsCBuffer = Tok.is(tok::kw_cbuffer);
|
||||
SourceLocation BufferLoc = ConsumeToken(); // Eat the 'cbuffer' or 'tbuffer'.
|
||||
|
||||
if (!Tok.is(tok::identifier)) {
|
||||
Diag(Tok, diag::err_expected) << tok::identifier;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IdentifierInfo *Identifier = Tok.getIdentifierInfo();
|
||||
SourceLocation IdentifierLoc = ConsumeToken();
|
||||
|
||||
ParseScope BufferScope(this, Scope::DeclScope);
|
||||
BalancedDelimiterTracker T(*this, tok::l_brace);
|
||||
if (T.consumeOpen()) {
|
||||
Diag(Tok, diag::err_expected) << tok::l_brace;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Decl *D = Actions.ActOnStartHLSLBuffer(getCurScope(), IsCBuffer, BufferLoc,
|
||||
Identifier, IdentifierLoc,
|
||||
T.getOpenLocation());
|
||||
|
||||
// FIXME: support attribute on cbuffer/tbuffer.
|
||||
while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
|
||||
SourceLocation Loc = Tok.getLocation();
|
||||
// FIXME: support attribute on constants inside cbuffer/tbuffer.
|
||||
ParsedAttributes Attrs(AttrFactory);
|
||||
|
||||
DeclGroupPtrTy Result = ParseExternalDeclaration(Attrs);
|
||||
if (!validateDeclsInsideHLSLBuffer(Result, IdentifierLoc, IsCBuffer,
|
||||
*this)) {
|
||||
T.skipToEnd();
|
||||
DeclEnd = T.getCloseLocation();
|
||||
BufferScope.Exit();
|
||||
Actions.ActOnFinishHLSLBuffer(D, DeclEnd);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
T.consumeClose();
|
||||
DeclEnd = T.getCloseLocation();
|
||||
BufferScope.Exit();
|
||||
Actions.ActOnFinishHLSLBuffer(D, DeclEnd);
|
||||
|
||||
return D;
|
||||
}
|
||||
|
||||
void Parser::ParseHLSLSemantics(ParsedAttributes &Attrs,
|
||||
SourceLocation *EndLoc) {
|
||||
assert(Tok.is(tok::colon) && "Not a HLSL Semantic");
|
||||
|
|
|
@ -947,6 +947,16 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(ParsedAttributes &Attrs,
|
|||
EmptyDeclSpecAttrs);
|
||||
}
|
||||
|
||||
case tok::kw_cbuffer:
|
||||
case tok::kw_tbuffer:
|
||||
if (getLangOpts().HLSL) {
|
||||
SourceLocation DeclEnd;
|
||||
ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);
|
||||
return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs,
|
||||
EmptyDeclSpecAttrs);
|
||||
}
|
||||
goto dont_know;
|
||||
|
||||
case tok::kw_static:
|
||||
// Parse (then ignore) 'static' prior to a template instantiation. This is
|
||||
// a GCC extension that we intentionally do not support.
|
||||
|
|
|
@ -44,6 +44,7 @@ add_clang_library(clangSema
|
|||
SemaExprMember.cpp
|
||||
SemaExprObjC.cpp
|
||||
SemaFixItUtils.cpp
|
||||
SemaHLSL.cpp
|
||||
SemaInit.cpp
|
||||
SemaLambda.cpp
|
||||
SemaLookup.cpp
|
||||
|
|
|
@ -99,7 +99,11 @@ IdentifierResolver::~IdentifierResolver() {
|
|||
bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx, Scope *S,
|
||||
bool AllowInlineNamespace) const {
|
||||
Ctx = Ctx->getRedeclContext();
|
||||
|
||||
// The names for HLSL cbuffer/tbuffers only used by the CPU-side
|
||||
// reflection API which supports querying bindings. It will not have name
|
||||
// conflict with other Decls.
|
||||
if (LangOpt.HLSL && isa<HLSLBufferDecl>(D))
|
||||
return false;
|
||||
if (Ctx->isFunctionOrMethod() || (S && S->isFunctionPrototypeScope())) {
|
||||
// Ignore the scopes associated within transparent declaration contexts.
|
||||
while (S->getEntity() && S->getEntity()->isTransparentContext())
|
||||
|
|
|
@ -7123,6 +7123,9 @@ static bool shouldConsiderLinkage(const VarDecl *VD) {
|
|||
return true;
|
||||
if (DC->isRecord())
|
||||
return false;
|
||||
if (DC->getDeclKind() == Decl::HLSLBuffer)
|
||||
return false;
|
||||
|
||||
if (isa<RequiresExprBodyDecl>(DC))
|
||||
return false;
|
||||
llvm_unreachable("Unexpected context");
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
//===- SemaHLSL.cpp - Semantic Analysis for HLSL constructs ---------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// This implements Semantic Analysis for HLSL constructs.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Sema/Sema.h"
|
||||
|
||||
using namespace clang;
|
||||
|
||||
Decl *Sema::ActOnStartHLSLBuffer(Scope *BufferScope, bool CBuffer,
|
||||
SourceLocation KwLoc, IdentifierInfo *Ident,
|
||||
SourceLocation IdentLoc,
|
||||
SourceLocation LBrace) {
|
||||
// For anonymous namespace, take the location of the left brace.
|
||||
DeclContext *LexicalParent = getCurLexicalContext();
|
||||
HLSLBufferDecl *Result = HLSLBufferDecl::Create(
|
||||
Context, LexicalParent, CBuffer, KwLoc, Ident, IdentLoc, LBrace);
|
||||
|
||||
PushOnScopeChains(Result, BufferScope);
|
||||
PushDeclContext(BufferScope, Result);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
void Sema::ActOnFinishHLSLBuffer(Decl *Dcl, SourceLocation RBrace) {
|
||||
auto *BufDecl = cast<HLSLBufferDecl>(Dcl);
|
||||
BufDecl->setRBraceLoc(RBrace);
|
||||
PopDeclContext();
|
||||
}
|
|
@ -519,7 +519,8 @@ void LookupResult::resolveKind() {
|
|||
D = cast<NamedDecl>(D->getCanonicalDecl());
|
||||
|
||||
// Ignore an invalid declaration unless it's the only one left.
|
||||
if (D->isInvalidDecl() && !(I == 0 && N == 1)) {
|
||||
// Also ignore HLSLBufferDecl which not have name conflict with other Decls.
|
||||
if ((D->isInvalidDecl() || isa<HLSLBufferDecl>(D)) && !(I == 0 && N == 1)) {
|
||||
Decls[I] = Decls[--N];
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -876,6 +876,10 @@ TemplateDeclInstantiator::VisitTranslationUnitDecl(TranslationUnitDecl *D) {
|
|||
llvm_unreachable("Translation units cannot be instantiated");
|
||||
}
|
||||
|
||||
Decl *TemplateDeclInstantiator::VisitHLSLBufferDecl(HLSLBufferDecl *Decl) {
|
||||
llvm_unreachable("HLSL buffer declarations cannot be instantiated");
|
||||
}
|
||||
|
||||
Decl *
|
||||
TemplateDeclInstantiator::VisitPragmaCommentDecl(PragmaCommentDecl *D) {
|
||||
llvm_unreachable("pragma comment cannot be instantiated");
|
||||
|
|
|
@ -433,6 +433,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) {
|
|||
case Decl::LifetimeExtendedTemporary:
|
||||
case Decl::RequiresExprBody:
|
||||
case Decl::UnresolvedUsingIfExists:
|
||||
case Decl::HLSLBuffer:
|
||||
return false;
|
||||
|
||||
// These indirectly derive from Redeclarable<T> but are not actually
|
||||
|
|
|
@ -322,6 +322,7 @@ namespace clang {
|
|||
void VisitNamedDecl(NamedDecl *ND);
|
||||
void VisitLabelDecl(LabelDecl *LD);
|
||||
void VisitNamespaceDecl(NamespaceDecl *D);
|
||||
void VisitHLSLBufferDecl(HLSLBufferDecl *D);
|
||||
void VisitUsingDirectiveDecl(UsingDirectiveDecl *D);
|
||||
void VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
|
||||
void VisitTypeDecl(TypeDecl *TD);
|
||||
|
@ -1735,6 +1736,15 @@ void ASTDeclReader::VisitNamespaceDecl(NamespaceDecl *D) {
|
|||
}
|
||||
}
|
||||
|
||||
void ASTDeclReader::VisitHLSLBufferDecl(HLSLBufferDecl *D) {
|
||||
VisitNamedDecl(D);
|
||||
VisitDeclContext(D);
|
||||
D->IsCBuffer = Record.readBool();
|
||||
D->KwLoc = readSourceLocation();
|
||||
D->LBraceLoc = readSourceLocation();
|
||||
D->RBraceLoc = readSourceLocation();
|
||||
}
|
||||
|
||||
void ASTDeclReader::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
|
||||
RedeclarableResult Redecl = VisitRedeclarable(D);
|
||||
VisitNamedDecl(D);
|
||||
|
@ -3855,6 +3865,9 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
|
|||
case DECL_OBJC_TYPE_PARAM:
|
||||
D = ObjCTypeParamDecl::CreateDeserialized(Context, ID);
|
||||
break;
|
||||
case DECL_HLSL_BUFFER:
|
||||
D = HLSLBufferDecl::CreateDeserialized(Context, ID);
|
||||
break;
|
||||
}
|
||||
|
||||
assert(D && "Unknown declaration reading AST file");
|
||||
|
|
|
@ -1017,6 +1017,7 @@ void ASTWriter::WriteBlockInfoBlock() {
|
|||
RECORD(DECL_PRAGMA_DETECT_MISMATCH);
|
||||
RECORD(DECL_OMP_DECLARE_REDUCTION);
|
||||
RECORD(DECL_OMP_ALLOCATE);
|
||||
RECORD(DECL_HLSL_BUFFER);
|
||||
|
||||
// Statements and Exprs can occur in the Decls and Types block.
|
||||
AddStmtsExprs(Stream, Record);
|
||||
|
|
|
@ -131,10 +131,9 @@ namespace clang {
|
|||
void VisitCapturedDecl(CapturedDecl *D);
|
||||
void VisitEmptyDecl(EmptyDecl *D);
|
||||
void VisitLifetimeExtendedTemporaryDecl(LifetimeExtendedTemporaryDecl *D);
|
||||
|
||||
void VisitDeclContext(DeclContext *DC);
|
||||
template <typename T> void VisitRedeclarable(Redeclarable<T> *D);
|
||||
|
||||
void VisitHLSLBufferDecl(HLSLBufferDecl *D);
|
||||
|
||||
// FIXME: Put in the same order is DeclNodes.td?
|
||||
void VisitObjCMethodDecl(ObjCMethodDecl *D);
|
||||
|
@ -1864,6 +1863,17 @@ void ASTDeclWriter::VisitRedeclarable(Redeclarable<T> *D) {
|
|||
}
|
||||
}
|
||||
|
||||
void ASTDeclWriter::VisitHLSLBufferDecl(HLSLBufferDecl *D) {
|
||||
VisitNamedDecl(D);
|
||||
VisitDeclContext(D);
|
||||
Record.push_back(D->isCBuffer());
|
||||
Record.AddSourceLocation(D->getLocStart());
|
||||
Record.AddSourceLocation(D->getLBraceLoc());
|
||||
Record.AddSourceLocation(D->getRBraceLoc());
|
||||
|
||||
Code = serialization::DECL_HLSL_BUFFER;
|
||||
}
|
||||
|
||||
void ASTDeclWriter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) {
|
||||
Record.writeOMPChildren(D->Data);
|
||||
VisitDecl(D);
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
// RUN: %clang_cc1 -Wdocumentation -ast-dump=json -x hlsl -triple dxil-pc-shadermodel6.3-library %s | FileCheck %s --check-prefix=JSON
|
||||
// RUN: %clang_cc1 -Wdocumentation -ast-dump -x hlsl -triple dxil-pc-shadermodel6.3-library %s | FileCheck %s --check-prefix=AST
|
||||
|
||||
// JSON:"kind": "HLSLBufferDecl",
|
||||
// JSON:"name": "A",
|
||||
// JSON-NEXT:"bufferKind": "cbuffer",
|
||||
// JSON:"kind": "TextComment",
|
||||
// JSON:"text": " CBuffer decl."
|
||||
|
||||
/// CBuffer decl.
|
||||
cbuffer A {
|
||||
// JSON: "kind": "VarDecl",
|
||||
// JSON: "name": "a",
|
||||
// JSON: "qualType": "float"
|
||||
float a;
|
||||
// JSON: "kind": "VarDecl",
|
||||
// JSON: "name": "b",
|
||||
// JSON: "qualType": "int"
|
||||
int b;
|
||||
}
|
||||
|
||||
// JSON:"kind": "HLSLBufferDecl",
|
||||
// JSON:"name": "B",
|
||||
// JSON-NEXT:"bufferKind": "tbuffer",
|
||||
// JSON:"kind": "TextComment",
|
||||
// JSON:"text": " TBuffer decl."
|
||||
|
||||
/// TBuffer decl.
|
||||
tbuffer B {
|
||||
// JSON: "kind": "VarDecl",
|
||||
// JSON: "name": "c",
|
||||
// JSON: "qualType": "float"
|
||||
float c;
|
||||
// JSON: "kind": "VarDecl",
|
||||
// JSON: "name": "d",
|
||||
// JSON: "qualType": "int"
|
||||
int d;
|
||||
}
|
||||
|
||||
// AST:HLSLBufferDecl {{.*}}:11:1, line:20:1> line:11:9 cbuffer A
|
||||
// AST-NEXT:FullComment {{.*}}<line:10:4, col:17>
|
||||
// AST-NEXT:`-ParagraphComment {{.*}}<col:4, col:17>
|
||||
// AST-NEXT:`-TextComment {{.*}}<col:4, col:17> Text=" CBuffer decl."
|
||||
// AST-NEXT:-VarDecl {{.*}}<line:15:5, col:11> col:11 a 'float'
|
||||
// AST-NEXT:`-VarDecl {{.*}}<line:19:5, col:9> col:9 b 'int'
|
||||
// AST-NEXT:HLSLBufferDecl {{.*}}<line:29:1, line:38:1> line:29:9 tbuffer B
|
||||
// AST-NEXT:-FullComment {{.*}}<line:28:4, col:17>
|
||||
// AST-NEXT: `-ParagraphComment {{.*}}<col:4, col:17>
|
||||
// AST-NEXT: `-TextComment {{.*}}<col:4, col:17> Text=" TBuffer decl."
|
||||
// AST-NEXT:-VarDecl {{.*}}<line:33:5, col:11> col:11 c 'float'
|
||||
// AST-NEXT:`-VarDecl {{.*}} <line:37:5, col:9> col:9 d 'int'
|
|
@ -0,0 +1,22 @@
|
|||
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -ast-dump -o - %s | FileCheck %s
|
||||
|
||||
// CHECK:HLSLBufferDecl 0x[[CB:[0-9a-f]+]] {{.*}} line:5:9 cbuffer CB
|
||||
// CHECK-NEXT:VarDecl 0x[[A:[0-9a-f]+]] {{.*}} col:9 used a 'float'
|
||||
cbuffer CB {
|
||||
float a;
|
||||
}
|
||||
|
||||
// CHECK:HLSLBufferDecl 0x[[TB:[0-9a-f]+]] {{.*}} line:11:9 tbuffer TB
|
||||
// CHECK-NEXT:VarDecl 0x[[B:[0-9a-f]+]] {{.*}} col:9 used b 'float'
|
||||
tbuffer TB {
|
||||
float b;
|
||||
}
|
||||
|
||||
float foo() {
|
||||
// CHECK: BinaryOperator 0x{{[0-9a-f]+}} <col:10, col:14> 'float' '+'
|
||||
// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-f]+}} <col:10> 'float' <LValueToRValue>
|
||||
// CHECK-NEXT: DeclRefExpr 0x{{[0-9a-f]+}} <col:10> 'float' lvalue Var 0x[[A]] 'a' 'float'
|
||||
// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-f]+}} <col:14> 'float' <LValueToRValue>
|
||||
// CHECK-NEXT: DeclRefExpr 0x{{[0-9a-f]+}} <col:14> 'float' lvalue Var 0x[[B]] 'b' 'float'
|
||||
return a + b;
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl \
|
||||
// RUN: -emit-pch -o %t %s
|
||||
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl \
|
||||
// RUN: -include-pch %t -fsyntax-only -ast-dump-all %S/Inputs/empty.hlsl \
|
||||
// RUN: | FileCheck %s
|
||||
|
||||
cbuffer A {
|
||||
float a;
|
||||
}
|
||||
|
||||
tbuffer B {
|
||||
float b;
|
||||
}
|
||||
|
||||
float foo() {
|
||||
return a + b;
|
||||
}
|
||||
// Make sure cbuffer/tbuffer works for PCH.
|
||||
// CHECK:HLSLBufferDecl 0x{{[0-9a-f]+}} <{{.*}}:7:1, line:9:1> line:7:9 imported <undeserialized declarations> cbuffer A
|
||||
// CHECK-NEXT:`-VarDecl 0x[[A:[0-9a-f]+]] <line:8:3, col:9> col:9 imported used a 'float'
|
||||
// CHECK-NEXT:HLSLBufferDecl 0x{{[0-9a-f]+}} <line:11:1, line:13:1> line:11:9 imported <undeserialized declarations> tbuffer B
|
||||
// CHECK-NEXT:`-VarDecl 0x[[B:[0-9a-f]+]] <line:12:3, col:9> col:9 imported used b 'float'
|
||||
// CHECK-NEXT:FunctionDecl 0x{{[0-9a-f]+}} <line:15:1, line:17:1> line:15:7 imported foo 'float ()'
|
||||
// CHECK-NEXT:CompoundStmt 0x{{[0-9a-f]+}} <col:13, line:17:1>
|
||||
// CHECK-NEXT:ReturnStmt 0x{{[0-9a-f]+}} <line:16:3, col:14>
|
||||
// CHECK-NEXT:BinaryOperator 0x{{[0-9a-f]+}} <col:10, col:14> 'float' '+'
|
||||
// CHECK-NEXT:ImplicitCastExpr 0x{{[0-9a-f]+}} <col:10> 'float' <LValueToRValue>
|
||||
// CHECK-NEXT:`-DeclRefExpr 0x{{[0-9a-f]+}} <col:10> 'float' lvalue Var 0x[[A]] 'a' 'float'
|
||||
// CHECK-NEXT:`-ImplicitCastExpr 0x{{[0-9a-f]+}} <col:14> 'float' <LValueToRValue>
|
||||
// CHECK-NEXT:`-DeclRefExpr 0x{{[0-9a-f]+}} <col:14> 'float' lvalue Var 0x[[B]] 'b' 'float'
|
|
@ -0,0 +1,74 @@
|
|||
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -o - -fsyntax-only %s -verify
|
||||
|
||||
// expected-error@+2 {{expected identifier}}
|
||||
// expected-error@+1 {{expected unqualified-id}}
|
||||
cbuffer { ... };
|
||||
// expected-error@+1 {{expected '{'}}
|
||||
cbuffer missing_definition;
|
||||
// expected-error@+1 {{expected unqualified-id}}
|
||||
int cbuffer;
|
||||
// expected-error@+1 {{expected identifier}}
|
||||
cbuffer;
|
||||
|
||||
// expected-error@+2 {{expected identifier}}
|
||||
// expected-error@+1 {{expected unqualified-id}}
|
||||
tbuffer { ... };
|
||||
// expected-error@+1 {{expected '{'}}
|
||||
tbuffer missing_definition;
|
||||
// expected-error@+1 {{expected unqualified-id}}
|
||||
int tbuffer;
|
||||
// expected-error@+1 {{expected identifier}}
|
||||
tbuffer;
|
||||
|
||||
// expected-error@+1 {{expected unqualified-id}}
|
||||
cbuffer A {}, B{}
|
||||
|
||||
// cbuffer inside namespace is supported.
|
||||
namespace N {
|
||||
cbuffer A {
|
||||
float g;
|
||||
}
|
||||
}
|
||||
|
||||
cbuffer A {
|
||||
// expected-error@+1 {{invalid declaration inside cbuffer}}
|
||||
namespace N {
|
||||
}
|
||||
}
|
||||
|
||||
cbuffer A {
|
||||
// expected-error@+1 {{invalid declaration inside cbuffer}}
|
||||
cbuffer Nested {
|
||||
}
|
||||
}
|
||||
|
||||
struct S {
|
||||
// expected-error@+1 {{expected member name or ';' after declaration specifiers}}
|
||||
cbuffer what {
|
||||
int y;
|
||||
}
|
||||
};
|
||||
|
||||
void func() {
|
||||
// expected-error@+1 {{expected expression}}
|
||||
tbuffer derp {
|
||||
int z;
|
||||
}
|
||||
|
||||
decltype(derp) another {
|
||||
int a;
|
||||
}
|
||||
}
|
||||
|
||||
// struct decl inside cb is supported.
|
||||
cbuffer A {
|
||||
struct S2 {
|
||||
float s;
|
||||
};
|
||||
S2 s;
|
||||
}
|
||||
|
||||
// function decl inside cb is supported.
|
||||
cbuffer A {
|
||||
float foo_inside_cb() { return 1.2;}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -o - -fsyntax-only %s -verify
|
||||
|
||||
// template not allowed inside cbuffer.
|
||||
cbuffer A {
|
||||
// expected-error@+2 {{invalid declaration inside cbuffer}}
|
||||
template<typename T>
|
||||
T foo(T t) { return t;}
|
||||
}
|
||||
|
||||
cbuffer A {
|
||||
// expected-error@+2 {{invalid declaration inside cbuffer}}
|
||||
template<typename T>
|
||||
struct S { float s;};
|
||||
}
|
||||
|
||||
// typealias not allowed inside cbuffer.
|
||||
cbuffer A {
|
||||
// expected-error@+2 {{invalid declaration inside cbuffer}}
|
||||
// expected-warning@+1 {{alias declarations are a C++11 extension}}
|
||||
using F32 = float;
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -o - -fsyntax-only %s -verify
|
||||
|
||||
// expected-note@+1 {{declared here}}
|
||||
cbuffer a {
|
||||
int x;
|
||||
};
|
||||
|
||||
int foo() {
|
||||
// expected-error@+1 {{'a' does not refer to a value}}
|
||||
return sizeof(a);
|
||||
}
|
||||
|
||||
// expected-error@+1 {{expected unqualified-id}}
|
||||
template <typename Ty> cbuffer a { Ty f; };
|
||||
|
||||
// For back-compat reason, it is OK for multiple cbuffer/tbuffer use same name in hlsl.
|
||||
// And these cbuffer name only used for reflection, cannot be removed.
|
||||
cbuffer A {
|
||||
float A;
|
||||
}
|
||||
|
||||
cbuffer A {
|
||||
float b;
|
||||
}
|
||||
|
||||
tbuffer A {
|
||||
float a;
|
||||
}
|
||||
|
||||
float bar() {
|
||||
// cbuffer/tbuffer name will not conflict with other variables.
|
||||
return A;
|
||||
}
|
||||
|
||||
cbuffer a {
|
||||
// expected-error@+2 {{unknown type name 'oh'}}
|
||||
// expected-error@+1 {{expected ';' after top level declarator}}
|
||||
oh no!
|
||||
// expected-warning@+1 {{missing terminating ' character}}
|
||||
this isn't even valid HLSL code
|
||||
despite seeming totally reasonable
|
||||
once you understand that HLSL
|
||||
is so flaming weird.
|
||||
}
|
||||
|
||||
tbuffer B {
|
||||
// expected-error@+1 {{unknown type name 'flaot'}}
|
||||
flaot f;
|
||||
}
|
Loading…
Reference in New Issue