[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 ®ion,
- 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(®ion, region.end(), argsTy, argsLoc);
- builder.setInsertionPointToEnd(®ion.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