[flang-commits] [flang] [flang][acc][NFC] move recipe generation in FIROpenACCUtils (PR #176924)

via flang-commits flang-commits at lists.llvm.org
Tue Jan 20 05:25:51 PST 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-flang-fir-hlfir

Author: None (jeanPerier)

<details>
<summary>Changes</summary>

Move the code that generates private, firstprivate, and reduction from Lower/OpenACC.cpp to Optimizer/OpenACC/Support/FIROpenACCUtils.cpp so that it can be used in passes too.

---

Patch is 44.48 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/176924.diff


3 Files Affected:

- (modified) flang/include/flang/Optimizer/OpenACC/Support/FIROpenACCUtils.h (+37) 
- (modified) flang/lib/Lower/OpenACC.cpp (+13-396) 
- (modified) flang/lib/Optimizer/OpenACC/Support/FIROpenACCUtils.cpp (+381-11) 


``````````diff
diff --git a/flang/include/flang/Optimizer/OpenACC/Support/FIROpenACCUtils.h b/flang/include/flang/Optimizer/OpenACC/Support/FIROpenACCUtils.h
index 5ca0925ea681f..79f5626df4d24 100644
--- a/flang/include/flang/Optimizer/OpenACC/Support/FIROpenACCUtils.h
+++ b/flang/include/flang/Optimizer/OpenACC/Support/FIROpenACCUtils.h
@@ -14,6 +14,7 @@
 #define FORTRAN_OPTIMIZER_OPENACC_SUPPORT_FIROPENACCUTILS_H
 
 #include "mlir/Dialect/OpenACC/OpenACC.h"
+#include "mlir/IR/Builders.h"
 #include "mlir/IR/Value.h"
 #include <string>
 
@@ -51,6 +52,42 @@ std::string getRecipeName(mlir::acc::RecipeKind kind, mlir::Type type,
 /// \return true if all bounds have constant lowerbound/upperbound or extent
 bool areAllBoundsConstant(llvm::ArrayRef<mlir::Value> bounds);
 
+/// Create or get a private recipe for the given type and name.
+/// \param builder The FIR builder
+/// \param loc The location
+/// \param ty The type of the variable
+/// \param dataBoundOps Optional bounds for the variable
+/// \return The existing or created PrivateRecipeOp symbol
+mlir::SymbolRefAttr
+createOrGetPrivateRecipe(mlir::OpBuilder &builder, mlir::Location loc,
+                         mlir::Type ty,
+                         llvm::SmallVector<mlir::Value> &dataBoundOps);
+
+/// Create or get a firstprivate recipe for the given type and name.
+/// \param builder The FIR builder
+/// \param loc The location
+/// \param ty The type of the variable
+/// \param dataBoundOps Optional bounds for the variable
+/// \return The existing or created FirstprivateRecipeOp symbol
+mlir::SymbolRefAttr
+createOrGetFirstprivateRecipe(mlir::OpBuilder &builder, mlir::Location loc,
+                              mlir::Type ty,
+                              llvm::SmallVector<mlir::Value> &dataBoundOps);
+
+/// Create or get a reduction recipe for the given type, name and operator.
+/// \param builder The FIR builder
+/// \param loc The location
+/// \param ty The type of the variable
+/// \param op The reduction operator
+/// \param dataBoundOps Optional bounds for the variable
+/// \param fastMathAttr Optional fast math attributes
+/// \return The existing or created ReductionRecipeOp symbol
+mlir::SymbolRefAttr
+createOrGetReductionRecipe(mlir::OpBuilder &builder, mlir::Location loc,
+                           mlir::Type ty, mlir::acc::ReductionOperator op,
+                           llvm::SmallVector<mlir::Value> &dataBoundOps,
+                           mlir::Attribute fastMathAttr = {});
+
 } // namespace acc
 } // namespace fir
 
diff --git a/flang/lib/Lower/OpenACC.cpp b/flang/lib/Lower/OpenACC.cpp
index 1e313b20d464c..ee1c95349c535 100644
--- a/flang/lib/Lower/OpenACC.cpp
+++ b/flang/lib/Lower/OpenACC.cpp
@@ -83,8 +83,6 @@ static constexpr std::int64_t starCst = -1;
 
 static unsigned routineCounter = 0;
 static constexpr llvm::StringRef accRoutinePrefix = "acc_routine_";
-static constexpr llvm::StringRef accPrivateInitName = "acc.private.init";
-static constexpr llvm::StringRef accReductionInitName = "acc.reduction.init";
 
 static mlir::Location
 genOperandLocation(Fortran::lower::AbstractConverter &converter,
@@ -649,32 +647,6 @@ void genAtomicCapture(Fortran::lower::AbstractConverter &converter,
   firOpBuilder.setInsertionPointAfter(atomicCaptureOp);
 }
 
-static mlir::SymbolRefAttr
-createOrGetRecipe(fir::FirOpBuilder &builder, mlir::Location loc,
-                  mlir::acc::RecipeKind kind, mlir::Value addr,
-                  llvm::SmallVector<mlir::Value> &bounds) {
-  mlir::Type ty = addr.getType();
-  // Compute the canonical recipe name for the given kind, type, address and
-  // bounds so that recipes are shared wherever possible.
-  std::string recipeName = fir::acc::getRecipeName(kind, ty, addr, bounds);
-
-  switch (kind) {
-  case mlir::acc::RecipeKind::private_recipe: {
-    auto recipe = Fortran::lower::createOrGetPrivateRecipe(builder, recipeName,
-                                                           loc, ty, bounds);
-    return mlir::SymbolRefAttr::get(builder.getContext(), recipe.getSymName());
-  }
-  case mlir::acc::RecipeKind::firstprivate_recipe: {
-    auto recipe = Fortran::lower::createOrGetFirstprivateRecipe(
-        builder, recipeName, loc, ty, bounds);
-    return mlir::SymbolRefAttr::get(builder.getContext(), recipe.getSymName());
-  }
-  default:
-    llvm::report_fatal_error(
-        "createOrGetRecipe only supports private and firstprivate recipes");
-  }
-}
-
 namespace {
 // Helper class to keep track of designators that appear in data clauses of
 // structured constructs so that they can be remapped to the data operation
@@ -828,14 +800,12 @@ genDataOperandOperations(const Fortran::parser::AccObjectList &objectList,
 
     // For private/firstprivate, attach (and optionally record) the recipe.
     if constexpr (std::is_same_v<Op, mlir::acc::PrivateOp>) {
-      mlir::SymbolRefAttr recipeAttr = createOrGetRecipe(
-          builder, operandLocation, mlir::acc::RecipeKind::private_recipe,
-          info.addr, bounds);
+      mlir::SymbolRefAttr recipeAttr = fir::acc::createOrGetPrivateRecipe(
+          builder, operandLocation, baseAddr.getType(), bounds);
       op.setRecipeAttr(recipeAttr);
     } else if constexpr (std::is_same_v<Op, mlir::acc::FirstprivateOp>) {
-      mlir::SymbolRefAttr recipeAttr = createOrGetRecipe(
-          builder, operandLocation, mlir::acc::RecipeKind::firstprivate_recipe,
-          info.addr, bounds);
+      mlir::SymbolRefAttr recipeAttr = fir::acc::createOrGetFirstprivateRecipe(
+          builder, operandLocation, baseAddr.getType(), bounds);
       op.setRecipeAttr(recipeAttr);
     }
   }
@@ -1100,323 +1070,6 @@ genDataExitOperations(fir::FirOpBuilder &builder,
   }
 }
 
-/// Get the initial value for reduction operator.
-template <typename R>
-static R getReductionInitValue(mlir::acc::ReductionOperator op, mlir::Type ty) {
-  if (op == mlir::acc::ReductionOperator::AccMin) {
-    // min init value -> largest
-    if constexpr (std::is_same_v<R, llvm::APInt>) {
-      assert(ty.isIntOrIndex() && "expect integer or index type");
-      return llvm::APInt::getSignedMaxValue(ty.getIntOrFloatBitWidth());
-    }
-    if constexpr (std::is_same_v<R, llvm::APFloat>) {
-      auto floatTy = mlir::dyn_cast_or_null<mlir::FloatType>(ty);
-      assert(floatTy && "expect float type");
-      return llvm::APFloat::getLargest(floatTy.getFloatSemantics(),
-                                       /*negative=*/false);
-    }
-  } else if (op == mlir::acc::ReductionOperator::AccMax) {
-    // max init value -> smallest
-    if constexpr (std::is_same_v<R, llvm::APInt>) {
-      assert(ty.isIntOrIndex() && "expect integer or index type");
-      return llvm::APInt::getSignedMinValue(ty.getIntOrFloatBitWidth());
-    }
-    if constexpr (std::is_same_v<R, llvm::APFloat>) {
-      auto floatTy = mlir::dyn_cast_or_null<mlir::FloatType>(ty);
-      assert(floatTy && "expect float type");
-      return llvm::APFloat::getSmallest(floatTy.getFloatSemantics(),
-                                        /*negative=*/true);
-    }
-  } else if (op == mlir::acc::ReductionOperator::AccIand) {
-    if constexpr (std::is_same_v<R, llvm::APInt>) {
-      assert(ty.isIntOrIndex() && "expect integer type");
-      unsigned bits = ty.getIntOrFloatBitWidth();
-      return llvm::APInt::getAllOnes(bits);
-    }
-  } else {
-    assert(op != mlir::acc::ReductionOperator::AccNone);
-    // +, ior, ieor init value -> 0
-    // * init value -> 1
-    int64_t value = (op == mlir::acc::ReductionOperator::AccMul) ? 1 : 0;
-    if constexpr (std::is_same_v<R, llvm::APInt>) {
-      assert(ty.isIntOrIndex() && "expect integer or index type");
-      return llvm::APInt(ty.getIntOrFloatBitWidth(), value, true);
-    }
-
-    if constexpr (std::is_same_v<R, llvm::APFloat>) {
-      assert(mlir::isa<mlir::FloatType>(ty) && "expect float type");
-      auto floatTy = mlir::dyn_cast<mlir::FloatType>(ty);
-      return llvm::APFloat(floatTy.getFloatSemantics(), value);
-    }
-
-    if constexpr (std::is_same_v<R, int64_t>)
-      return value;
-  }
-  llvm_unreachable("OpenACC reduction unsupported type");
-}
-
-/// Return a constant with the initial value for the reduction operator and
-/// type combination.
-static mlir::Value getReductionInitValue(fir::FirOpBuilder &builder,
-                                         mlir::Location loc, mlir::Type ty,
-                                         mlir::acc::ReductionOperator op) {
-  if (op == mlir::acc::ReductionOperator::AccLand ||
-      op == mlir::acc::ReductionOperator::AccLor ||
-      op == mlir::acc::ReductionOperator::AccEqv ||
-      op == mlir::acc::ReductionOperator::AccNeqv) {
-    assert(mlir::isa<fir::LogicalType>(ty) && "expect fir.logical type");
-    bool value = true; // .true. for .and. and .eqv.
-    if (op == mlir::acc::ReductionOperator::AccLor ||
-        op == mlir::acc::ReductionOperator::AccNeqv)
-      value = false; // .false. for .or. and .neqv.
-    return builder.createBool(loc, value);
-  }
-  if (ty.isIntOrIndex())
-    return mlir::arith::ConstantOp::create(
-        builder, loc, ty,
-        builder.getIntegerAttr(ty, getReductionInitValue<llvm::APInt>(op, ty)));
-  if (op == mlir::acc::ReductionOperator::AccMin ||
-      op == mlir::acc::ReductionOperator::AccMax) {
-    if (mlir::isa<mlir::ComplexType>(ty))
-      llvm::report_fatal_error(
-          "min/max reduction not supported for complex type");
-    if (auto floatTy = mlir::dyn_cast_or_null<mlir::FloatType>(ty))
-      return mlir::arith::ConstantOp::create(
-          builder, loc, ty,
-          builder.getFloatAttr(ty,
-                               getReductionInitValue<llvm::APFloat>(op, ty)));
-  } else if (auto floatTy = mlir::dyn_cast_or_null<mlir::FloatType>(ty)) {
-    return mlir::arith::ConstantOp::create(
-        builder, loc, ty,
-        builder.getFloatAttr(ty, getReductionInitValue<int64_t>(op, ty)));
-  } else if (auto cmplxTy = mlir::dyn_cast_or_null<mlir::ComplexType>(ty)) {
-    mlir::Type floatTy = cmplxTy.getElementType();
-    mlir::Value realInit = builder.createRealConstant(
-        loc, floatTy, getReductionInitValue<int64_t>(op, cmplxTy));
-    mlir::Value imagInit = builder.createRealConstant(loc, floatTy, 0.0);
-    return fir::factory::Complex{builder, loc}.createComplex(cmplxTy, realInit,
-                                                             imagInit);
-  }
-
-  if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(ty))
-    return getReductionInitValue(builder, loc, seqTy.getEleTy(), op);
-
-  if (auto boxTy = mlir::dyn_cast<fir::BaseBoxType>(ty))
-    return getReductionInitValue(builder, loc, boxTy.getEleTy(), op);
-
-  if (auto heapTy = mlir::dyn_cast<fir::HeapType>(ty))
-    return getReductionInitValue(builder, loc, heapTy.getEleTy(), op);
-
-  if (auto ptrTy = mlir::dyn_cast<fir::PointerType>(ty))
-    return getReductionInitValue(builder, loc, ptrTy.getEleTy(), op);
-
-  llvm::report_fatal_error("Unsupported OpenACC reduction type");
-}
-
-static llvm::SmallVector<mlir::Value>
-getRecipeBounds(fir::FirOpBuilder &builder, mlir::Location loc,
-                mlir::ValueRange dataBoundOps,
-                mlir::ValueRange blockBoundArgs) {
-  if (dataBoundOps.empty())
-    return {};
-  mlir::Type idxTy = builder.getIndexType();
-  mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1);
-  llvm::SmallVector<mlir::Value> bounds;
-  if (!blockBoundArgs.empty()) {
-    for (unsigned i = 0; i + 2 < blockBoundArgs.size(); i += 3) {
-      bounds.push_back(blockBoundArgs[i]);
-      bounds.push_back(blockBoundArgs[i + 1]);
-      // acc data bound strides is the inner size in bytes or elements, but
-      // sections are always 1-based, so there is no need to try to compute
-      // that back from the acc bounds.
-      bounds.push_back(one);
-    }
-    return bounds;
-  }
-  for (auto bound : dataBoundOps) {
-    auto dataBound = llvm::dyn_cast_if_present<mlir::acc::DataBoundsOp>(
-        bound.getDefiningOp());
-    assert(dataBound && "expect acc bounds to be produced by DataBoundsOp");
-    assert(
-        dataBound.getLowerbound() && dataBound.getUpperbound() &&
-        "expect acc bounds for Fortran to always have lower and upper bounds");
-    std::optional<std::int64_t> lb =
-        fir::getIntIfConstant(dataBound.getLowerbound());
-    std::optional<std::int64_t> ub =
-        fir::getIntIfConstant(dataBound.getUpperbound());
-    assert(lb.has_value() && ub.has_value() &&
-           "must get constant bounds when there are no bound block arguments");
-    bounds.push_back(builder.createIntegerConstant(loc, idxTy, *lb));
-    bounds.push_back(builder.createIntegerConstant(loc, idxTy, *ub));
-    bounds.push_back(one);
-  }
-  return bounds;
-}
-
-static void addRecipeBoundsArgs(llvm::SmallVector<mlir::Value> &bounds,
-                                bool allConstantBound,
-                                llvm::SmallVector<mlir::Type> &argsTy,
-                                llvm::SmallVector<mlir::Location> &argsLoc) {
-  if (!allConstantBound) {
-    for (mlir::Value bound : llvm::reverse(bounds)) {
-      auto dataBound =
-          mlir::dyn_cast<mlir::acc::DataBoundsOp>(bound.getDefiningOp());
-      argsTy.push_back(dataBound.getLowerbound().getType());
-      argsLoc.push_back(dataBound.getLowerbound().getLoc());
-      argsTy.push_back(dataBound.getUpperbound().getType());
-      argsLoc.push_back(dataBound.getUpperbound().getLoc());
-      argsTy.push_back(dataBound.getStartIdx().getType());
-      argsLoc.push_back(dataBound.getStartIdx().getLoc());
-    }
-  }
-}
-
-using MappableValue = mlir::TypedValue<mlir::acc::MappableType>;
-
-template <typename RecipeOp>
-static RecipeOp genRecipeOp(
-    fir::FirOpBuilder &builder, mlir::ModuleOp mod, llvm::StringRef recipeName,
-    mlir::Location loc, mlir::Type ty,
-    llvm::SmallVector<mlir::Value> &dataOperationBounds, bool allConstantBound,
-    mlir::acc::ReductionOperator op = mlir::acc::ReductionOperator::AccNone) {
-  mlir::OpBuilder modBuilder(mod.getBodyRegion());
-  RecipeOp recipe;
-  if constexpr (std::is_same_v<RecipeOp, mlir::acc::ReductionRecipeOp>) {
-    recipe = mlir::acc::ReductionRecipeOp::create(modBuilder, loc, recipeName,
-                                                  ty, op);
-  } else {
-    recipe = RecipeOp::create(modBuilder, loc, recipeName, ty);
-  }
-
-  assert(hlfir::isFortranVariableType(ty) && "expect Fortran variable type");
-
-  llvm::SmallVector<mlir::Type> argsTy{ty};
-  llvm::SmallVector<mlir::Location> argsLoc{loc};
-  if (!dataOperationBounds.empty())
-    addRecipeBoundsArgs(dataOperationBounds, allConstantBound, argsTy, argsLoc);
-
-  auto initBlock = builder.createBlock(
-      &recipe.getInitRegion(), recipe.getInitRegion().end(), argsTy, argsLoc);
-  builder.setInsertionPointToEnd(&recipe.getInitRegion().back());
-  mlir::Value initValue;
-  if constexpr (std::is_same_v<RecipeOp, mlir::acc::ReductionRecipeOp>) {
-    assert(op != mlir::acc::ReductionOperator::AccNone);
-    initValue = getReductionInitValue(builder, loc, fir::unwrapRefType(ty), op);
-  }
-
-  // Since we reuse the same recipe for all variables of the same type - we
-  // cannot use the actual variable name. Thus use a temporary name.
-  llvm::StringRef initName;
-  if constexpr (std::is_same_v<RecipeOp, mlir::acc::ReductionRecipeOp>)
-    initName = accReductionInitName;
-  else
-    initName = accPrivateInitName;
-
-  auto mappableTy = mlir::dyn_cast<mlir::acc::MappableType>(ty);
-  assert(mappableTy &&
-         "Expected that all variable types are considered mappable");
-  bool needsDestroy = false;
-  llvm::SmallVector<mlir::Value> initBounds =
-      getRecipeBounds(builder, loc, dataOperationBounds,
-                      initBlock->getArguments().drop_front(1));
-  mlir::Value retVal = mappableTy.generatePrivateInit(
-      builder, loc, mlir::cast<MappableValue>(initBlock->getArgument(0)),
-      initName, initBounds, initValue, needsDestroy);
-  mlir::acc::YieldOp::create(builder, loc, retVal);
-  // Create destroy region and generate destruction if requested.
-  if (needsDestroy) {
-    llvm::SmallVector<mlir::Type> destroyArgsTy;
-    llvm::SmallVector<mlir::Location> destroyArgsLoc;
-    // original and privatized/reduction value
-    destroyArgsTy.push_back(ty);
-    destroyArgsTy.push_back(ty);
-    destroyArgsLoc.push_back(loc);
-    destroyArgsLoc.push_back(loc);
-    // Append bounds arguments (if any) in the same order as init region
-    if (argsTy.size() > 1) {
-      destroyArgsTy.append(argsTy.begin() + 1, argsTy.end());
-      destroyArgsLoc.insert(destroyArgsLoc.end(), argsTy.size() - 1, loc);
-    }
-
-    mlir::Block *destroyBlock = builder.createBlock(
-        &recipe.getDestroyRegion(), recipe.getDestroyRegion().end(),
-        destroyArgsTy, destroyArgsLoc);
-    builder.setInsertionPointToEnd(destroyBlock);
-
-    llvm::SmallVector<mlir::Value> destroyBounds =
-        getRecipeBounds(builder, loc, dataOperationBounds,
-                        destroyBlock->getArguments().drop_front(2));
-    [[maybe_unused]] bool success = mappableTy.generatePrivateDestroy(
-        builder, loc, destroyBlock->getArgument(1), destroyBounds);
-    assert(success && "failed to generate destroy region");
-    mlir::acc::TerminatorOp::create(builder, loc);
-  }
-  return recipe;
-}
-
-mlir::acc::PrivateRecipeOp Fortran::lower::createOrGetPrivateRecipe(
-    fir::FirOpBuilder &builder, llvm::StringRef recipeName, mlir::Location loc,
-    mlir::Type ty, llvm::SmallVector<mlir::Value> &bounds) {
-  mlir::ModuleOp mod =
-      builder.getBlock()->getParent()->getParentOfType<mlir::ModuleOp>();
-  if (auto recipe = mod.lookupSymbol<mlir::acc::PrivateRecipeOp>(recipeName))
-    return recipe;
-
-  auto ip = builder.saveInsertionPoint();
-  bool allConstantBound = fir::acc::areAllBoundsConstant(bounds);
-  auto recipe = genRecipeOp<mlir::acc::PrivateRecipeOp>(
-      builder, mod, recipeName, loc, ty, bounds, allConstantBound);
-  builder.restoreInsertionPoint(ip);
-  return recipe;
-}
-
-// Generate the combiner or copy region block and block arguments and return the
-// source and destination entities.
-static std::pair<MappableValue, MappableValue>
-genRecipeCombinerOrCopyRegion(fir::FirOpBuilder &builder, mlir::Location loc,
-                              mlir::Type ty, mlir::Region &region,
-                              llvm::SmallVector<mlir::Value> &bounds,
-                              bool allConstantBound) {
-  llvm::SmallVector<mlir::Type> argsTy{ty, ty};
-  llvm::SmallVector<mlir::Location> argsLoc{loc, loc};
-  addRecipeBoundsArgs(bounds, allConstantBound, argsTy, argsLoc);
-  mlir::Block *block =
-      builder.createBlock(&region, region.end(), argsTy, argsLoc);
-  builder.setInsertionPointToEnd(&region.back());
-  auto firstArg = mlir::cast<MappableValue>(block->getArgument(0));
-  auto secondArg = mlir::cast<MappableValue>(block->getArgument(1));
-  return {firstArg, secondArg};
-}
-
-mlir::acc::FirstprivateRecipeOp Fortran::lower::createOrGetFirstprivateRecipe(
-    fir::FirOpBuilder &builder, llvm::StringRef recipeName, mlir::Location loc,
-    mlir::Type ty, llvm::SmallVector<mlir::Value> &dataBoundOps) {
-  mlir::ModuleOp mod =
-      builder.getBlock()->getParent()->getParentOfType<mlir::ModuleOp>();
-  if (auto recipe =
-          mod.lookupSymbol<mlir::acc::FirstprivateRecipeOp>(recipeName))
-    return recipe;
-
-  mlir::OpBuilder::InsertionGuard guard(builder);
-  bool allConstantBound = fir::acc::areAllBoundsConstant(dataBoundOps);
-  auto recipe = genRecipeOp<mlir::acc::FirstprivateRecipeOp>(
-      builder, mod, recipeName, loc, ty, dataBoundOps, allConstantBound);
-  auto [source, destination] = genRecipeCombinerOrCopyRegion(
-      builder, loc, ty, recipe.getCopyRegion(), dataBoundOps, allConstantBound);
-  llvm::SmallVector<mlir::Value> copyBounds =
-      getRecipeBounds(builder, loc, dataBoundOps,
-                      recipe.getCopyRegion().getArguments().drop_front(2));
-
-  auto mappableTy = mlir::dyn_cast<mlir::acc::MappableType>(ty);
-  assert(mappableTy &&
-         "Expected that all variable types are considered mappable");
-  [[maybe_unused]] bool success =
-      mappableTy.generateCopy(builder, loc, source, destination, copyBounds);
-  assert(success && "failed to generate copy");
-  mlir::acc::TerminatorOp::create(builder, loc);
-  return recipe;
-}
-
 /// Ret...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/176924


More information about the flang-commits mailing list