Author: Erich Keane
Date: 2025-09-05T19:18:15Z
New Revision: a549e73cad60336d8e9c0622ae7ad86aa65ef4ce

URL: 
https://github.com/llvm/llvm-project/commit/a549e73cad60336d8e9c0622ae7ad86aa65ef4ce
DIFF: 
https://github.com/llvm/llvm-project/commit/a549e73cad60336d8e9c0622ae7ad86aa65ef4ce.diff

LOG: [OpenACC][NFCI] Split recipe generation into its own class (#157160)

The recipe generation was dependent on the clause kind, which meant we
had all of the recipe generation duplicated in each of clauses. This
patch copy/pastes all of them into their own type to do recipe
generation, which should reduce clang's size.

Additionally, we've moved it off into its own file, which should make
readability/organization improvements.

Added: 
    clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.h

Modified: 
    clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp 
b/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp
index 0022befa3b562..9959cf6c15792 100644
--- a/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp
@@ -14,6 +14,7 @@
 
 #include "CIRGenCXXABI.h"
 #include "CIRGenFunction.h"
+#include "CIRGenOpenACCRecipe.h"
 
 #include "clang/AST/ExprCXX.h"
 
@@ -356,299 +357,6 @@ class OpenACCClauseCIREmitter final
     }
   }
 
-  template <typename RecipeTy>
-  std::string getRecipeName(SourceRange loc, QualType baseType,
-                            OpenACCReductionOperator reductionOp) {
-    std::string recipeName;
-    {
-      llvm::raw_string_ostream stream(recipeName);
-
-      if constexpr (std::is_same_v<RecipeTy, mlir::acc::PrivateRecipeOp>) {
-        stream << "privatization_";
-      } else if constexpr (std::is_same_v<RecipeTy,
-                                          mlir::acc::FirstprivateRecipeOp>) {
-        stream << "firstprivatization_";
-
-      } else if constexpr (std::is_same_v<RecipeTy,
-                                          mlir::acc::ReductionRecipeOp>) {
-        stream << "reduction_";
-        // Values here are a little weird (for bitwise and/or is 'i' prefix, 
and
-        // logical ops with 'l'), but are chosen to be the same as the MLIR
-        // dialect names as well as to match the Flang versions of these.
-        switch (reductionOp) {
-        case OpenACCReductionOperator::Addition:
-          stream << "add_";
-          break;
-        case OpenACCReductionOperator::Multiplication:
-          stream << "mul_";
-          break;
-        case OpenACCReductionOperator::Max:
-          stream << "max_";
-          break;
-        case OpenACCReductionOperator::Min:
-          stream << "min_";
-          break;
-        case OpenACCReductionOperator::BitwiseAnd:
-          stream << "iand_";
-          break;
-        case OpenACCReductionOperator::BitwiseOr:
-          stream << "ior_";
-          break;
-        case OpenACCReductionOperator::BitwiseXOr:
-          stream << "xor_";
-          break;
-        case OpenACCReductionOperator::And:
-          stream << "land_";
-          break;
-        case OpenACCReductionOperator::Or:
-          stream << "lor_";
-          break;
-        case OpenACCReductionOperator::Invalid:
-          llvm_unreachable("invalid reduction operator");
-        }
-      } else {
-        static_assert(!sizeof(RecipeTy), "Unknown Recipe op kind");
-      }
-
-      MangleContext &mc = cgf.cgm.getCXXABI().getMangleContext();
-      mc.mangleCanonicalTypeName(baseType, stream);
-    }
-    return recipeName;
-  }
-
-  void createFirstprivateRecipeCopy(
-      mlir::Location loc, mlir::Location locEnd, mlir::Value mainOp,
-      CIRGenFunction::AutoVarEmission tempDeclEmission,
-      mlir::acc::FirstprivateRecipeOp recipe, const VarDecl *varRecipe,
-      const VarDecl *temporary) {
-    mlir::Block *block = builder.createBlock(
-        &recipe.getCopyRegion(), recipe.getCopyRegion().end(),
-        {mainOp.getType(), mainOp.getType()}, {loc, loc});
-    builder.setInsertionPointToEnd(&recipe.getCopyRegion().back());
-    CIRGenFunction::LexicalScope ls(cgf, loc, block);
-
-    mlir::BlockArgument fromArg = block->getArgument(0);
-    mlir::BlockArgument toArg = block->getArgument(1);
-
-    mlir::Type elementTy =
-        mlir::cast<cir::PointerType>(mainOp.getType()).getPointee();
-
-    // Set the address of the emission to be the argument, so that we 
initialize
-    // that instead of the variable in the other block.
-    tempDeclEmission.setAllocatedAddress(
-        Address{toArg, elementTy, cgf.getContext().getDeclAlign(varRecipe)});
-    tempDeclEmission.EmittedAsOffload = true;
-
-    CIRGenFunction::DeclMapRevertingRAII declMapRAII{cgf, temporary};
-    cgf.setAddrOfLocalVar(
-        temporary,
-        Address{fromArg, elementTy, cgf.getContext().getDeclAlign(varRecipe)});
-
-    cgf.emitAutoVarInit(tempDeclEmission);
-    mlir::acc::YieldOp::create(builder, locEnd);
-  }
-
-  // Create the 'init' section of the recipe, including the 'copy' section for
-  // 'firstprivate'.  Note that this function is not 'insertion point' clean, 
in
-  // that it alters the insertion point to be inside of the 'destroy' section 
of
-  // the recipe, but doesn't restore it aftewards.
-  template <typename RecipeTy>
-  void createRecipeInitCopy(mlir::Location loc, mlir::Location locEnd,
-                            SourceRange exprRange, mlir::Value mainOp,
-                            RecipeTy recipe, const VarDecl *varRecipe,
-                            const VarDecl *temporary) {
-    assert(varRecipe && "Required recipe variable not set?");
-
-    CIRGenFunction::AutoVarEmission tempDeclEmission{
-        CIRGenFunction::AutoVarEmission::invalid()};
-    CIRGenFunction::DeclMapRevertingRAII declMapRAII{cgf, varRecipe};
-
-    // Do the 'init' section of the recipe IR, which does an alloca, then the
-    // initialization (except for firstprivate).
-    mlir::Block *block = builder.createBlock(&recipe.getInitRegion(),
-                                             recipe.getInitRegion().end(),
-                                             {mainOp.getType()}, {loc});
-    builder.setInsertionPointToEnd(&recipe.getInitRegion().back());
-    CIRGenFunction::LexicalScope ls(cgf, loc, block);
-
-    tempDeclEmission =
-        cgf.emitAutoVarAlloca(*varRecipe, builder.saveInsertionPoint());
-
-    // 'firstprivate' doesn't do its initialization in the 'init' section,
-    // instead does it in the 'copy' section.  SO only do init here.
-    // 'reduction' appears to use it too (rather than a 'copy' section), so
-    // we probably have to do it here too, but we can do that when we get to
-    // reduction implementation.
-    if constexpr (std::is_same_v<RecipeTy, mlir::acc::PrivateRecipeOp>) {
-      // We are OK with no init for builtins, arrays of builtins, or pointers,
-      // else we should NYI so we know to go look for these.
-      if (cgf.getContext().getLangOpts().CPlusPlus &&
-          !varRecipe->getType()
-               ->getPointeeOrArrayElementType()
-               ->isBuiltinType() &&
-          !varRecipe->getType()->isPointerType() && !varRecipe->getInit()) {
-        // If we don't have any initialization recipe, we failed during Sema to
-        // initialize this correctly. If we disable the
-        // Sema::TentativeAnalysisScopes in SemaOpenACC::CreateInitRecipe, 
it'll
-        // emit an error to tell us.  However, emitting those errors during
-        // production is a violation of the standard, so we cannot do them.
-        cgf.cgm.errorNYI(exprRange, "private default-init recipe");
-      }
-      cgf.emitAutoVarInit(tempDeclEmission);
-    } else if constexpr (std::is_same_v<RecipeTy,
-                                        mlir::acc::ReductionRecipeOp>) {
-      // Unlike Private, the recipe here is always required as it has to do
-      // init, not just 'default' init.
-      if (!varRecipe->getInit())
-        cgf.cgm.errorNYI(exprRange, "reduction init recipe");
-      cgf.emitAutoVarInit(tempDeclEmission);
-    }
-
-    mlir::acc::YieldOp::create(builder, locEnd);
-
-    if constexpr (std::is_same_v<RecipeTy, mlir::acc::FirstprivateRecipeOp>) {
-      if (!varRecipe->getInit()) {
-        // If we don't have any initialization recipe, we failed during Sema to
-        // initialize this correctly. If we disable the
-        // Sema::TentativeAnalysisScopes in SemaOpenACC::CreateInitRecipe, 
it'll
-        // emit an error to tell us.  However, emitting those errors during
-        // production is a violation of the standard, so we cannot do them.
-        cgf.cgm.errorNYI(
-            exprRange, "firstprivate copy-init recipe not properly generated");
-      }
-
-      createFirstprivateRecipeCopy(loc, locEnd, mainOp, tempDeclEmission,
-                                   recipe, varRecipe, temporary);
-    }
-  }
-
-  // This function generates the 'combiner' section for a reduction recipe. 
Note
-  // that this function is not 'insertion point' clean, in that it alters the
-  // insertion point to be inside of the 'combiner' section of the recipe, but
-  // doesn't restore it aftewards.
-  void createReductionRecipeCombiner(mlir::Location loc, mlir::Location locEnd,
-                                     mlir::Value mainOp,
-                                     mlir::acc::ReductionRecipeOp recipe) {
-    mlir::Block *block = builder.createBlock(
-        &recipe.getCombinerRegion(), recipe.getCombinerRegion().end(),
-        {mainOp.getType(), mainOp.getType()}, {loc, loc});
-    builder.setInsertionPointToEnd(&recipe.getCombinerRegion().back());
-    CIRGenFunction::LexicalScope ls(cgf, loc, block);
-
-    mlir::BlockArgument lhsArg = block->getArgument(0);
-
-    mlir::acc::YieldOp::create(builder, locEnd, lhsArg);
-  }
-
-  // This function generates the 'destroy' section for a recipe. Note
-  // that this function is not 'insertion point' clean, in that it alters the
-  // insertion point to be inside of the 'destroy' section of the recipe, but
-  // doesn't restore it aftewards.
-  void createRecipeDestroySection(mlir::Location loc, mlir::Location locEnd,
-                                  mlir::Value mainOp, CharUnits alignment,
-                                  QualType baseType,
-                                  mlir::Region &destroyRegion) {
-    mlir::Block *block =
-        builder.createBlock(&destroyRegion, destroyRegion.end(),
-                            {mainOp.getType(), mainOp.getType()}, {loc, loc});
-    builder.setInsertionPointToEnd(&destroyRegion.back());
-    CIRGenFunction::LexicalScope ls(cgf, loc, block);
-
-    mlir::Type elementTy =
-        mlir::cast<cir::PointerType>(mainOp.getType()).getPointee();
-    // The destroy region has a signature of "original item, privatized item".
-    // So the 2nd item is the one that needs destroying, the former is just for
-    // reference and we don't really have a need for it at the moment.
-    Address addr{block->getArgument(1), elementTy, alignment};
-    cgf.emitDestroy(addr, baseType,
-                    cgf.getDestroyer(QualType::DK_cxx_destructor));
-
-    mlir::acc::YieldOp::create(builder, locEnd);
-  }
-
-  mlir::acc::ReductionOperator convertReductionOp(OpenACCReductionOperator op) 
{
-    switch (op) {
-    case OpenACCReductionOperator::Addition:
-      return mlir::acc::ReductionOperator::AccAdd;
-    case OpenACCReductionOperator::Multiplication:
-      return mlir::acc::ReductionOperator::AccMul;
-    case OpenACCReductionOperator::Max:
-      return mlir::acc::ReductionOperator::AccMax;
-    case OpenACCReductionOperator::Min:
-      return mlir::acc::ReductionOperator::AccMin;
-    case OpenACCReductionOperator::BitwiseAnd:
-      return mlir::acc::ReductionOperator::AccIand;
-    case OpenACCReductionOperator::BitwiseOr:
-      return mlir::acc::ReductionOperator::AccIor;
-    case OpenACCReductionOperator::BitwiseXOr:
-      return mlir::acc::ReductionOperator::AccXor;
-    case OpenACCReductionOperator::And:
-      return mlir::acc::ReductionOperator::AccLand;
-    case OpenACCReductionOperator::Or:
-      return mlir::acc::ReductionOperator::AccLor;
-    case OpenACCReductionOperator::Invalid:
-      llvm_unreachable("invalid reduction operator");
-    }
-
-    llvm_unreachable("invalid reduction operator");
-  }
-
-  template <typename RecipeTy>
-  RecipeTy getOrCreateRecipe(ASTContext &astCtx, const Expr *varRef,
-                             const VarDecl *varRecipe, const VarDecl 
*temporary,
-                             OpenACCReductionOperator reductionOp,
-                             DeclContext *dc, QualType baseType,
-                             mlir::Value mainOp) {
-
-    if (baseType->isPointerType() ||
-        (baseType->isArrayType() && !baseType->isConstantArrayType())) {
-      // It is clear that the use of pointers/VLAs in a recipe are not properly
-      // generated/don't do what they are supposed to do.  In the case where we
-      // have 'bounds', we can actually figure out what we want to
-      // initialize/copy/destroy/compare/etc, but we haven't figured out how
-      // that looks yet, both between the IR and generation code.  For now, we
-      // will do an NYI error no it.
-      cgf.cgm.errorNYI(
-          varRef->getSourceRange(),
-          "OpenACC recipe generation for pointer/non-constant arrays");
-    }
-
-    mlir::ModuleOp mod = builder.getBlock()
-                             ->getParent()
-                             ->template getParentOfType<mlir::ModuleOp>();
-
-    std::string recipeName = getRecipeName<RecipeTy>(varRef->getSourceRange(),
-                                                     baseType, reductionOp);
-    if (auto recipe = mod.lookupSymbol<RecipeTy>(recipeName))
-      return recipe;
-
-    mlir::Location loc = cgf.cgm.getLoc(varRef->getBeginLoc());
-    mlir::Location locEnd = cgf.cgm.getLoc(varRef->getEndLoc());
-
-    mlir::OpBuilder modBuilder(mod.getBodyRegion());
-    RecipeTy recipe;
-
-    if constexpr (std::is_same_v<RecipeTy, mlir::acc::ReductionRecipeOp>) {
-      recipe = RecipeTy::create(modBuilder, loc, recipeName, mainOp.getType(),
-                                convertReductionOp(reductionOp));
-    } else {
-      recipe = RecipeTy::create(modBuilder, loc, recipeName, mainOp.getType());
-    }
-
-    createRecipeInitCopy(loc, locEnd, varRef->getSourceRange(), mainOp, recipe,
-                         varRecipe, temporary);
-
-    if constexpr (std::is_same_v<RecipeTy, mlir::acc::ReductionRecipeOp>) {
-      createReductionRecipeCombiner(loc, locEnd, mainOp, recipe);
-    }
-
-    if (varRecipe && varRecipe->needsDestruction(cgf.getContext()))
-      createRecipeDestroySection(loc, locEnd, mainOp,
-                                 cgf.getContext().getDeclAlign(varRecipe),
-                                 baseType, recipe.getDestroyRegion());
-    return recipe;
-  }
-
 public:
   OpenACCClauseCIREmitter(OpTy &operation, CIRGen::CIRGenFunction &cgf,
                           CIRGen::CIRGenBuilderTy &builder,
@@ -1287,11 +995,13 @@ class OpenACCClauseCIREmitter final
           allocaDecl->setInit(varRecipe.InitExpr);
           allocaDecl->setInitStyle(VarDecl::CallInit);
 
-          auto recipe = getOrCreateRecipe<mlir::acc::PrivateRecipeOp>(
-              cgf.getContext(), varExpr, allocaDecl, /*temporary=*/nullptr,
-              OpenACCReductionOperator::Invalid,
-              Decl::castToDeclContext(cgf.curFuncDecl), opInfo.baseType,
-              privateOp.getResult());
+          auto recipe =
+              OpenACCRecipeBuilder<mlir::acc::PrivateRecipeOp>(cgf, builder)
+                  .getOrCreateRecipe(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
           // have these be on a 
diff erent operation, so when that changes, we
           // probably need to change these here.
@@ -1329,11 +1039,15 @@ class OpenACCClauseCIREmitter final
           allocaDecl->setInit(varRecipe.InitExpr);
           allocaDecl->setInitStyle(VarDecl::CallInit);
 
-          auto recipe = getOrCreateRecipe<mlir::acc::FirstprivateRecipeOp>(
-              cgf.getContext(), varExpr, allocaDecl,
-              varRecipe.InitFromTemporary, OpenACCReductionOperator::Invalid,
-              Decl::castToDeclContext(cgf.curFuncDecl), opInfo.baseType,
-              firstPrivateOp.getResult());
+          auto recipe =
+              OpenACCRecipeBuilder<mlir::acc::FirstprivateRecipeOp>(cgf,
+                                                                    builder)
+                  .getOrCreateRecipe(cgf.getContext(), varExpr, allocaDecl,
+                                     varRecipe.InitFromTemporary,
+                                     OpenACCReductionOperator::Invalid,
+                                     Decl::castToDeclContext(cgf.curFuncDecl),
+                                     opInfo.baseType,
+                                     firstPrivateOp.getResult());
 
           // TODO: OpenACC: The dialect is going to change in the near future 
to
           // have these be on a 
diff erent operation, so when that changes, we
@@ -1373,11 +1087,13 @@ class OpenACCClauseCIREmitter final
           allocaDecl->setInit(varRecipe.InitExpr);
           allocaDecl->setInitStyle(VarDecl::CallInit);
 
-          auto recipe = getOrCreateRecipe<mlir::acc::ReductionRecipeOp>(
-              cgf.getContext(), varExpr, allocaDecl,
-              /*temporary=*/nullptr, clause.getReductionOp(),
-              Decl::castToDeclContext(cgf.curFuncDecl), opInfo.baseType,
-              reductionOp.getResult());
+          auto recipe =
+              OpenACCRecipeBuilder<mlir::acc::ReductionRecipeOp>(cgf, builder)
+                  .getOrCreateRecipe(cgf.getContext(), varExpr, allocaDecl,
+                                     /*temporary=*/nullptr,
+                                     clause.getReductionOp(),
+                                     Decl::castToDeclContext(cgf.curFuncDecl),
+                                     opInfo.baseType, reductionOp.getResult());
 
           operation.addReduction(builder.getContext(), reductionOp, recipe);
         }

diff  --git a/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.h 
b/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.h
new file mode 100644
index 0000000000000..102fd890e5579
--- /dev/null
+++ b/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.h
@@ -0,0 +1,323 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Emit OpenACC clause recipes as CIR code.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CIRGenFunction.h"
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclBase.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/TypeBase.h"
+#include "clang/Basic/OpenACCKinds.h"
+
+#include "mlir/Dialect/OpenACC/OpenACC.h"
+
+namespace clang::CIRGen {
+template <typename RecipeTy> class OpenACCRecipeBuilder {
+  CIRGen::CIRGenFunction &cgf;
+  CIRGen::CIRGenBuilderTy &builder;
+
+  mlir::acc::ReductionOperator convertReductionOp(OpenACCReductionOperator op) 
{
+    switch (op) {
+    case OpenACCReductionOperator::Addition:
+      return mlir::acc::ReductionOperator::AccAdd;
+    case OpenACCReductionOperator::Multiplication:
+      return mlir::acc::ReductionOperator::AccMul;
+    case OpenACCReductionOperator::Max:
+      return mlir::acc::ReductionOperator::AccMax;
+    case OpenACCReductionOperator::Min:
+      return mlir::acc::ReductionOperator::AccMin;
+    case OpenACCReductionOperator::BitwiseAnd:
+      return mlir::acc::ReductionOperator::AccIand;
+    case OpenACCReductionOperator::BitwiseOr:
+      return mlir::acc::ReductionOperator::AccIor;
+    case OpenACCReductionOperator::BitwiseXOr:
+      return mlir::acc::ReductionOperator::AccXor;
+    case OpenACCReductionOperator::And:
+      return mlir::acc::ReductionOperator::AccLand;
+    case OpenACCReductionOperator::Or:
+      return mlir::acc::ReductionOperator::AccLor;
+    case OpenACCReductionOperator::Invalid:
+      llvm_unreachable("invalid reduction operator");
+    }
+
+    llvm_unreachable("invalid reduction operator");
+  }
+
+  std::string getRecipeName(SourceRange loc, QualType baseType,
+                            OpenACCReductionOperator reductionOp) {
+    std::string recipeName;
+    {
+      llvm::raw_string_ostream stream(recipeName);
+
+      if constexpr (std::is_same_v<RecipeTy, mlir::acc::PrivateRecipeOp>) {
+        stream << "privatization_";
+      } else if constexpr (std::is_same_v<RecipeTy,
+                                          mlir::acc::FirstprivateRecipeOp>) {
+        stream << "firstprivatization_";
+
+      } else if constexpr (std::is_same_v<RecipeTy,
+                                          mlir::acc::ReductionRecipeOp>) {
+        stream << "reduction_";
+        // Values here are a little weird (for bitwise and/or is 'i' prefix, 
and
+        // logical ops with 'l'), but are chosen to be the same as the MLIR
+        // dialect names as well as to match the Flang versions of these.
+        switch (reductionOp) {
+        case OpenACCReductionOperator::Addition:
+          stream << "add_";
+          break;
+        case OpenACCReductionOperator::Multiplication:
+          stream << "mul_";
+          break;
+        case OpenACCReductionOperator::Max:
+          stream << "max_";
+          break;
+        case OpenACCReductionOperator::Min:
+          stream << "min_";
+          break;
+        case OpenACCReductionOperator::BitwiseAnd:
+          stream << "iand_";
+          break;
+        case OpenACCReductionOperator::BitwiseOr:
+          stream << "ior_";
+          break;
+        case OpenACCReductionOperator::BitwiseXOr:
+          stream << "xor_";
+          break;
+        case OpenACCReductionOperator::And:
+          stream << "land_";
+          break;
+        case OpenACCReductionOperator::Or:
+          stream << "lor_";
+          break;
+        case OpenACCReductionOperator::Invalid:
+          llvm_unreachable("invalid reduction operator");
+        }
+      } else {
+        static_assert(!sizeof(RecipeTy), "Unknown Recipe op kind");
+      }
+
+      MangleContext &mc = cgf.cgm.getCXXABI().getMangleContext();
+      mc.mangleCanonicalTypeName(baseType, stream);
+    }
+    return recipeName;
+  }
+
+  void createFirstprivateRecipeCopy(
+      mlir::Location loc, mlir::Location locEnd, mlir::Value mainOp,
+      CIRGenFunction::AutoVarEmission tempDeclEmission,
+      mlir::acc::FirstprivateRecipeOp recipe, const VarDecl *varRecipe,
+      const VarDecl *temporary) {
+    mlir::Block *block = builder.createBlock(
+        &recipe.getCopyRegion(), recipe.getCopyRegion().end(),
+        {mainOp.getType(), mainOp.getType()}, {loc, loc});
+    builder.setInsertionPointToEnd(&recipe.getCopyRegion().back());
+    CIRGenFunction::LexicalScope ls(cgf, loc, block);
+
+    mlir::BlockArgument fromArg = block->getArgument(0);
+    mlir::BlockArgument toArg = block->getArgument(1);
+
+    mlir::Type elementTy =
+        mlir::cast<cir::PointerType>(mainOp.getType()).getPointee();
+
+    // Set the address of the emission to be the argument, so that we 
initialize
+    // that instead of the variable in the other block.
+    tempDeclEmission.setAllocatedAddress(
+        Address{toArg, elementTy, cgf.getContext().getDeclAlign(varRecipe)});
+    tempDeclEmission.EmittedAsOffload = true;
+
+    CIRGenFunction::DeclMapRevertingRAII declMapRAII{cgf, temporary};
+    cgf.setAddrOfLocalVar(
+        temporary,
+        Address{fromArg, elementTy, cgf.getContext().getDeclAlign(varRecipe)});
+
+    cgf.emitAutoVarInit(tempDeclEmission);
+    mlir::acc::YieldOp::create(builder, locEnd);
+  }
+
+  // Create the 'init' section of the recipe, including the 'copy' section for
+  // 'firstprivate'.  Note that this function is not 'insertion point' clean, 
in
+  // that it alters the insertion point to be inside of the 'destroy' section 
of
+  // the recipe, but doesn't restore it aftewards.
+  void createRecipeInitCopy(mlir::Location loc, mlir::Location locEnd,
+                            SourceRange exprRange, mlir::Value mainOp,
+                            RecipeTy recipe, const VarDecl *varRecipe,
+                            const VarDecl *temporary) {
+    assert(varRecipe && "Required recipe variable not set?");
+
+    CIRGenFunction::AutoVarEmission tempDeclEmission{
+        CIRGenFunction::AutoVarEmission::invalid()};
+    CIRGenFunction::DeclMapRevertingRAII declMapRAII{cgf, varRecipe};
+
+    // Do the 'init' section of the recipe IR, which does an alloca, then the
+    // initialization (except for firstprivate).
+    mlir::Block *block = builder.createBlock(&recipe.getInitRegion(),
+                                             recipe.getInitRegion().end(),
+                                             {mainOp.getType()}, {loc});
+    builder.setInsertionPointToEnd(&recipe.getInitRegion().back());
+    CIRGenFunction::LexicalScope ls(cgf, loc, block);
+
+    tempDeclEmission =
+        cgf.emitAutoVarAlloca(*varRecipe, builder.saveInsertionPoint());
+
+    // 'firstprivate' doesn't do its initialization in the 'init' section,
+    // instead does it in the 'copy' section.  SO only do init here.
+    // 'reduction' appears to use it too (rather than a 'copy' section), so
+    // we probably have to do it here too, but we can do that when we get to
+    // reduction implementation.
+    if constexpr (std::is_same_v<RecipeTy, mlir::acc::PrivateRecipeOp>) {
+      // We are OK with no init for builtins, arrays of builtins, or pointers,
+      // else we should NYI so we know to go look for these.
+      if (cgf.getContext().getLangOpts().CPlusPlus &&
+          !varRecipe->getType()
+               ->getPointeeOrArrayElementType()
+               ->isBuiltinType() &&
+          !varRecipe->getType()->isPointerType() && !varRecipe->getInit()) {
+        // If we don't have any initialization recipe, we failed during Sema to
+        // initialize this correctly. If we disable the
+        // Sema::TentativeAnalysisScopes in SemaOpenACC::CreateInitRecipe, 
it'll
+        // emit an error to tell us.  However, emitting those errors during
+        // production is a violation of the standard, so we cannot do them.
+        cgf.cgm.errorNYI(exprRange, "private default-init recipe");
+      }
+      cgf.emitAutoVarInit(tempDeclEmission);
+    } else if constexpr (std::is_same_v<RecipeTy,
+                                        mlir::acc::ReductionRecipeOp>) {
+      // Unlike Private, the recipe here is always required as it has to do
+      // init, not just 'default' init.
+      if (!varRecipe->getInit())
+        cgf.cgm.errorNYI(exprRange, "reduction init recipe");
+      cgf.emitAutoVarInit(tempDeclEmission);
+    }
+
+    mlir::acc::YieldOp::create(builder, locEnd);
+
+    if constexpr (std::is_same_v<RecipeTy, mlir::acc::FirstprivateRecipeOp>) {
+      if (!varRecipe->getInit()) {
+        // If we don't have any initialization recipe, we failed during Sema to
+        // initialize this correctly. If we disable the
+        // Sema::TentativeAnalysisScopes in SemaOpenACC::CreateInitRecipe, 
it'll
+        // emit an error to tell us.  However, emitting those errors during
+        // production is a violation of the standard, so we cannot do them.
+        cgf.cgm.errorNYI(
+            exprRange, "firstprivate copy-init recipe not properly generated");
+      }
+
+      createFirstprivateRecipeCopy(loc, locEnd, mainOp, tempDeclEmission,
+                                   recipe, varRecipe, temporary);
+    }
+  }
+
+  // This function generates the 'combiner' section for a reduction recipe. 
Note
+  // that this function is not 'insertion point' clean, in that it alters the
+  // insertion point to be inside of the 'combiner' section of the recipe, but
+  // doesn't restore it aftewards.
+  void createReductionRecipeCombiner(mlir::Location loc, mlir::Location locEnd,
+                                     mlir::Value mainOp,
+                                     mlir::acc::ReductionRecipeOp recipe) {
+    mlir::Block *block = builder.createBlock(
+        &recipe.getCombinerRegion(), recipe.getCombinerRegion().end(),
+        {mainOp.getType(), mainOp.getType()}, {loc, loc});
+    builder.setInsertionPointToEnd(&recipe.getCombinerRegion().back());
+    CIRGenFunction::LexicalScope ls(cgf, loc, block);
+
+    mlir::BlockArgument lhsArg = block->getArgument(0);
+
+    mlir::acc::YieldOp::create(builder, locEnd, lhsArg);
+  }
+
+  // This function generates the 'destroy' section for a recipe. Note
+  // that this function is not 'insertion point' clean, in that it alters the
+  // insertion point to be inside of the 'destroy' section of the recipe, but
+  // doesn't restore it aftewards.
+  void createRecipeDestroySection(mlir::Location loc, mlir::Location locEnd,
+                                  mlir::Value mainOp, CharUnits alignment,
+                                  QualType baseType,
+                                  mlir::Region &destroyRegion) {
+    mlir::Block *block =
+        builder.createBlock(&destroyRegion, destroyRegion.end(),
+                            {mainOp.getType(), mainOp.getType()}, {loc, loc});
+    builder.setInsertionPointToEnd(&destroyRegion.back());
+    CIRGenFunction::LexicalScope ls(cgf, loc, block);
+
+    mlir::Type elementTy =
+        mlir::cast<cir::PointerType>(mainOp.getType()).getPointee();
+    // The destroy region has a signature of "original item, privatized item".
+    // So the 2nd item is the one that needs destroying, the former is just for
+    // reference and we don't really have a need for it at the moment.
+    Address addr{block->getArgument(1), elementTy, alignment};
+    cgf.emitDestroy(addr, baseType,
+                    cgf.getDestroyer(QualType::DK_cxx_destructor));
+
+    mlir::acc::YieldOp::create(builder, locEnd);
+  }
+
+public:
+  OpenACCRecipeBuilder(CIRGen::CIRGenFunction &cgf,
+                       CIRGen::CIRGenBuilderTy &builder)
+      : cgf(cgf), builder(builder) {}
+  RecipeTy getOrCreateRecipe(ASTContext &astCtx, const Expr *varRef,
+                             const VarDecl *varRecipe, const VarDecl 
*temporary,
+                             OpenACCReductionOperator reductionOp,
+                             DeclContext *dc, QualType baseType,
+                             mlir::Value mainOp) {
+
+    if (baseType->isPointerType() ||
+        (baseType->isArrayType() && !baseType->isConstantArrayType())) {
+      // It is clear that the use of pointers/VLAs in a recipe are not properly
+      // generated/don't do what they are supposed to do.  In the case where we
+      // have 'bounds', we can actually figure out what we want to
+      // initialize/copy/destroy/compare/etc, but we haven't figured out how
+      // that looks yet, both between the IR and generation code.  For now, we
+      // will do an NYI error no it.
+      cgf.cgm.errorNYI(
+          varRef->getSourceRange(),
+          "OpenACC recipe generation for pointer/non-constant arrays");
+    }
+
+    mlir::ModuleOp mod = builder.getBlock()
+                             ->getParent()
+                             ->template getParentOfType<mlir::ModuleOp>();
+
+    std::string recipeName =
+        getRecipeName(varRef->getSourceRange(), baseType, reductionOp);
+    if (auto recipe = mod.lookupSymbol<RecipeTy>(recipeName))
+      return recipe;
+
+    mlir::Location loc = cgf.cgm.getLoc(varRef->getBeginLoc());
+    mlir::Location locEnd = cgf.cgm.getLoc(varRef->getEndLoc());
+
+    mlir::OpBuilder modBuilder(mod.getBodyRegion());
+    RecipeTy recipe;
+
+    if constexpr (std::is_same_v<RecipeTy, mlir::acc::ReductionRecipeOp>) {
+      recipe = RecipeTy::create(modBuilder, loc, recipeName, mainOp.getType(),
+                                convertReductionOp(reductionOp));
+    } else {
+      recipe = RecipeTy::create(modBuilder, loc, recipeName, mainOp.getType());
+    }
+
+    createRecipeInitCopy(loc, locEnd, varRef->getSourceRange(), mainOp, recipe,
+                         varRecipe, temporary);
+
+    if constexpr (std::is_same_v<RecipeTy, mlir::acc::ReductionRecipeOp>) {
+      createReductionRecipeCombiner(loc, locEnd, mainOp, recipe);
+    }
+
+    if (varRecipe && varRecipe->needsDestruction(cgf.getContext()))
+      createRecipeDestroySection(loc, locEnd, mainOp,
+                                 cgf.getContext().getDeclAlign(varRecipe),
+                                 baseType, recipe.getDestroyRegion());
+    return recipe;
+  }
+};
+} // namespace clang::CIRGen


        
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to