-
Notifications
You must be signed in to change notification settings - Fork 14.9k
[OpenACC][NFCI] Split up the init and decl from OpenACC recipes #156938
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
Conversation
Expressions/references with 'bounds' are going to need to do initialization significantly differently, so we need to have the initializer and the declaration 'separate' in the future. This patch splits the AST node into two, and normalizes them a bit. Additionally, since this required significant work on the recipe generation, this patch also does a bit of a refactor to improve readability and future expansion, now that we have a good understanding of how these are going to look.
@llvm/pr-subscribers-clang-modules @llvm/pr-subscribers-clang Author: Erich Keane (erichkeane) ChangesExpressions/references with 'bounds' are going to need to do initialization significantly differently, so we need to have the initializer and the declaration 'separate' in the future. This patch splits the AST node into two, and normalizes them a bit. Additionally, since this required significant work on the recipe generation, this patch also does a bit of a refactor to improve readability and future expansion, now that we have a good understanding of how these are going to look. Patch is 41.86 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/156938.diff 11 Files Affected:
diff --git a/clang/include/clang/AST/OpenACCClause.h b/clang/include/clang/AST/OpenACCClause.h
index 2f4aba1cdcd90..081244fe0efb6 100644
--- a/clang/include/clang/AST/OpenACCClause.h
+++ b/clang/include/clang/AST/OpenACCClause.h
@@ -835,19 +835,40 @@ class OpenACCClauseWithVarList : public OpenACCClauseWithExprs {
ArrayRef<Expr *> getVarList() const { return getExprs(); }
};
+// Represents all the data needed for recipe generation. The declaration and
+// init are stored separately, because in the case of subscripts, we do the
+// alloca at the level of the base, and the init at the element level.
+struct OpenACCPrivateRecipe {
+ VarDecl *AllocaDecl;
+ Expr *InitExpr;
+
+ OpenACCPrivateRecipe(VarDecl *A, Expr *I) : AllocaDecl(A), InitExpr(I) {
+ assert(!AllocaDecl || AllocaDecl->getInit() == nullptr);
+ }
+
+ bool isSet() const { return AllocaDecl; }
+
+ static OpenACCPrivateRecipe Empty() {
+ return OpenACCPrivateRecipe(nullptr, nullptr);
+ }
+};
+
class OpenACCPrivateClause final
: public OpenACCClauseWithVarList,
- private llvm::TrailingObjects<OpenACCPrivateClause, Expr *, VarDecl *> {
+ private llvm::TrailingObjects<OpenACCPrivateClause, Expr *,
+ OpenACCPrivateRecipe> {
friend TrailingObjects;
OpenACCPrivateClause(SourceLocation BeginLoc, SourceLocation LParenLoc,
ArrayRef<Expr *> VarList,
- ArrayRef<VarDecl *> InitRecipes, SourceLocation EndLoc)
+ ArrayRef<OpenACCPrivateRecipe> InitRecipes,
+ SourceLocation EndLoc)
: OpenACCClauseWithVarList(OpenACCClauseKind::Private, BeginLoc,
LParenLoc, EndLoc) {
assert(VarList.size() == InitRecipes.size());
setExprs(getTrailingObjects<Expr *>(VarList.size()), VarList);
- llvm::uninitialized_copy(InitRecipes, getTrailingObjects<VarDecl *>());
+ llvm::uninitialized_copy(InitRecipes,
+ getTrailingObjects<OpenACCPrivateRecipe>());
}
public:
@@ -856,19 +877,19 @@ class OpenACCPrivateClause final
}
// Gets a list of 'made up' `VarDecl` objects that can be used by codegen to
// ensure that we properly initialize each of these variables.
- ArrayRef<VarDecl *> getInitRecipes() {
- return ArrayRef<VarDecl *>{getTrailingObjects<VarDecl *>(),
- getExprs().size()};
+ ArrayRef<OpenACCPrivateRecipe> getInitRecipes() {
+ return ArrayRef<OpenACCPrivateRecipe>{
+ getTrailingObjects<OpenACCPrivateRecipe>(), getExprs().size()};
}
- ArrayRef<VarDecl *> getInitRecipes() const {
- return ArrayRef<VarDecl *>{getTrailingObjects<VarDecl *>(),
- getExprs().size()};
+ ArrayRef<OpenACCPrivateRecipe> getInitRecipes() const {
+ return ArrayRef<OpenACCPrivateRecipe>{
+ getTrailingObjects<OpenACCPrivateRecipe>(), getExprs().size()};
}
static OpenACCPrivateClause *
Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc,
- ArrayRef<Expr *> VarList, ArrayRef<VarDecl *> InitRecipes,
+ ArrayRef<Expr *> VarList, ArrayRef<OpenACCPrivateRecipe> InitRecipes,
SourceLocation EndLoc);
size_t numTrailingObjects(OverloadToken<Expr *>) const {
@@ -879,11 +900,20 @@ class OpenACCPrivateClause final
// A 'pair' to stand in for the recipe. RecipeDecl is the main declaration, and
// InitFromTemporary is the 'temp' declaration we put in to be 'copied from'.
struct OpenACCFirstPrivateRecipe {
- VarDecl *RecipeDecl, *InitFromTemporary;
- OpenACCFirstPrivateRecipe(VarDecl *R, VarDecl *T)
- : RecipeDecl(R), InitFromTemporary(T) {}
- OpenACCFirstPrivateRecipe(std::pair<VarDecl *, VarDecl *> p)
- : RecipeDecl(p.first), InitFromTemporary(p.second) {}
+ VarDecl *AllocaDecl;
+ Expr *InitExpr;
+ VarDecl *InitFromTemporary;
+ OpenACCFirstPrivateRecipe(VarDecl *A, Expr *I, VarDecl *T)
+ : AllocaDecl(A), InitExpr(I), InitFromTemporary(T) {
+ assert(!AllocaDecl || AllocaDecl->getInit() == nullptr);
+ assert(!InitFromTemporary || InitFromTemporary->getInit() == nullptr);
+ }
+
+ bool isSet() const { return AllocaDecl; }
+
+ static OpenACCFirstPrivateRecipe Empty() {
+ return OpenACCFirstPrivateRecipe(nullptr, nullptr, nullptr);
+ }
};
class OpenACCFirstPrivateClause final
@@ -1253,8 +1283,18 @@ class OpenACCCreateClause final
// A structure to stand in for the recipe on a reduction. RecipeDecl is the
// 'main' declaration used for initializaiton, which is fixed.
struct OpenACCReductionRecipe {
- VarDecl *RecipeDecl;
+ VarDecl *AllocaDecl;
+ Expr *InitExpr;
// TODO: OpenACC: this should eventually have the operations here too.
+
+ OpenACCReductionRecipe(VarDecl *A, Expr *I) : AllocaDecl(A), InitExpr(I) {
+ assert(!AllocaDecl || AllocaDecl->getInit() == nullptr);
+ }
+
+ bool isSet() const { return AllocaDecl; }
+ static OpenACCReductionRecipe Empty() {
+ return OpenACCReductionRecipe(nullptr, nullptr);
+ }
};
class OpenACCReductionClause final
diff --git a/clang/include/clang/Sema/SemaOpenACC.h b/clang/include/clang/Sema/SemaOpenACC.h
index 42e86582c3b06..09fdf75fbbd09 100644
--- a/clang/include/clang/Sema/SemaOpenACC.h
+++ b/clang/include/clang/Sema/SemaOpenACC.h
@@ -15,6 +15,7 @@
#define LLVM_CLANG_SEMA_SEMAOPENACC_H
#include "clang/AST/DeclGroup.h"
+#include "clang/AST/OpenACCClause.h"
#include "clang/AST/StmtOpenACC.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/OpenACCKinds.h"
@@ -237,21 +238,11 @@ class SemaOpenACC : public SemaBase {
SourceLocation ClauseLoc,
ArrayRef<const OpenACCClause *> Clauses);
- // Creates a VarDecl with a proper default init for the purposes of a
- // `private`/'firstprivate'/'reduction' clause, so it can be used to generate
- // a recipe later.
- // The first entry is the recipe itself, the second is any required
- // 'temporary' created for the init (in the case of a copy), such as with
- // firstprivate.
- std::pair<VarDecl *, VarDecl *> CreateInitRecipe(OpenACCClauseKind CK,
- const Expr *VarExpr) {
- assert(CK != OpenACCClauseKind::Reduction);
- return CreateInitRecipe(CK, OpenACCReductionOperator::Invalid, VarExpr);
- }
- std::pair<VarDecl *, VarDecl *>
- CreateInitRecipe(OpenACCClauseKind CK,
- OpenACCReductionOperator ReductionOperator,
- const Expr *VarExpr);
+ OpenACCPrivateRecipe CreatePrivateInitRecipe(const Expr *VarExpr);
+ OpenACCFirstPrivateRecipe CreateFirstPrivateInitRecipe(const Expr *VarExpr);
+ OpenACCReductionRecipe
+ CreateReductionInitRecipe(OpenACCReductionOperator ReductionOperator,
+ const Expr *VarExpr);
public:
ComputeConstructInfo &getActiveComputeConstructInfo() {
diff --git a/clang/lib/AST/OpenACCClause.cpp b/clang/lib/AST/OpenACCClause.cpp
index 9a9ede467331e..6c4bc7c274eaa 100644
--- a/clang/lib/AST/OpenACCClause.cpp
+++ b/clang/lib/AST/OpenACCClause.cpp
@@ -317,11 +317,11 @@ OpenACCTileClause *OpenACCTileClause::Create(const ASTContext &C,
OpenACCPrivateClause *
OpenACCPrivateClause::Create(const ASTContext &C, SourceLocation BeginLoc,
SourceLocation LParenLoc, ArrayRef<Expr *> VarList,
- ArrayRef<VarDecl *> InitRecipes,
+ ArrayRef<OpenACCPrivateRecipe> InitRecipes,
SourceLocation EndLoc) {
assert(VarList.size() == InitRecipes.size());
- void *Mem =
- C.Allocate(OpenACCPrivateClause::totalSizeToAlloc<Expr *, VarDecl *>(
+ void *Mem = C.Allocate(
+ OpenACCPrivateClause::totalSizeToAlloc<Expr *, OpenACCPrivateRecipe>(
VarList.size(), InitRecipes.size()));
return new (Mem)
OpenACCPrivateClause(BeginLoc, LParenLoc, VarList, InitRecipes, EndLoc);
diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index 2035fa7635f2a..1bc21062203cb 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -2636,8 +2636,11 @@ void OpenACCClauseProfiler::VisitPrivateClause(
const OpenACCPrivateClause &Clause) {
VisitClauseWithVarList(Clause);
- for (auto *VD : Clause.getInitRecipes())
- Profiler.VisitDecl(VD);
+ for (auto &Recipe : Clause.getInitRecipes()) {
+ Profiler.VisitDecl(Recipe.AllocaDecl);
+ if (Recipe.InitExpr)
+ Profiler.VisitExpr(Recipe.InitExpr);
+ }
}
void OpenACCClauseProfiler::VisitFirstPrivateClause(
@@ -2645,7 +2648,9 @@ void OpenACCClauseProfiler::VisitFirstPrivateClause(
VisitClauseWithVarList(Clause);
for (auto &Recipe : Clause.getInitRecipes()) {
- Profiler.VisitDecl(Recipe.RecipeDecl);
+ Profiler.VisitDecl(Recipe.AllocaDecl);
+ if (Recipe.InitExpr)
+ Profiler.VisitExpr(Recipe.InitExpr);
Profiler.VisitDecl(Recipe.InitFromTemporary);
}
}
@@ -2750,11 +2755,13 @@ void OpenACCClauseProfiler::VisitReductionClause(
VisitClauseWithVarList(Clause);
for (auto &Recipe : Clause.getRecipes()) {
- Profiler.VisitDecl(Recipe.RecipeDecl);
+ Profiler.VisitDecl(Recipe.AllocaDecl);
+ if (Recipe.InitExpr)
+ Profiler.VisitExpr(Recipe.InitExpr);
// TODO: OpenACC: Make sure we remember to update this when we figure out
// what we're adding for the operation recipe, in the meantime, a static
// assert will make sure we don't add something.
- static_assert(sizeof(OpenACCReductionRecipe) == sizeof(int *));
+ static_assert(sizeof(OpenACCReductionRecipe) == 2 * sizeof(int *));
}
}
diff --git a/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp b/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp
index 41834da8a86c3..0022befa3b562 100644
--- a/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp
@@ -1280,10 +1280,16 @@ class OpenACCClauseCIREmitter final
{
mlir::OpBuilder::InsertionGuard guardCase(builder);
+ // TODO: OpenACC: At the moment this is a bit of a hacky way of doing
+ // this, and won't work when we get to bounds/etc. Do this for now to
+ // limit the scope of this refactor.
+ VarDecl *allocaDecl = varRecipe.AllocaDecl;
+ allocaDecl->setInit(varRecipe.InitExpr);
+ allocaDecl->setInitStyle(VarDecl::CallInit);
+
auto recipe = getOrCreateRecipe<mlir::acc::PrivateRecipeOp>(
- cgf.getContext(), varExpr, varRecipe, /*temporary=*/nullptr,
+ cgf.getContext(), varExpr, allocaDecl, /*temporary=*/nullptr,
OpenACCReductionOperator::Invalid,
-
Decl::castToDeclContext(cgf.curFuncDecl), opInfo.baseType,
privateOp.getResult());
// TODO: OpenACC: The dialect is going to change in the near future to
@@ -1316,8 +1322,15 @@ class OpenACCClauseCIREmitter final
{
mlir::OpBuilder::InsertionGuard guardCase(builder);
+ // TODO: OpenACC: At the moment this is a bit of a hacky way of doing
+ // this, and won't work when we get to bounds/etc. Do this for now to
+ // limit the scope of this refactor.
+ VarDecl *allocaDecl = varRecipe.AllocaDecl;
+ allocaDecl->setInit(varRecipe.InitExpr);
+ allocaDecl->setInitStyle(VarDecl::CallInit);
+
auto recipe = getOrCreateRecipe<mlir::acc::FirstprivateRecipeOp>(
- cgf.getContext(), varExpr, varRecipe.RecipeDecl,
+ cgf.getContext(), varExpr, allocaDecl,
varRecipe.InitFromTemporary, OpenACCReductionOperator::Invalid,
Decl::castToDeclContext(cgf.curFuncDecl), opInfo.baseType,
firstPrivateOp.getResult());
@@ -1353,9 +1366,15 @@ class OpenACCClauseCIREmitter final
{
mlir::OpBuilder::InsertionGuard guardCase(builder);
+ // TODO: OpenACC: At the moment this is a bit of a hacky way of doing
+ // this, and won't work when we get to bounds/etc. Do this for now to
+ // limit the scope of this refactor.
+ VarDecl *allocaDecl = varRecipe.AllocaDecl;
+ allocaDecl->setInit(varRecipe.InitExpr);
+ allocaDecl->setInitStyle(VarDecl::CallInit);
auto recipe = getOrCreateRecipe<mlir::acc::ReductionRecipeOp>(
- cgf.getContext(), varExpr, varRecipe.RecipeDecl,
+ cgf.getContext(), varExpr, allocaDecl,
/*temporary=*/nullptr, clause.getReductionOp(),
Decl::castToDeclContext(cgf.curFuncDecl), opInfo.baseType,
reductionOp.getResult());
diff --git a/clang/lib/Sema/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp
index 5082e2c272ebd..fbd8022cd68ba 100644
--- a/clang/lib/Sema/SemaOpenACC.cpp
+++ b/clang/lib/Sema/SemaOpenACC.cpp
@@ -2590,9 +2590,11 @@ SemaOpenACC::ActOnOpenACCAsteriskSizeExpr(SourceLocation AsteriskLoc) {
}
namespace {
-enum class InitKind { Zero, One, AllOnes, Least, Largest };
+enum class InitKind { Invalid, Zero, One, AllOnes, Least, Largest };
llvm::APFloat getInitFloatValue(ASTContext &Context, InitKind IK, QualType Ty) {
switch (IK) {
+ case InitKind::Invalid:
+ llvm_unreachable("invalid init kind");
case InitKind::Zero:
return llvm::APFloat::getZero(Context.getFloatTypeSemantics(Ty));
case InitKind::One:
@@ -2604,13 +2606,14 @@ llvm::APFloat getInitFloatValue(ASTContext &Context, InitKind IK, QualType Ty) {
/*Negative=*/true);
case InitKind::Largest:
return llvm::APFloat::getLargest(Context.getFloatTypeSemantics(Ty));
- break;
}
llvm_unreachable("unknown init kind");
}
llvm::APInt getInitIntValue(ASTContext &Context, InitKind IK, QualType Ty) {
switch (IK) {
+ case InitKind::Invalid:
+ llvm_unreachable("invalid init kind");
case InitKind::Zero:
return llvm::APInt(Context.getIntWidth(Ty), 0);
case InitKind::One:
@@ -2625,7 +2628,6 @@ llvm::APInt getInitIntValue(ASTContext &Context, InitKind IK, QualType Ty) {
if (Ty->isSignedIntegerOrEnumerationType())
return llvm::APInt::getSignedMaxValue(Context.getIntWidth(Ty));
return llvm::APInt::getMaxValue(Context.getIntWidth(Ty));
- break;
}
llvm_unreachable("unknown init kind");
}
@@ -2635,6 +2637,16 @@ llvm::APInt getInitIntValue(ASTContext &Context, InitKind IK, QualType Ty) {
Expr *GenerateReductionInitRecipeExpr(ASTContext &Context,
SourceRange ExprRange, QualType Ty,
InitKind IK) {
+ if (IK == InitKind::Invalid)
+ return nullptr;
+
+ if (IK == InitKind::Zero) {
+ Expr *InitExpr = new (Context)
+ InitListExpr(Context, ExprRange.getBegin(), {}, ExprRange.getEnd());
+ InitExpr->setType(Context.VoidTy);
+ return InitExpr;
+ }
+
Ty = Ty.getCanonicalType();
llvm::SmallVector<Expr *> Exprs;
@@ -2712,219 +2724,202 @@ Expr *GenerateReductionInitRecipeExpr(ASTContext &Context,
return InitExpr;
}
-} // namespace
-
-std::pair<VarDecl *, VarDecl *>
-SemaOpenACC::CreateInitRecipe(OpenACCClauseKind CK,
- OpenACCReductionOperator ReductionOperator,
- const Expr *VarExpr) {
- // Strip off any array subscripts/array section exprs to get to the type of
- // the variable.
+const Expr *StripOffBounds(const Expr *VarExpr) {
while (isa_and_present<ArraySectionExpr, ArraySubscriptExpr>(VarExpr)) {
if (const auto *AS = dyn_cast<ArraySectionExpr>(VarExpr))
VarExpr = AS->getBase()->IgnoreParenImpCasts();
else if (const auto *Sub = dyn_cast<ArraySubscriptExpr>(VarExpr))
VarExpr = Sub->getBase()->IgnoreParenImpCasts();
}
+ return VarExpr;
+}
+
+VarDecl *CreateAllocaDecl(ASTContext &Ctx, DeclContext *DC,
+ SourceLocation BeginLoc, IdentifierInfo *VarName,
+ QualType VarTy) {
+ return VarDecl::Create(Ctx, DC, BeginLoc, BeginLoc, VarName, VarTy,
+ Ctx.getTrivialTypeSourceInfo(VarTy), SC_Auto);
+}
+
+ExprResult FinishValueInit(Sema &S, InitializedEntity &Entity,
+ SourceLocation Loc, QualType VarTy, Expr *InitExpr) {
+ if (!InitExpr)
+ return ExprEmpty();
+
+ InitializationKind Kind =
+ InitializationKind::CreateForInit(Loc, /*DirectInit=*/true, InitExpr);
+ InitializationSequence InitSeq(S, Entity, Kind, InitExpr,
+ /*TopLevelOfInitList=*/false,
+ /*TreatUnavailableAsInvalid=*/false);
+
+ return InitSeq.Perform(S, Entity, Kind, InitExpr, &VarTy);
+}
+
+} // namespace
+
+OpenACCPrivateRecipe SemaOpenACC::CreatePrivateInitRecipe(const Expr *VarExpr) {
+ VarExpr = StripOffBounds(VarExpr);
- // If for some reason the expression is invalid, or this is dependent, just
- // fill in with nullptr. We'll count on TreeTransform to make this if
- // necessary.
if (!VarExpr || VarExpr->getType()->isDependentType())
- return {nullptr, nullptr};
+ return OpenACCPrivateRecipe::Empty();
QualType VarTy =
VarExpr->getType().getNonReferenceType().getUnqualifiedType();
- IdentifierInfo *VarName = [&]() {
- switch (CK) {
- case OpenACCClauseKind::Private:
- return &getASTContext().Idents.get("openacc.private.init");
- case OpenACCClauseKind::FirstPrivate:
- return &getASTContext().Idents.get("openacc.firstprivate.init");
- case OpenACCClauseKind::Reduction:
- return &getASTContext().Idents.get("openacc.reduction.init");
- default:
- llvm_unreachable("Unknown clause kind?");
- }
- }();
+ // TODO: OpenACC: for arrays/bounds versions, we're going to have to do a
+ // different initializer, but for now we can go ahead with this.
- VarDecl *Recipe = VarDecl::Create(
+ VarDecl *AllocaDecl = CreateAllocaDecl(
getASTContext(), SemaRef.getCurContext(), VarExpr->getBeginLoc(),
- VarExpr->getBeginLoc(), VarName, VarTy,
- getASTContext().getTrivialTypeSourceInfo(VarTy), SC_Auto);
-
- ExprResult Init;
- VarDecl *Temporary = nullptr;
- {
- // Trap errors so we don't get weird ones here. If we can't init, we'll just
- // swallow the errors.
- Sema::TentativeAnalysisScope Trap{SemaRef};
- InitializedEntity Entity = InitializedEntity::InitializeVariable(Recipe);
-
- auto FinishValueInit = [&](Expr *InitExpr) {
- if (InitExpr) {
- InitializationKind Kind = InitializationKind::CreateForInit(
- Recipe->getLocation(), /*DirectInit=*/true, InitExpr);
- InitializationSequence InitSeq(SemaRef.SemaRef, Entity, Kind, InitExpr,
- /*TopLevelOfInitList=*/false,
- /*TreatUnavailableAsInvalid=*/false);
- return InitSeq.Perform(SemaRef.SemaRef, Entity, Kind, InitExpr, &VarTy);
- }
- return ExprEmpty();
- };
+ &getASTContext().Idents.get("openacc.private.init"), VarTy);
- if (CK == OpenACCClauseKind::Private) {
- InitializationKind Kind =
- InitializationKind::CreateDefault(Recipe->getLocation());
-
- InitializationSequence InitSeq(SemaRef.SemaRef, Entity, Kind, {});
- Init = InitSeq.Perform(SemaRef.SemaRef, Entity, Kind, {});
- } else if (CK == OpenACCClauseKind::FirstPrivate) {
- // Create a VarDecl to be the 'copied-from' for the copy section of the
- // recipe. This allows us to make the association so that we can use the
- // standard 'generation' ability of the init.
- Temporary = VarDecl::Create(
- getASTContext(), SemaRef.getCurContext(), VarExpr->getBeginLoc(),
- VarExpr->getBeginLoc(), &getASTContext().Idents.get("openacc.temp"),
- VarTy, getASTContext().getTrivialTypeSourceInfo(VarTy), SC_Auto);
- auto *TemporaryDRE = DeclRefExpr::Create(
- getASTContext(), NestedNameSpecifierLoc{}, SourceLocation{},
- Temporary,
- /*ReferstoEnclosingVariableOrCapture=*/false,
- DeclarationNameInfo{DeclarationName{Temporary->getDeclName()},
- VarExpr->getBeginLoc()},
- VarTy, clang::VK_LValue, Temporary, nullptr, NOUR_None);
-
- Expr *InitExpr = nullptr;
-
- if (const auto *ArrTy = getASTContext().getAsConstantArrayType(VarTy)) {
- // Arrays need to have each individua...
[truncated]
|
@llvm/pr-subscribers-clangir Author: Erich Keane (erichkeane) ChangesExpressions/references with 'bounds' are going to need to do initialization significantly differently, so we need to have the initializer and the declaration 'separate' in the future. This patch splits the AST node into two, and normalizes them a bit. Additionally, since this required significant work on the recipe generation, this patch also does a bit of a refactor to improve readability and future expansion, now that we have a good understanding of how these are going to look. Patch is 41.86 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/156938.diff 11 Files Affected:
diff --git a/clang/include/clang/AST/OpenACCClause.h b/clang/include/clang/AST/OpenACCClause.h
index 2f4aba1cdcd90..081244fe0efb6 100644
--- a/clang/include/clang/AST/OpenACCClause.h
+++ b/clang/include/clang/AST/OpenACCClause.h
@@ -835,19 +835,40 @@ class OpenACCClauseWithVarList : public OpenACCClauseWithExprs {
ArrayRef<Expr *> getVarList() const { return getExprs(); }
};
+// Represents all the data needed for recipe generation. The declaration and
+// init are stored separately, because in the case of subscripts, we do the
+// alloca at the level of the base, and the init at the element level.
+struct OpenACCPrivateRecipe {
+ VarDecl *AllocaDecl;
+ Expr *InitExpr;
+
+ OpenACCPrivateRecipe(VarDecl *A, Expr *I) : AllocaDecl(A), InitExpr(I) {
+ assert(!AllocaDecl || AllocaDecl->getInit() == nullptr);
+ }
+
+ bool isSet() const { return AllocaDecl; }
+
+ static OpenACCPrivateRecipe Empty() {
+ return OpenACCPrivateRecipe(nullptr, nullptr);
+ }
+};
+
class OpenACCPrivateClause final
: public OpenACCClauseWithVarList,
- private llvm::TrailingObjects<OpenACCPrivateClause, Expr *, VarDecl *> {
+ private llvm::TrailingObjects<OpenACCPrivateClause, Expr *,
+ OpenACCPrivateRecipe> {
friend TrailingObjects;
OpenACCPrivateClause(SourceLocation BeginLoc, SourceLocation LParenLoc,
ArrayRef<Expr *> VarList,
- ArrayRef<VarDecl *> InitRecipes, SourceLocation EndLoc)
+ ArrayRef<OpenACCPrivateRecipe> InitRecipes,
+ SourceLocation EndLoc)
: OpenACCClauseWithVarList(OpenACCClauseKind::Private, BeginLoc,
LParenLoc, EndLoc) {
assert(VarList.size() == InitRecipes.size());
setExprs(getTrailingObjects<Expr *>(VarList.size()), VarList);
- llvm::uninitialized_copy(InitRecipes, getTrailingObjects<VarDecl *>());
+ llvm::uninitialized_copy(InitRecipes,
+ getTrailingObjects<OpenACCPrivateRecipe>());
}
public:
@@ -856,19 +877,19 @@ class OpenACCPrivateClause final
}
// Gets a list of 'made up' `VarDecl` objects that can be used by codegen to
// ensure that we properly initialize each of these variables.
- ArrayRef<VarDecl *> getInitRecipes() {
- return ArrayRef<VarDecl *>{getTrailingObjects<VarDecl *>(),
- getExprs().size()};
+ ArrayRef<OpenACCPrivateRecipe> getInitRecipes() {
+ return ArrayRef<OpenACCPrivateRecipe>{
+ getTrailingObjects<OpenACCPrivateRecipe>(), getExprs().size()};
}
- ArrayRef<VarDecl *> getInitRecipes() const {
- return ArrayRef<VarDecl *>{getTrailingObjects<VarDecl *>(),
- getExprs().size()};
+ ArrayRef<OpenACCPrivateRecipe> getInitRecipes() const {
+ return ArrayRef<OpenACCPrivateRecipe>{
+ getTrailingObjects<OpenACCPrivateRecipe>(), getExprs().size()};
}
static OpenACCPrivateClause *
Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc,
- ArrayRef<Expr *> VarList, ArrayRef<VarDecl *> InitRecipes,
+ ArrayRef<Expr *> VarList, ArrayRef<OpenACCPrivateRecipe> InitRecipes,
SourceLocation EndLoc);
size_t numTrailingObjects(OverloadToken<Expr *>) const {
@@ -879,11 +900,20 @@ class OpenACCPrivateClause final
// A 'pair' to stand in for the recipe. RecipeDecl is the main declaration, and
// InitFromTemporary is the 'temp' declaration we put in to be 'copied from'.
struct OpenACCFirstPrivateRecipe {
- VarDecl *RecipeDecl, *InitFromTemporary;
- OpenACCFirstPrivateRecipe(VarDecl *R, VarDecl *T)
- : RecipeDecl(R), InitFromTemporary(T) {}
- OpenACCFirstPrivateRecipe(std::pair<VarDecl *, VarDecl *> p)
- : RecipeDecl(p.first), InitFromTemporary(p.second) {}
+ VarDecl *AllocaDecl;
+ Expr *InitExpr;
+ VarDecl *InitFromTemporary;
+ OpenACCFirstPrivateRecipe(VarDecl *A, Expr *I, VarDecl *T)
+ : AllocaDecl(A), InitExpr(I), InitFromTemporary(T) {
+ assert(!AllocaDecl || AllocaDecl->getInit() == nullptr);
+ assert(!InitFromTemporary || InitFromTemporary->getInit() == nullptr);
+ }
+
+ bool isSet() const { return AllocaDecl; }
+
+ static OpenACCFirstPrivateRecipe Empty() {
+ return OpenACCFirstPrivateRecipe(nullptr, nullptr, nullptr);
+ }
};
class OpenACCFirstPrivateClause final
@@ -1253,8 +1283,18 @@ class OpenACCCreateClause final
// A structure to stand in for the recipe on a reduction. RecipeDecl is the
// 'main' declaration used for initializaiton, which is fixed.
struct OpenACCReductionRecipe {
- VarDecl *RecipeDecl;
+ VarDecl *AllocaDecl;
+ Expr *InitExpr;
// TODO: OpenACC: this should eventually have the operations here too.
+
+ OpenACCReductionRecipe(VarDecl *A, Expr *I) : AllocaDecl(A), InitExpr(I) {
+ assert(!AllocaDecl || AllocaDecl->getInit() == nullptr);
+ }
+
+ bool isSet() const { return AllocaDecl; }
+ static OpenACCReductionRecipe Empty() {
+ return OpenACCReductionRecipe(nullptr, nullptr);
+ }
};
class OpenACCReductionClause final
diff --git a/clang/include/clang/Sema/SemaOpenACC.h b/clang/include/clang/Sema/SemaOpenACC.h
index 42e86582c3b06..09fdf75fbbd09 100644
--- a/clang/include/clang/Sema/SemaOpenACC.h
+++ b/clang/include/clang/Sema/SemaOpenACC.h
@@ -15,6 +15,7 @@
#define LLVM_CLANG_SEMA_SEMAOPENACC_H
#include "clang/AST/DeclGroup.h"
+#include "clang/AST/OpenACCClause.h"
#include "clang/AST/StmtOpenACC.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/OpenACCKinds.h"
@@ -237,21 +238,11 @@ class SemaOpenACC : public SemaBase {
SourceLocation ClauseLoc,
ArrayRef<const OpenACCClause *> Clauses);
- // Creates a VarDecl with a proper default init for the purposes of a
- // `private`/'firstprivate'/'reduction' clause, so it can be used to generate
- // a recipe later.
- // The first entry is the recipe itself, the second is any required
- // 'temporary' created for the init (in the case of a copy), such as with
- // firstprivate.
- std::pair<VarDecl *, VarDecl *> CreateInitRecipe(OpenACCClauseKind CK,
- const Expr *VarExpr) {
- assert(CK != OpenACCClauseKind::Reduction);
- return CreateInitRecipe(CK, OpenACCReductionOperator::Invalid, VarExpr);
- }
- std::pair<VarDecl *, VarDecl *>
- CreateInitRecipe(OpenACCClauseKind CK,
- OpenACCReductionOperator ReductionOperator,
- const Expr *VarExpr);
+ OpenACCPrivateRecipe CreatePrivateInitRecipe(const Expr *VarExpr);
+ OpenACCFirstPrivateRecipe CreateFirstPrivateInitRecipe(const Expr *VarExpr);
+ OpenACCReductionRecipe
+ CreateReductionInitRecipe(OpenACCReductionOperator ReductionOperator,
+ const Expr *VarExpr);
public:
ComputeConstructInfo &getActiveComputeConstructInfo() {
diff --git a/clang/lib/AST/OpenACCClause.cpp b/clang/lib/AST/OpenACCClause.cpp
index 9a9ede467331e..6c4bc7c274eaa 100644
--- a/clang/lib/AST/OpenACCClause.cpp
+++ b/clang/lib/AST/OpenACCClause.cpp
@@ -317,11 +317,11 @@ OpenACCTileClause *OpenACCTileClause::Create(const ASTContext &C,
OpenACCPrivateClause *
OpenACCPrivateClause::Create(const ASTContext &C, SourceLocation BeginLoc,
SourceLocation LParenLoc, ArrayRef<Expr *> VarList,
- ArrayRef<VarDecl *> InitRecipes,
+ ArrayRef<OpenACCPrivateRecipe> InitRecipes,
SourceLocation EndLoc) {
assert(VarList.size() == InitRecipes.size());
- void *Mem =
- C.Allocate(OpenACCPrivateClause::totalSizeToAlloc<Expr *, VarDecl *>(
+ void *Mem = C.Allocate(
+ OpenACCPrivateClause::totalSizeToAlloc<Expr *, OpenACCPrivateRecipe>(
VarList.size(), InitRecipes.size()));
return new (Mem)
OpenACCPrivateClause(BeginLoc, LParenLoc, VarList, InitRecipes, EndLoc);
diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index 2035fa7635f2a..1bc21062203cb 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -2636,8 +2636,11 @@ void OpenACCClauseProfiler::VisitPrivateClause(
const OpenACCPrivateClause &Clause) {
VisitClauseWithVarList(Clause);
- for (auto *VD : Clause.getInitRecipes())
- Profiler.VisitDecl(VD);
+ for (auto &Recipe : Clause.getInitRecipes()) {
+ Profiler.VisitDecl(Recipe.AllocaDecl);
+ if (Recipe.InitExpr)
+ Profiler.VisitExpr(Recipe.InitExpr);
+ }
}
void OpenACCClauseProfiler::VisitFirstPrivateClause(
@@ -2645,7 +2648,9 @@ void OpenACCClauseProfiler::VisitFirstPrivateClause(
VisitClauseWithVarList(Clause);
for (auto &Recipe : Clause.getInitRecipes()) {
- Profiler.VisitDecl(Recipe.RecipeDecl);
+ Profiler.VisitDecl(Recipe.AllocaDecl);
+ if (Recipe.InitExpr)
+ Profiler.VisitExpr(Recipe.InitExpr);
Profiler.VisitDecl(Recipe.InitFromTemporary);
}
}
@@ -2750,11 +2755,13 @@ void OpenACCClauseProfiler::VisitReductionClause(
VisitClauseWithVarList(Clause);
for (auto &Recipe : Clause.getRecipes()) {
- Profiler.VisitDecl(Recipe.RecipeDecl);
+ Profiler.VisitDecl(Recipe.AllocaDecl);
+ if (Recipe.InitExpr)
+ Profiler.VisitExpr(Recipe.InitExpr);
// TODO: OpenACC: Make sure we remember to update this when we figure out
// what we're adding for the operation recipe, in the meantime, a static
// assert will make sure we don't add something.
- static_assert(sizeof(OpenACCReductionRecipe) == sizeof(int *));
+ static_assert(sizeof(OpenACCReductionRecipe) == 2 * sizeof(int *));
}
}
diff --git a/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp b/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp
index 41834da8a86c3..0022befa3b562 100644
--- a/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp
@@ -1280,10 +1280,16 @@ class OpenACCClauseCIREmitter final
{
mlir::OpBuilder::InsertionGuard guardCase(builder);
+ // TODO: OpenACC: At the moment this is a bit of a hacky way of doing
+ // this, and won't work when we get to bounds/etc. Do this for now to
+ // limit the scope of this refactor.
+ VarDecl *allocaDecl = varRecipe.AllocaDecl;
+ allocaDecl->setInit(varRecipe.InitExpr);
+ allocaDecl->setInitStyle(VarDecl::CallInit);
+
auto recipe = getOrCreateRecipe<mlir::acc::PrivateRecipeOp>(
- cgf.getContext(), varExpr, varRecipe, /*temporary=*/nullptr,
+ cgf.getContext(), varExpr, allocaDecl, /*temporary=*/nullptr,
OpenACCReductionOperator::Invalid,
-
Decl::castToDeclContext(cgf.curFuncDecl), opInfo.baseType,
privateOp.getResult());
// TODO: OpenACC: The dialect is going to change in the near future to
@@ -1316,8 +1322,15 @@ class OpenACCClauseCIREmitter final
{
mlir::OpBuilder::InsertionGuard guardCase(builder);
+ // TODO: OpenACC: At the moment this is a bit of a hacky way of doing
+ // this, and won't work when we get to bounds/etc. Do this for now to
+ // limit the scope of this refactor.
+ VarDecl *allocaDecl = varRecipe.AllocaDecl;
+ allocaDecl->setInit(varRecipe.InitExpr);
+ allocaDecl->setInitStyle(VarDecl::CallInit);
+
auto recipe = getOrCreateRecipe<mlir::acc::FirstprivateRecipeOp>(
- cgf.getContext(), varExpr, varRecipe.RecipeDecl,
+ cgf.getContext(), varExpr, allocaDecl,
varRecipe.InitFromTemporary, OpenACCReductionOperator::Invalid,
Decl::castToDeclContext(cgf.curFuncDecl), opInfo.baseType,
firstPrivateOp.getResult());
@@ -1353,9 +1366,15 @@ class OpenACCClauseCIREmitter final
{
mlir::OpBuilder::InsertionGuard guardCase(builder);
+ // TODO: OpenACC: At the moment this is a bit of a hacky way of doing
+ // this, and won't work when we get to bounds/etc. Do this for now to
+ // limit the scope of this refactor.
+ VarDecl *allocaDecl = varRecipe.AllocaDecl;
+ allocaDecl->setInit(varRecipe.InitExpr);
+ allocaDecl->setInitStyle(VarDecl::CallInit);
auto recipe = getOrCreateRecipe<mlir::acc::ReductionRecipeOp>(
- cgf.getContext(), varExpr, varRecipe.RecipeDecl,
+ cgf.getContext(), varExpr, allocaDecl,
/*temporary=*/nullptr, clause.getReductionOp(),
Decl::castToDeclContext(cgf.curFuncDecl), opInfo.baseType,
reductionOp.getResult());
diff --git a/clang/lib/Sema/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp
index 5082e2c272ebd..fbd8022cd68ba 100644
--- a/clang/lib/Sema/SemaOpenACC.cpp
+++ b/clang/lib/Sema/SemaOpenACC.cpp
@@ -2590,9 +2590,11 @@ SemaOpenACC::ActOnOpenACCAsteriskSizeExpr(SourceLocation AsteriskLoc) {
}
namespace {
-enum class InitKind { Zero, One, AllOnes, Least, Largest };
+enum class InitKind { Invalid, Zero, One, AllOnes, Least, Largest };
llvm::APFloat getInitFloatValue(ASTContext &Context, InitKind IK, QualType Ty) {
switch (IK) {
+ case InitKind::Invalid:
+ llvm_unreachable("invalid init kind");
case InitKind::Zero:
return llvm::APFloat::getZero(Context.getFloatTypeSemantics(Ty));
case InitKind::One:
@@ -2604,13 +2606,14 @@ llvm::APFloat getInitFloatValue(ASTContext &Context, InitKind IK, QualType Ty) {
/*Negative=*/true);
case InitKind::Largest:
return llvm::APFloat::getLargest(Context.getFloatTypeSemantics(Ty));
- break;
}
llvm_unreachable("unknown init kind");
}
llvm::APInt getInitIntValue(ASTContext &Context, InitKind IK, QualType Ty) {
switch (IK) {
+ case InitKind::Invalid:
+ llvm_unreachable("invalid init kind");
case InitKind::Zero:
return llvm::APInt(Context.getIntWidth(Ty), 0);
case InitKind::One:
@@ -2625,7 +2628,6 @@ llvm::APInt getInitIntValue(ASTContext &Context, InitKind IK, QualType Ty) {
if (Ty->isSignedIntegerOrEnumerationType())
return llvm::APInt::getSignedMaxValue(Context.getIntWidth(Ty));
return llvm::APInt::getMaxValue(Context.getIntWidth(Ty));
- break;
}
llvm_unreachable("unknown init kind");
}
@@ -2635,6 +2637,16 @@ llvm::APInt getInitIntValue(ASTContext &Context, InitKind IK, QualType Ty) {
Expr *GenerateReductionInitRecipeExpr(ASTContext &Context,
SourceRange ExprRange, QualType Ty,
InitKind IK) {
+ if (IK == InitKind::Invalid)
+ return nullptr;
+
+ if (IK == InitKind::Zero) {
+ Expr *InitExpr = new (Context)
+ InitListExpr(Context, ExprRange.getBegin(), {}, ExprRange.getEnd());
+ InitExpr->setType(Context.VoidTy);
+ return InitExpr;
+ }
+
Ty = Ty.getCanonicalType();
llvm::SmallVector<Expr *> Exprs;
@@ -2712,219 +2724,202 @@ Expr *GenerateReductionInitRecipeExpr(ASTContext &Context,
return InitExpr;
}
-} // namespace
-
-std::pair<VarDecl *, VarDecl *>
-SemaOpenACC::CreateInitRecipe(OpenACCClauseKind CK,
- OpenACCReductionOperator ReductionOperator,
- const Expr *VarExpr) {
- // Strip off any array subscripts/array section exprs to get to the type of
- // the variable.
+const Expr *StripOffBounds(const Expr *VarExpr) {
while (isa_and_present<ArraySectionExpr, ArraySubscriptExpr>(VarExpr)) {
if (const auto *AS = dyn_cast<ArraySectionExpr>(VarExpr))
VarExpr = AS->getBase()->IgnoreParenImpCasts();
else if (const auto *Sub = dyn_cast<ArraySubscriptExpr>(VarExpr))
VarExpr = Sub->getBase()->IgnoreParenImpCasts();
}
+ return VarExpr;
+}
+
+VarDecl *CreateAllocaDecl(ASTContext &Ctx, DeclContext *DC,
+ SourceLocation BeginLoc, IdentifierInfo *VarName,
+ QualType VarTy) {
+ return VarDecl::Create(Ctx, DC, BeginLoc, BeginLoc, VarName, VarTy,
+ Ctx.getTrivialTypeSourceInfo(VarTy), SC_Auto);
+}
+
+ExprResult FinishValueInit(Sema &S, InitializedEntity &Entity,
+ SourceLocation Loc, QualType VarTy, Expr *InitExpr) {
+ if (!InitExpr)
+ return ExprEmpty();
+
+ InitializationKind Kind =
+ InitializationKind::CreateForInit(Loc, /*DirectInit=*/true, InitExpr);
+ InitializationSequence InitSeq(S, Entity, Kind, InitExpr,
+ /*TopLevelOfInitList=*/false,
+ /*TreatUnavailableAsInvalid=*/false);
+
+ return InitSeq.Perform(S, Entity, Kind, InitExpr, &VarTy);
+}
+
+} // namespace
+
+OpenACCPrivateRecipe SemaOpenACC::CreatePrivateInitRecipe(const Expr *VarExpr) {
+ VarExpr = StripOffBounds(VarExpr);
- // If for some reason the expression is invalid, or this is dependent, just
- // fill in with nullptr. We'll count on TreeTransform to make this if
- // necessary.
if (!VarExpr || VarExpr->getType()->isDependentType())
- return {nullptr, nullptr};
+ return OpenACCPrivateRecipe::Empty();
QualType VarTy =
VarExpr->getType().getNonReferenceType().getUnqualifiedType();
- IdentifierInfo *VarName = [&]() {
- switch (CK) {
- case OpenACCClauseKind::Private:
- return &getASTContext().Idents.get("openacc.private.init");
- case OpenACCClauseKind::FirstPrivate:
- return &getASTContext().Idents.get("openacc.firstprivate.init");
- case OpenACCClauseKind::Reduction:
- return &getASTContext().Idents.get("openacc.reduction.init");
- default:
- llvm_unreachable("Unknown clause kind?");
- }
- }();
+ // TODO: OpenACC: for arrays/bounds versions, we're going to have to do a
+ // different initializer, but for now we can go ahead with this.
- VarDecl *Recipe = VarDecl::Create(
+ VarDecl *AllocaDecl = CreateAllocaDecl(
getASTContext(), SemaRef.getCurContext(), VarExpr->getBeginLoc(),
- VarExpr->getBeginLoc(), VarName, VarTy,
- getASTContext().getTrivialTypeSourceInfo(VarTy), SC_Auto);
-
- ExprResult Init;
- VarDecl *Temporary = nullptr;
- {
- // Trap errors so we don't get weird ones here. If we can't init, we'll just
- // swallow the errors.
- Sema::TentativeAnalysisScope Trap{SemaRef};
- InitializedEntity Entity = InitializedEntity::InitializeVariable(Recipe);
-
- auto FinishValueInit = [&](Expr *InitExpr) {
- if (InitExpr) {
- InitializationKind Kind = InitializationKind::CreateForInit(
- Recipe->getLocation(), /*DirectInit=*/true, InitExpr);
- InitializationSequence InitSeq(SemaRef.SemaRef, Entity, Kind, InitExpr,
- /*TopLevelOfInitList=*/false,
- /*TreatUnavailableAsInvalid=*/false);
- return InitSeq.Perform(SemaRef.SemaRef, Entity, Kind, InitExpr, &VarTy);
- }
- return ExprEmpty();
- };
+ &getASTContext().Idents.get("openacc.private.init"), VarTy);
- if (CK == OpenACCClauseKind::Private) {
- InitializationKind Kind =
- InitializationKind::CreateDefault(Recipe->getLocation());
-
- InitializationSequence InitSeq(SemaRef.SemaRef, Entity, Kind, {});
- Init = InitSeq.Perform(SemaRef.SemaRef, Entity, Kind, {});
- } else if (CK == OpenACCClauseKind::FirstPrivate) {
- // Create a VarDecl to be the 'copied-from' for the copy section of the
- // recipe. This allows us to make the association so that we can use the
- // standard 'generation' ability of the init.
- Temporary = VarDecl::Create(
- getASTContext(), SemaRef.getCurContext(), VarExpr->getBeginLoc(),
- VarExpr->getBeginLoc(), &getASTContext().Idents.get("openacc.temp"),
- VarTy, getASTContext().getTrivialTypeSourceInfo(VarTy), SC_Auto);
- auto *TemporaryDRE = DeclRefExpr::Create(
- getASTContext(), NestedNameSpecifierLoc{}, SourceLocation{},
- Temporary,
- /*ReferstoEnclosingVariableOrCapture=*/false,
- DeclarationNameInfo{DeclarationName{Temporary->getDeclName()},
- VarExpr->getBeginLoc()},
- VarTy, clang::VK_LValue, Temporary, nullptr, NOUR_None);
-
- Expr *InitExpr = nullptr;
-
- if (const auto *ArrTy = getASTContext().getAsConstantArrayType(VarTy)) {
- // Arrays need to have each individua...
[truncated]
|
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.
lgtm
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/163/builds/25924 Here is the relevant piece of the build log for the reference
|
Expressions/references with 'bounds' are going to need to do initialization significantly differently, so we need to have the initializer and the declaration 'separate' in the future. This patch splits the AST node into two, and normalizes them a bit.
Additionally, since this required significant work on the recipe generation, this patch also does a bit of a refactor to improve readability and future expansion, now that we have a good understanding of how these are going to look.