@@ -1277,7 +1277,7 @@ class OpenACCCreateClause final
12771277};
12781278
12791279// A structure to stand in for the recipe on a reduction. RecipeDecl is the
1280- // 'main' declaration used for initializaiton, which is fixed.
1280+ // 'main' declaration used for initializaiton, which is fixed.
12811281struct OpenACCReductionRecipe {
12821282 VarDecl *AllocaDecl;
12831283
@@ -1297,36 +1297,93 @@ struct OpenACCReductionRecipe {
12971297 // -For a struct without the operator, this will be 1 element per field, which
12981298 // should be the combiner for that element.
12991299 // -For an array of any of the above, it will be the above for the element.
1300- llvm::SmallVector<CombinerRecipe, 1 > CombinerRecipes;
1300+ // Note: These are necessarily stored in either Trailing Storage (when in the
1301+ // AST), or in a separate collection when being semantically analyzed.
1302+ llvm::ArrayRef<CombinerRecipe> CombinerRecipes;
13011303
13021304 OpenACCReductionRecipe (VarDecl *A, llvm::ArrayRef<CombinerRecipe> Combiners)
13031305 : AllocaDecl(A), CombinerRecipes(Combiners) {}
13041306
13051307 bool isSet () const { return AllocaDecl; }
1306- static OpenACCReductionRecipe Empty () {
1307- return OpenACCReductionRecipe (/* AllocaDecl=*/ nullptr , {});
1308+ };
1309+
1310+ // A version of the above that is used for semantic analysis, at a time before
1311+ // the OpenACCReductionClause node has been created. This one has storage for
1312+ // the CombinerRecipe, since Trailing storage for it doesn't exist yet.
1313+ struct OpenACCReductionRecipeWithStorage : OpenACCReductionRecipe {
1314+ private:
1315+ llvm::SmallVector<CombinerRecipe, 1 > CombinerRecipeStorage;
1316+
1317+ public:
1318+ OpenACCReductionRecipeWithStorage (VarDecl *A,
1319+ llvm::ArrayRef<CombinerRecipe> Combiners)
1320+ : OpenACCReductionRecipe(A, {}), CombinerRecipeStorage(Combiners) {
1321+ CombinerRecipes = CombinerRecipeStorage;
1322+ }
1323+
1324+ OpenACCReductionRecipeWithStorage (
1325+ const OpenACCReductionRecipeWithStorage &Other)
1326+ : OpenACCReductionRecipe(Other),
1327+ CombinerRecipeStorage (Other.CombinerRecipeStorage) {
1328+ CombinerRecipes = CombinerRecipeStorage;
1329+ }
1330+
1331+ OpenACCReductionRecipeWithStorage (OpenACCReductionRecipeWithStorage &&Other)
1332+ : OpenACCReductionRecipe(std::move(Other)),
1333+ CombinerRecipeStorage(std::move(Other.CombinerRecipeStorage)) {
1334+ CombinerRecipes = CombinerRecipeStorage;
1335+ }
1336+
1337+ // There is no real problem implementing these, we just have to make sure the
1338+ // array-ref this inherits from stays in sync. But as we don't need it at the
1339+ // moment, make sure we don't accidentially call these.
1340+ OpenACCReductionRecipeWithStorage &
1341+ operator =(OpenACCReductionRecipeWithStorage &&) = delete ;
1342+ OpenACCReductionRecipeWithStorage &
1343+ operator =(const OpenACCReductionRecipeWithStorage &) = delete ;
1344+
1345+ static OpenACCReductionRecipeWithStorage Empty () {
1346+ return OpenACCReductionRecipeWithStorage (/* AllocaDecl=*/ nullptr , {});
13081347 }
13091348};
13101349
13111350class OpenACCReductionClause final
13121351 : public OpenACCClauseWithVarList,
13131352 private llvm::TrailingObjects<OpenACCReductionClause, Expr *,
1314- OpenACCReductionRecipe> {
1353+ OpenACCReductionRecipe,
1354+ OpenACCReductionRecipe::CombinerRecipe> {
13151355 friend TrailingObjects;
13161356 OpenACCReductionOperator Op;
13171357
13181358 OpenACCReductionClause (SourceLocation BeginLoc, SourceLocation LParenLoc,
13191359 OpenACCReductionOperator Operator,
13201360 ArrayRef<Expr *> VarList,
1321- ArrayRef<OpenACCReductionRecipe > Recipes,
1361+ ArrayRef<OpenACCReductionRecipeWithStorage > Recipes,
13221362 SourceLocation EndLoc)
13231363 : OpenACCClauseWithVarList(OpenACCClauseKind::Reduction, BeginLoc,
13241364 LParenLoc, EndLoc),
13251365 Op (Operator) {
1326- assert (VarList.size () == Recipes.size ());
1366+ assert (VarList.size () == Recipes.size ());
13271367 setExprs (getTrailingObjects<Expr *>(VarList.size ()), VarList);
1328- llvm::uninitialized_copy (Recipes, getTrailingObjects<
1329- OpenACCReductionRecipe > ());
1368+
1369+ // Since we're using trailing storage on this node to store the 'combiner'
1370+ // recipes of the Reduction Recipes (which have a 1:M relationship), we need
1371+ // to ensure we get the ArrayRef of each of our combiner 'correct'.
1372+ OpenACCReductionRecipe::CombinerRecipe *CurCombinerLoc =
1373+ getTrailingObjects<OpenACCReductionRecipe::CombinerRecipe>();
1374+ for (const auto &[Idx, R] : llvm::enumerate (Recipes)) {
1375+
1376+ // ArrayRef to the 'correct' data location in trailing storage.
1377+ llvm::MutableArrayRef<OpenACCReductionRecipe::CombinerRecipe>
1378+ NewCombiners{CurCombinerLoc, R.CombinerRecipes .size ()};
1379+ CurCombinerLoc += R.CombinerRecipes .size ();
1380+
1381+ llvm::uninitialized_copy (R.CombinerRecipes , NewCombiners.begin ());
1382+
1383+ // Placement new into the correct location in trailng storage.
1384+ new (&getTrailingObjects<OpenACCReductionRecipe>()[Idx])
1385+ OpenACCReductionRecipe (R.AllocaDecl , NewCombiners);
1386+ }
13301387 }
13311388
13321389public:
@@ -1347,13 +1404,17 @@ class OpenACCReductionClause final
13471404 static OpenACCReductionClause *
13481405 Create (const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc,
13491406 OpenACCReductionOperator Operator, ArrayRef<Expr *> VarList,
1350- ArrayRef<OpenACCReductionRecipe> Recipes, SourceLocation EndLoc);
1407+ ArrayRef<OpenACCReductionRecipeWithStorage> Recipes,
1408+ SourceLocation EndLoc);
13511409
13521410 OpenACCReductionOperator getReductionOp () const { return Op; }
13531411
13541412 size_t numTrailingObjects (OverloadToken<Expr *>) const {
13551413 return getExprs ().size ();
13561414 }
1415+ size_t numTrailingObjects (OverloadToken<OpenACCReductionRecipe>) const {
1416+ return getExprs ().size ();
1417+ }
13571418};
13581419
13591420class OpenACCLinkClause final
0 commit comments