[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:13 PST 2026
https://github.com/jeanPerier created https://github.com/llvm/llvm-project/pull/176924
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.
>From 7481c083215d0c1c1716694990075a698dde4a85 Mon Sep 17 00:00:00 2001
From: Jean Perier <jperier at nvidia.com>
Date: Tue, 20 Jan 2026 05:10:28 -0800
Subject: [PATCH] [flang][acc][NFC] move recipe generation in FIROpenACCUtils
---
.../OpenACC/Support/FIROpenACCUtils.h | 37 ++
flang/lib/Lower/OpenACC.cpp | 409 +-----------------
.../OpenACC/Support/FIROpenACCUtils.cpp | 392 ++++++++++++++++-
3 files changed, 431 insertions(+), 407 deletions(-)
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;
-}
-
/// Return the corresponding enum value for the mlir::acc::ReductionOperator
/// from the parser representation.
static mlir::acc::ReductionOperator
@@ -1448,41 +1101,6 @@ getReductionOperator(const Fortran::parser::ReductionOperator &op) {
llvm_unreachable("unexpected reduction operator");
}
-mlir::acc::ReductionRecipeOp Fortran::lower::createOrGetReductionRecipe(
- fir::FirOpBuilder &builder, llvm::StringRef recipeName, mlir::Location loc,
- mlir::Type ty, mlir::acc::ReductionOperator op,
- llvm::SmallVector<mlir::Value> &dataBoundOps) {
- mlir::ModuleOp mod =
- builder.getBlock()->getParent()->getParentOfType<mlir::ModuleOp>();
- if (auto recipe = mod.lookupSymbol<mlir::acc::ReductionRecipeOp>(recipeName))
- return recipe;
-
- mlir::OpBuilder::InsertionGuard guard(builder);
- bool allConstantBound = fir::acc::areAllBoundsConstant(dataBoundOps);
- auto recipe = genRecipeOp<mlir::acc::ReductionRecipeOp>(
- builder, mod, recipeName, loc, ty, dataBoundOps, allConstantBound, op);
-
- auto [dest, source] = genRecipeCombinerOrCopyRegion(
- builder, loc, ty, recipe.getCombinerRegion(), dataBoundOps,
- allConstantBound);
- llvm::SmallVector<mlir::Value> combinerBounds =
- getRecipeBounds(builder, loc, dataBoundOps,
- recipe.getCombinerRegion().getArguments().drop_front(2));
-
- auto mappableTy = mlir::dyn_cast<mlir::acc::MappableType>(ty);
- assert(mappableTy &&
- "Expected that all variable types are considered mappable");
- mlir::Attribute fastMathAttr;
- if (builder.getFastMathFlags() != mlir::arith::FastMathFlags::none)
- fastMathAttr = mlir::arith::FastMathFlagsAttr::get(
- builder.getContext(), builder.getFastMathFlags());
- [[maybe_unused]] bool success = mappableTy.generateCombiner(
- builder, loc, dest, source, combinerBounds, op, fastMathAttr);
- assert(success && "failed to generate combiner");
- mlir::acc::YieldOp::create(builder, loc, dest);
- return recipe;
-}
-
static bool isSupportedReductionType(mlir::Type ty) {
ty = fir::unwrapRefType(ty);
if (auto boxTy = mlir::dyn_cast<fir::BaseBoxType>(ty))
@@ -1553,14 +1171,13 @@ genReductions(const Fortran::parser::AccObjectListWithReduction &objectList,
mlir::acc::DataClause::acc_reduction, info.addr.getType(), async,
asyncDeviceTypes, asyncOnlyDeviceTypes, /*unwrapBoxAddr=*/true);
mlir::Type ty = op.getAccVar().getType();
- std::string recipeName = fir::acc::getRecipeName(
- mlir::acc::RecipeKind::reduction_recipe, ty, info.addr, bounds, mlirOp);
-
- mlir::acc::ReductionRecipeOp recipe =
- Fortran::lower::createOrGetReductionRecipe(
- builder, recipeName, operandLocation, ty, mlirOp, bounds);
- op.setRecipeAttr(
- mlir::SymbolRefAttr::get(builder.getContext(), recipe.getSymName()));
+ mlir::Attribute fastMathAttr;
+ if (builder.getFastMathFlags() != mlir::arith::FastMathFlags::none)
+ fastMathAttr = mlir::arith::FastMathFlagsAttr::get(
+ builder.getContext(), builder.getFastMathFlags());
+ mlir::SymbolRefAttr recipe = fir::acc::createOrGetReductionRecipe(
+ builder, operandLocation, ty, mlirOp, bounds, fastMathAttr);
+ op.setRecipeAttr(recipe);
reductionOperands.push_back(op.getAccVar());
// Track the symbol and its corresponding mlir::Value if requested so that
// accesses inside the compute/loop regions use the acc.reduction variable.
@@ -1804,8 +1421,8 @@ static void privatizeIv(
if (privateOp == nullptr) {
llvm::SmallVector<mlir::Value> noBounds;
- mlir::SymbolRefAttr recipe = createOrGetRecipe(
- builder, loc, mlir::acc::RecipeKind::private_recipe, ivValue, noBounds);
+ mlir::SymbolRefAttr recipe = fir::acc::createOrGetPrivateRecipe(
+ builder, loc, ivValue.getType(), noBounds);
std::stringstream asFortran;
asFortran << Fortran::lower::mangle::demangleName(toStringRef(sym.name()));
diff --git a/flang/lib/Optimizer/OpenACC/Support/FIROpenACCUtils.cpp b/flang/lib/Optimizer/OpenACC/Support/FIROpenACCUtils.cpp
index b88936426657d..322577f8014fc 100644
--- a/flang/lib/Optimizer/OpenACC/Support/FIROpenACCUtils.cpp
+++ b/flang/lib/Optimizer/OpenACC/Support/FIROpenACCUtils.cpp
@@ -11,6 +11,9 @@
//===----------------------------------------------------------------------===//
#include "flang/Optimizer/OpenACC/Support/FIROpenACCUtils.h"
+#include "flang/Optimizer/Builder/BoxValue.h"
+#include "flang/Optimizer/Builder/Complex.h"
+#include "flang/Optimizer/Builder/FIRBuilder.h"
#include "flang/Optimizer/Dialect/FIROps.h"
#include "flang/Optimizer/Dialect/FIROpsSupport.h"
#include "flang/Optimizer/Dialect/FIRType.h"
@@ -18,7 +21,9 @@
#include "flang/Optimizer/Dialect/Support/KindMapping.h"
#include "flang/Optimizer/HLFIR/HLFIROps.h"
#include "flang/Optimizer/Support/InternalNames.h"
+#include "mlir/Dialect/Arith/IR/Arith.h"
#include "mlir/Dialect/OpenACC/OpenACC.h"
+#include "mlir/Dialect/OpenACC/OpenACCUtils.h"
#include "mlir/IR/Matchers.h"
#include "mlir/Interfaces/ViewLikeInterface.h"
#include "llvm/ADT/TypeSwitch.h"
@@ -26,10 +31,10 @@
using namespace mlir;
-namespace fir {
-namespace acc {
+static constexpr llvm::StringRef accPrivateInitName = "acc.private.init";
+static constexpr llvm::StringRef accReductionInitName = "acc.reduction.init";
-std::string getVariableName(Value v, bool preferDemangledName) {
+std::string fir::acc::getVariableName(Value v, bool preferDemangledName) {
std::string srcName;
std::string prefix;
llvm::SmallVector<std::string, 4> arrayIndices;
@@ -149,7 +154,7 @@ std::string getVariableName(Value v, bool preferDemangledName) {
// Fallback to the default implementation.
if (srcName.empty())
- return acc::getVariableName(v);
+ return mlir::acc::getVariableName(v);
// Build array index suffix if present
std::string suffix;
@@ -171,7 +176,7 @@ std::string getVariableName(Value v, bool preferDemangledName) {
return prefix + srcName + suffix;
}
-bool areAllBoundsConstant(llvm::ArrayRef<Value> bounds) {
+bool fir::acc::areAllBoundsConstant(llvm::ArrayRef<Value> bounds) {
for (auto bound : bounds) {
auto dataBound =
mlir::dyn_cast<mlir::acc::DataBoundsOp>(bound.getDefiningOp());
@@ -224,9 +229,11 @@ static std::string getBoundsString(llvm::ArrayRef<Value> bounds) {
return os.str();
}
-std::string getRecipeName(mlir::acc::RecipeKind kind, Type type, Value var,
- llvm::ArrayRef<Value> bounds,
- mlir::acc::ReductionOperator reductionOp) {
+static std::string getRecipeName(mlir::acc::RecipeKind kind, Type type,
+ const fir::KindMapping &kindMap,
+ llvm::ArrayRef<Value> bounds,
+ mlir::acc::ReductionOperator reductionOp =
+ mlir::acc::ReductionOperator::AccNone) {
assert(fir::isa_fir_type(type) && "getRecipeName expects a FIR type");
// Build the complete prefix with all components before calling
@@ -253,11 +260,374 @@ std::string getRecipeName(mlir::acc::RecipeKind kind, Type type, Value var,
if (!bounds.empty())
prefixOS << getBoundsString(bounds);
+ return fir::getTypeAsString(type, kindMap, prefixOS.str());
+}
+
+std::string fir::acc::getRecipeName(mlir::acc::RecipeKind kind, Type type,
+ Value var, llvm::ArrayRef<Value> bounds,
+ mlir::acc::ReductionOperator reductionOp) {
auto kindMap = var && var.getDefiningOp()
? fir::getKindMapping(var.getDefiningOp())
: fir::KindMapping(type.getContext());
- return fir::getTypeAsString(type, kindMap, prefixOS.str());
+ return ::getRecipeName(kind, type, kindMap, bounds, reductionOp);
+}
+
+/// 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");
}
-} // namespace acc
-} // namespace fir
+/// 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>;
+
+// 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};
+}
+
+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::SymbolRefAttr
+fir::acc::createOrGetPrivateRecipe(mlir::OpBuilder &mlirBuilder,
+ mlir::Location loc, mlir::Type ty,
+ llvm::SmallVector<mlir::Value> &bounds) {
+ mlir::ModuleOp mod =
+ mlirBuilder.getBlock()->getParent()->getParentOfType<mlir::ModuleOp>();
+ fir::FirOpBuilder builder(mlirBuilder, mod);
+ std::string recipeName = ::getRecipeName(
+ mlir::acc::RecipeKind::private_recipe, ty, builder.getKindMap(), bounds);
+ if (auto recipe = mod.lookupSymbol<mlir::acc::PrivateRecipeOp>(recipeName))
+ return mlir::SymbolRefAttr::get(builder.getContext(), recipe.getSymName());
+
+ mlir::OpBuilder::InsertionGuard guard(builder);
+ bool allConstantBound = fir::acc::areAllBoundsConstant(bounds);
+ auto recipe = genRecipeOp<mlir::acc::PrivateRecipeOp>(
+ builder, mod, recipeName, loc, ty, bounds, allConstantBound);
+ return mlir::SymbolRefAttr::get(builder.getContext(), recipe.getSymName());
+}
+
+mlir::SymbolRefAttr fir::acc::createOrGetFirstprivateRecipe(
+ mlir::OpBuilder &mlirBuilder, mlir::Location loc, mlir::Type ty,
+ llvm::SmallVector<mlir::Value> &dataBoundOps) {
+ mlir::ModuleOp mod =
+ mlirBuilder.getBlock()->getParent()->getParentOfType<mlir::ModuleOp>();
+ fir::FirOpBuilder builder(mlirBuilder, mod);
+ std::string recipeName =
+ ::getRecipeName(mlir::acc::RecipeKind::firstprivate_recipe, ty,
+ builder.getKindMap(), dataBoundOps);
+ if (auto recipe =
+ mod.lookupSymbol<mlir::acc::FirstprivateRecipeOp>(recipeName))
+ return mlir::SymbolRefAttr::get(builder.getContext(), recipe.getSymName());
+
+ 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 mlir::SymbolRefAttr::get(builder.getContext(), recipe.getSymName());
+}
+
+mlir::SymbolRefAttr fir::acc::createOrGetReductionRecipe(
+ mlir::OpBuilder &mlirBuilder, mlir::Location loc, mlir::Type ty,
+ mlir::acc::ReductionOperator op,
+ llvm::SmallVector<mlir::Value> &dataBoundOps,
+ mlir::Attribute fastMathAttr) {
+ mlir::ModuleOp mod =
+ mlirBuilder.getBlock()->getParent()->getParentOfType<mlir::ModuleOp>();
+ fir::FirOpBuilder builder(mlirBuilder, mod);
+ std::string recipeName =
+ ::getRecipeName(mlir::acc::RecipeKind::reduction_recipe, ty,
+ builder.getKindMap(), dataBoundOps, op);
+ if (auto recipe = mod.lookupSymbol<mlir::acc::ReductionRecipeOp>(recipeName))
+ return mlir::SymbolRefAttr::get(builder.getContext(), recipe.getSymName());
+
+ mlir::OpBuilder::InsertionGuard guard(builder);
+ bool allConstantBound = fir::acc::areAllBoundsConstant(dataBoundOps);
+ auto recipe = genRecipeOp<mlir::acc::ReductionRecipeOp>(
+ builder, mod, recipeName, loc, ty, dataBoundOps, allConstantBound, op);
+
+ auto [dest, source] = genRecipeCombinerOrCopyRegion(
+ builder, loc, ty, recipe.getCombinerRegion(), dataBoundOps,
+ allConstantBound);
+ llvm::SmallVector<mlir::Value> combinerBounds =
+ getRecipeBounds(builder, loc, dataBoundOps,
+ recipe.getCombinerRegion().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.generateCombiner(
+ builder, loc, dest, source, combinerBounds, op, fastMathAttr);
+ assert(success && "failed to generate combiner");
+ mlir::acc::YieldOp::create(builder, loc, dest);
+ return mlir::SymbolRefAttr::get(builder.getContext(), recipe.getSymName());
+}
More information about the flang-commits
mailing list