-
Notifications
You must be signed in to change notification settings - Fork 12k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[HLSL] Add implicit resource element type concepts to AST #112600
Changes from 21 commits
ab60544
b43675f
4307e45
4beb3a3
98200c0
f70fb48
54917b1
6ebe14a
1ecd544
19664f5
ea0ac08
d220a73
8014a47
8516483
defc84e
b373f15
4fecdc4
80d2d25
d770236
1159b02
cf1a7fd
17696d8
6edf031
fae51c5
1722578
f50b917
47f106b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -300,8 +300,9 @@ struct BuiltinTypeDeclBuilder { | |||||
} | ||||||
|
||||||
TemplateParameterListBuilder addTemplateArgumentList(Sema &S); | ||||||
BuiltinTypeDeclBuilder &addSimpleTemplateParams(Sema &S, | ||||||
ArrayRef<StringRef> Names); | ||||||
BuiltinTypeDeclBuilder & | ||||||
addSimpleTemplateParams(Sema &S, ArrayRef<StringRef> Names, ConceptDecl *CD); | ||||||
BuiltinTypeDeclBuilder &addConceptSpecializationExpr(Sema &S); | ||||||
}; | ||||||
|
||||||
struct TemplateParameterListBuilder { | ||||||
|
@@ -323,30 +324,127 @@ struct TemplateParameterListBuilder { | |||||
S.Context, Builder.Record->getDeclContext(), SourceLocation(), | ||||||
SourceLocation(), /* TemplateDepth */ 0, Position, | ||||||
&S.Context.Idents.get(Name, tok::TokenKind::identifier), | ||||||
/* Typename */ false, | ||||||
/* ParameterPack */ false); | ||||||
/* Typename */ true, | ||||||
/* ParameterPack */ false, | ||||||
/* HasTypeConstraint*/ false); | ||||||
if (!DefaultValue.isNull()) | ||||||
Decl->setDefaultArgument( | ||||||
S.Context, S.getTrivialTemplateArgumentLoc(DefaultValue, QualType(), | ||||||
SourceLocation())); | ||||||
|
||||||
Params.emplace_back(Decl); | ||||||
return *this; | ||||||
} | ||||||
|
||||||
BuiltinTypeDeclBuilder &finalizeTemplateArgs() { | ||||||
/* | ||||||
The concept specialization expression (CSE) constructed below is constructed | ||||||
so that it matches the CSE that is constructed when parsing | ||||||
the below C++ code: | ||||||
|
||||||
template<typename T> | ||||||
concept is_valid_line_vector =sizeof(T) <= 16; | ||||||
|
||||||
template<typename element_type> requires is_valid_line_vector<element_type> | ||||||
|
||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The blank line between the template bit and the struct really confused me for a while trying to read this. |
||||||
struct RWBuffer { | ||||||
element_type Val; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think that the code in this comment really matches the AST that's being built. RWBuffer doesn't have a member of type element_type, for example. I think that this function is just building up the AST that corresponds to the The AST nodes for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree that when parsing the C++ code in the comment, it produces more of the AST than the function is producing, but I still believe that including that extra context in the comments is helpful. The C++ code adds the structure "RWBuffer", and though it isn't being produced by The first point of the comment says that For your last 2 questions, yes I think your statements are accurate. |
||||||
}; | ||||||
|
||||||
int fn() { | ||||||
RWBuffer<int> Buf; | ||||||
} | ||||||
|
||||||
When dumping the AST and filtering for "RWBuffer", the resulting AST | ||||||
structure is what we're trying to construct below, specifically the | ||||||
CSE portion. | ||||||
*/ | ||||||
ConceptSpecializationExpr * | ||||||
constructConceptSpecializationExpr(Sema &S, ConceptDecl *CD) { | ||||||
ASTContext &Context = S.getASTContext(); | ||||||
SourceLocation Loc = Builder.Record->getBeginLoc(); | ||||||
DeclarationNameInfo DNI(CD->getDeclName(), Loc); | ||||||
NestedNameSpecifierLoc NNSLoc; | ||||||
DeclContext *DC = Builder.Record->getDeclContext(); | ||||||
TemplateArgumentListInfo TALI(Loc, Loc); | ||||||
|
||||||
// Assume that the concept decl has just one template parameter | ||||||
// This parameter should have been added when CD was constructed | ||||||
// in getTypedBufferConceptDecl | ||||||
assert(CD->getTemplateParameters()->size() == 1 && | ||||||
"unexpected concept decl parameter count"); | ||||||
TemplateTypeParmDecl *ConceptTTPD = dyn_cast<TemplateTypeParmDecl>( | ||||||
CD->getTemplateParameters()->getParam(0)); | ||||||
|
||||||
// this fake TemplateTypeParmDecl is used to construct a template argument | ||||||
// that will be used to construct the ImplicitConceptSpecializationDecl | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's fake about it? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It isn't being placed into the AST, the sole reason for its existence is to allow a path to construct a TemplateArgument, and that TemplateArgument will actually be placed into the AST. The fake TemplateTypeParmDecl is otherwise unused and discarded. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This sounds wrong... Like, completely wrong. You're absolutely adding it to the AST, that's what happens when you create a declaration and put it into a declaration context. This also seems like we're putting this declaration into the wrong declaration context. I don't see any of your tests verifying the AST shape of the concept declaration. Can you add tests for that so that we can see what the concept's AST looks like? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On further investigation, yes I believe it is being placed into the AST. I didn't realize that setting the DeclContext correlated with AST placement. However, comparing the generated AST with similar C++ code, I do think the declaration context for this template type parm decl is correct. (That is, the context is the ClassTemplateDecl, and it shows up directly indented under the ClassTemplateDecl in the AST. I've added tests for the concept declaration AST. |
||||||
TemplateTypeParmDecl *T = TemplateTypeParmDecl::Create( | ||||||
Context, // AST context | ||||||
Context.getTranslationUnitDecl(), // DeclContext | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is where the DeclContext is wrong that I referenced in https://github.com/llvm/llvm-project/pull/112600/files/6edf031b5e736b38cf3551ccc872351f9c8a07ca#r1835111011
Suggested change
|
||||||
SourceLocation(), SourceLocation(), | ||||||
/*depth=*/0, // Depth in the template parameter list | ||||||
/*position=*/0, // Position in the template parameter list | ||||||
/*id=*/nullptr, // Identifier for 'T' | ||||||
/*Typename=*/true, // Indicates this is a 'typename' or 'class' | ||||||
/*ParameterPack=*/false, // Not a parameter pack | ||||||
/*HasTypeConstraint=*/false // Has no type constraint | ||||||
); | ||||||
|
||||||
T->setDeclContext(DC); | ||||||
T->setReferenced(); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do you need to set this explicitly? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Setting the decl context is necessary because it puts the decl into the right indentation in the AST dump. Otherwise, I believe the decl would be placed at the same scope as one indentation below the translation unit decl, which is not where the decl belongs. |
||||||
|
||||||
QualType ConceptTType = Context.getTypeDeclType(ConceptTTPD); | ||||||
|
||||||
// this is the 2nd template argument node in the AST above | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not entirely sure what "the AST above" refers to. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, this was when I had the entire AST inside a comment previously, haven't updated it, will fix! |
||||||
TemplateArgument ConceptTA = TemplateArgument(ConceptTType); | ||||||
|
||||||
QualType CSETType = Context.getTypeDeclType(T); | ||||||
|
||||||
// this is the 1st template argument node in the AST above | ||||||
TemplateArgument CSETA = TemplateArgument(CSETType); | ||||||
|
||||||
ImplicitConceptSpecializationDecl *ImplicitCSEDecl = | ||||||
ImplicitConceptSpecializationDecl::Create( | ||||||
Context, Builder.Record->getDeclContext(), Loc, {CSETA}); | ||||||
|
||||||
// Constraint satisfaction is used to construct the | ||||||
// ConceptSpecailizationExpr, and represents the 2nd Template Argument, | ||||||
// located at the bottom of the sample AST above. | ||||||
const ConstraintSatisfaction CS(CD, {ConceptTA}); | ||||||
TemplateArgumentLoc TAL = S.getTrivialTemplateArgumentLoc( | ||||||
ConceptTA, QualType(), SourceLocation()); | ||||||
|
||||||
TALI.addArgument(TAL); | ||||||
const ASTTemplateArgumentListInfo *ATALI = | ||||||
ASTTemplateArgumentListInfo::Create(Context, TALI); | ||||||
|
||||||
// In the concept reference, ATALI is what adds the extra | ||||||
// TemplateArgument node underneath CSE | ||||||
ConceptReference *CR = | ||||||
ConceptReference::Create(Context, NNSLoc, Loc, DNI, CD, CD, ATALI); | ||||||
|
||||||
ConceptSpecializationExpr *CSE = | ||||||
ConceptSpecializationExpr::Create(Context, CR, ImplicitCSEDecl, &CS); | ||||||
|
||||||
return CSE; | ||||||
} | ||||||
|
||||||
BuiltinTypeDeclBuilder &finalizeTemplateArgs(ConceptDecl *CD = nullptr) { | ||||||
if (Params.empty()) | ||||||
return Builder; | ||||||
ConceptSpecializationExpr *CSE = | ||||||
CD ? constructConceptSpecializationExpr(S, CD) : nullptr; | ||||||
|
||||||
auto *ParamList = TemplateParameterList::Create(S.Context, SourceLocation(), | ||||||
SourceLocation(), Params, | ||||||
SourceLocation(), nullptr); | ||||||
SourceLocation(), CSE); | ||||||
Builder.Template = ClassTemplateDecl::Create( | ||||||
S.Context, Builder.Record->getDeclContext(), SourceLocation(), | ||||||
DeclarationName(Builder.Record->getIdentifier()), ParamList, | ||||||
Builder.Record); | ||||||
|
||||||
Builder.Record->setDescribedClassTemplate(Builder.Template); | ||||||
Builder.Template->setImplicit(true); | ||||||
Builder.Template->setLexicalDeclContext(Builder.Record->getDeclContext()); | ||||||
|
||||||
// NOTE: setPreviousDecl before addDecl so new decl replace old decl when | ||||||
// make visible. | ||||||
Builder.Template->setPreviousDecl(Builder.PrevTemplate); | ||||||
|
@@ -366,13 +464,13 @@ BuiltinTypeDeclBuilder::addTemplateArgumentList(Sema &S) { | |||||
return TemplateParameterListBuilder(S, *this); | ||||||
} | ||||||
|
||||||
BuiltinTypeDeclBuilder & | ||||||
BuiltinTypeDeclBuilder::addSimpleTemplateParams(Sema &S, | ||||||
ArrayRef<StringRef> Names) { | ||||||
BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addSimpleTemplateParams( | ||||||
Sema &S, ArrayRef<StringRef> Names, ConceptDecl *CD = nullptr) { | ||||||
TemplateParameterListBuilder Builder = this->addTemplateArgumentList(S); | ||||||
for (StringRef Name : Names) | ||||||
Builder.addTypeParameter(Name); | ||||||
return Builder.finalizeTemplateArgs(); | ||||||
|
||||||
return Builder.finalizeTemplateArgs(CD); | ||||||
} | ||||||
|
||||||
HLSLExternalSemaSource::~HLSLExternalSemaSource() {} | ||||||
|
@@ -483,10 +581,105 @@ static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S, | |||||
.addDefaultHandleConstructor(S, RC); | ||||||
} | ||||||
|
||||||
BinaryOperator *constructSizeOfLEQ16Expr(ASTContext &Context, | ||||||
SourceLocation NameLoc, | ||||||
TemplateTypeParmDecl *T) { | ||||||
// Obtain the QualType for 'unsigned long' | ||||||
QualType UnsignedLongType = Context.UnsignedLongTy; | ||||||
|
||||||
// Create a QualType that points to this TemplateTypeParmDecl | ||||||
QualType TType = Context.getTypeDeclType(T); | ||||||
|
||||||
// Create a TypeSourceInfo for the template type parameter 'T' | ||||||
TypeSourceInfo *TTypeSourceInfo = | ||||||
Context.getTrivialTypeSourceInfo(TType, NameLoc); | ||||||
|
||||||
UnaryExprOrTypeTraitExpr *sizeOfExpr = new (Context) UnaryExprOrTypeTraitExpr( | ||||||
UETT_SizeOf, TTypeSourceInfo, UnsignedLongType, NameLoc, NameLoc); | ||||||
|
||||||
// Create an IntegerLiteral for the value '16' with size type | ||||||
QualType SizeType = Context.getSizeType(); | ||||||
llvm::APInt SizeValue = llvm::APInt(Context.getTypeSize(SizeType), 16); | ||||||
IntegerLiteral *SizeLiteral = | ||||||
new (Context) IntegerLiteral(Context, SizeValue, SizeType, NameLoc); | ||||||
|
||||||
QualType BoolTy = Context.BoolTy; | ||||||
|
||||||
BinaryOperator *binaryOperator = | ||||||
BinaryOperator::Create(Context, sizeOfExpr, // Left-hand side expression | ||||||
SizeLiteral, // Right-hand side expression | ||||||
BO_LE, // Binary operator kind (<=) | ||||||
BoolTy, // Result type (bool) | ||||||
VK_LValue, // Value kind | ||||||
OK_Ordinary, // Object kind | ||||||
NameLoc, // Source location of operator | ||||||
FPOptionsOverride()); | ||||||
|
||||||
return binaryOperator; | ||||||
} | ||||||
|
||||||
Expr *constructTypedBufferConstraintExpr(Sema &S, SourceLocation NameLoc, | ||||||
TemplateTypeParmDecl *T) { | ||||||
ASTContext &Context = S.getASTContext(); | ||||||
|
||||||
// first get the "sizeof(T) <= 16" expression, as a binary operator | ||||||
BinaryOperator *SizeOfLEQ16 = constructSizeOfLEQ16Expr(Context, NameLoc, T); | ||||||
// TODO: add the 'builtin_hlsl_is_typed_resource_element_compatible' builtin | ||||||
// and return a binary operator that evaluates the builtin on the given | ||||||
// template type parameter 'T'. | ||||||
// Defined in issue https://github.com/llvm/llvm-project/issues/113223 | ||||||
return SizeOfLEQ16; | ||||||
} | ||||||
|
||||||
ConceptDecl *constructTypedBufferConceptDecl(Sema &S, NamespaceDecl *NSD) { | ||||||
ASTContext &Context = S.getASTContext(); | ||||||
DeclContext *DC = NSD->getDeclContext(); | ||||||
SourceLocation DeclLoc = SourceLocation(); | ||||||
|
||||||
IdentifierInfo &IsTypedResourceElementCompatibleII = | ||||||
Context.Idents.get("__is_typed_resource_element_compatible"); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit - move this just before DeclName declaration, or better yet use |
||||||
IdentifierInfo &ElementTypeII = Context.Idents.get("element_type"); | ||||||
TemplateTypeParmDecl *T = TemplateTypeParmDecl::Create( | ||||||
Context, Context.getTranslationUnitDecl(), DeclLoc, DeclLoc, | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pretty sure this is also wrong here:
Suggested change
|
||||||
/*depth=*/0, | ||||||
/*position=*/0, | ||||||
/*id=*/&ElementTypeII, | ||||||
/*Typename=*/true, | ||||||
/*ParameterPack=*/false); | ||||||
|
||||||
T->setDeclContext(DC); | ||||||
T->setReferenced(); | ||||||
|
||||||
// Create and Attach Template Parameter List to ConceptDecl | ||||||
TemplateParameterList *ConceptParams = TemplateParameterList::Create( | ||||||
Context, DeclLoc, DeclLoc, {T}, DeclLoc, nullptr); | ||||||
|
||||||
DeclarationName DeclName = | ||||||
DeclarationName(&IsTypedResourceElementCompatibleII); | ||||||
Expr *ConstraintExpr = constructTypedBufferConstraintExpr(S, DeclLoc, T); | ||||||
|
||||||
// Create a ConceptDecl | ||||||
ConceptDecl *CD = | ||||||
ConceptDecl::Create(Context, Context.getTranslationUnitDecl(), DeclLoc, | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
DeclName, ConceptParams, ConstraintExpr); | ||||||
|
||||||
// Attach the template parameter list to the ConceptDecl | ||||||
CD->setTemplateParameters(ConceptParams); | ||||||
|
||||||
// Add the concept declaration to the Translation Unit Decl | ||||||
Context.getTranslationUnitDecl()->addDecl(CD); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should be putting the concepts under the
Suggested change
|
||||||
|
||||||
return CD; | ||||||
} | ||||||
|
||||||
void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { | ||||||
CXXRecordDecl *Decl; | ||||||
ConceptDecl *TypeBufferConcept = | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Typo
Suggested change
|
||||||
constructTypedBufferConceptDecl(*SemaPtr, HLSLNamespace); | ||||||
|
||||||
Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWBuffer") | ||||||
.addSimpleTemplateParams(*SemaPtr, {"element_type"}) | ||||||
.addSimpleTemplateParams(*SemaPtr, {"element_type"}, | ||||||
TypeBufferConcept) | ||||||
.Record; | ||||||
|
||||||
onCompletion(Decl, [this](CXXRecordDecl *Decl) { | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This still uses the old name.