[llvm-branch-commits] [flang] 2162da3 - [flang][OpenMP] Revert array element reduction lowering
Douglas Yung via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Thu Aug 20 13:45:55 PDT 2026
Author: Tom Eccles
Date: 2026-08-20T20:43:18Z
New Revision: 2162da3e360fe0df54e96e992f2e0045369dca40
URL: https://github.com/llvm/llvm-project/commit/2162da3e360fe0df54e96e992f2e0045369dca40
DIFF: https://github.com/llvm/llvm-project/commit/2162da3e360fe0df54e96e992f2e0045369dca40.diff
LOG: [flang][OpenMP] Revert array element reduction lowering
Revert #196094 and its follow-up #209701. The expression override
mechanism does not preserve reduction-object identity across all data
environments, leading to incorrect lowering for procedure-local and
nested private arrays.
Restore the pre-#196094 lowering. Keep coverage showing that
array-element constructs compile through the boxed-array reduction
path.
This was in response to this comment:
https://github.com/llvm/llvm-project/pull/196094#issuecomment-5248085956
Fixing exactly the bug in the comment wasn't hard but AI code review
found a large number of follow on bugs so I think the design needs a
rethink, and definitely shouldn't be included in the LLVM release.
Assisted-by: Codex
Added:
Modified:
flang/include/flang/Lower/Support/ReductionProcessor.h
flang/lib/Lower/Bridge.cpp
flang/lib/Lower/ConvertExprToHLFIR.cpp
flang/lib/Lower/OpenMP/ClauseProcessor.cpp
flang/lib/Lower/OpenMP/DataSharingProcessor.cpp
flang/lib/Lower/OpenMP/DataSharingProcessor.h
flang/lib/Lower/OpenMP/OpenMP.cpp
flang/lib/Lower/Support/ReductionProcessor.cpp
flang/test/Lower/OpenMP/reduction-array-element.f90
Removed:
flang/test/Lower/OpenMP/reduction-array-section.f90
################################################################################
diff --git a/flang/include/flang/Lower/Support/ReductionProcessor.h b/flang/include/flang/Lower/Support/ReductionProcessor.h
index 7173fa9e33a31..a949da875b3a2 100644
--- a/flang/include/flang/Lower/Support/ReductionProcessor.h
+++ b/flang/include/flang/Lower/Support/ReductionProcessor.h
@@ -13,7 +13,6 @@
#ifndef FORTRAN_LOWER_REDUCTIONPROCESSOR_H
#define FORTRAN_LOWER_REDUCTIONPROCESSOR_H
-#include "flang/Lower/AbstractConverter.h"
#include "flang/Lower/OpenMP/Clauses.h"
#include "flang/Optimizer/Builder/FIRBuilder.h"
#include "flang/Optimizer/Dialect/FIRType.h"
@@ -22,7 +21,6 @@
#include "flang/Semantics/type.h"
#include "mlir/IR/Location.h"
#include "mlir/IR/Types.h"
-#include "llvm/ADT/ArrayRef.h"
namespace mlir {
namespace omp {
@@ -170,16 +168,8 @@ class ReductionProcessor {
llvm::SmallVectorImpl<bool> &reduceVarByRef,
llvm::SmallVectorImpl<mlir::Attribute> &reductionDeclSymbols,
const llvm::SmallVectorImpl<const semantics::Symbol *> &reductionSymbols,
- llvm::ArrayRef<Object> reductionObjects, lower::SymMap &symMap,
llvm::DenseMap<const semantics::Symbol *, mlir::Value>
*reductionVarCache = nullptr);
-
- /// Check if an expression is lowered as a Reduction object. This ensures
- /// reductions such as Array Elements are properly represented, rather than
- /// reducing the full array.
- // TODO support more types of objects
- // to avoid Reduction clauses being represented in FIR as full arrays.
- static bool isExpressionLoweredAsReductionObject(const Object *object);
};
template <typename FloatOp, typename IntegerOp>
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index e2c895351c977..f527e807f935c 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -2416,8 +2416,7 @@ class FirConverter : public Fortran::lower::AbstractConverter {
Fortran::lower::omp::ReductionProcessor rp;
bool result = rp.processReductionArguments<fir::DeclareReductionOp>(
toLocation(), *this, info.reduceOperatorList, reduceVars,
- reduceVarByRef, reductionDeclSymbols, info.reduceSymList,
- /*reductionObjects=*/{}, getSymbolMap());
+ reduceVarByRef, reductionDeclSymbols, info.reduceSymList);
if (!result)
TODO(toLocation(), "Lowering unrecognised reduction type");
diff --git a/flang/lib/Lower/ConvertExprToHLFIR.cpp b/flang/lib/Lower/ConvertExprToHLFIR.cpp
index 6f718a8eb5926..bac7b6cbd2a89 100644
--- a/flang/lib/Lower/ConvertExprToHLFIR.cpp
+++ b/flang/lib/Lower/ConvertExprToHLFIR.cpp
@@ -975,20 +975,11 @@ class HlfirDesignatorBuilder {
mlir::Location loc;
};
-static mlir::Value
-findOverriddenExprValue(const Fortran::lower::ExprToValueMap &map,
- const Fortran::lower::SomeExpr &expr);
-
hlfir::EntityWithAttributes HlfirDesignatorBuilder::genDesignatorExpr(
const Fortran::lower::SomeExpr &designatorExpr,
bool vectorSubscriptDesignatorToValue) {
// Expr<SomeType> plumbing to unwrap Designator<T> and call
// gen(Designator<T>.u).
- if (const Fortran::lower::ExprToValueMap *map =
- getConverter().getExprOverrides()) {
- if (mlir::Value value = findOverriddenExprValue(*map, designatorExpr))
- return hlfir::EntityWithAttributes{value};
- }
return Fortran::common::visit(
[&](const auto &x) -> hlfir::EntityWithAttributes {
using T = std::decay_t<decltype(x)>;
@@ -1561,30 +1552,6 @@ static bool hasDeferredCharacterLength(const Fortran::semantics::Symbol &sym) {
type->characterTypeSpec().length().isDeferred();
}
-static mlir::Value
-findOverriddenExprValue(const Fortran::lower::ExprToValueMap &map,
- const Fortran::lower::SomeExpr &expr) {
- if (auto match = map.find(&expr); match != map.end())
- return match->second;
-
- // The map uses pointer identity, but the some expressions
- // (e.g. a(2)) may appear at multiple AST nodes with
diff erent addresses.
- // Fall back to structural comparison via ArrayRef::operator==.
- for (auto [key, value] : map) {
- if (Fortran::lower::isEqual(key, &expr))
- return value;
- auto keyRef = Fortran::evaluate::ExtractDataRef(*key);
- auto exprRef = Fortran::evaluate::ExtractDataRef(expr);
- if (keyRef && exprRef) {
- auto *keyArray = std::get_if<Fortran::evaluate::ArrayRef>(&keyRef->u);
- auto *exprArray = std::get_if<Fortran::evaluate::ArrayRef>(&exprRef->u);
- if (keyArray && exprArray && *keyArray == *exprArray)
- return value;
- }
- }
- return {};
-}
-
/// Lower Expr to HLFIR.
class HlfirBuilder {
public:
@@ -1598,12 +1565,12 @@ class HlfirBuilder {
if (const Fortran::lower::ExprToValueMap *map =
getConverter().getExprOverrides()) {
if constexpr (std::is_same_v<T, Fortran::evaluate::SomeType>) {
- if (mlir::Value value = findOverriddenExprValue(*map, expr))
- return hlfir::EntityWithAttributes{value};
+ if (auto match = map->find(&expr); match != map->end())
+ return hlfir::EntityWithAttributes{match->second};
} else {
Fortran::lower::SomeExpr someExpr = toEvExpr(expr);
- if (mlir::Value value = findOverriddenExprValue(*map, someExpr))
- return hlfir::EntityWithAttributes{value};
+ if (auto match = map->find(&someExpr); match != map->end())
+ return hlfir::EntityWithAttributes{match->second};
}
}
return Fortran::common::visit([&](const auto &x) { return gen(x); },
@@ -1645,12 +1612,6 @@ class HlfirBuilder {
template <typename T>
hlfir::EntityWithAttributes
gen(const Fortran::evaluate::Designator<T> &designator) {
- if (const Fortran::lower::ExprToValueMap *map =
- getConverter().getExprOverrides()) {
- Fortran::lower::SomeExpr someExpr = toEvExpr(designator);
- if (mlir::Value value = findOverriddenExprValue(*map, someExpr))
- return hlfir::EntityWithAttributes{value};
- }
return HlfirDesignatorBuilder(getLoc(), getConverter(), getSymMap(),
getStmtCtx())
.gen(designator.u);
diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
index 26438ef968008..cfa3673a56f08 100644
--- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
+++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
@@ -1680,7 +1680,7 @@ bool ClauseProcessor::processInReduction(
currentLocation, converter,
std::get<typename omp::clause::ReductionOperatorList>(clause.t),
inReductionVars, inReduceVarByRef, inReductionDeclSymbols,
- inReductionSyms, inReductionObjects, converter.getSymbolMap()))
+ inReductionSyms))
TODO(currentLocation, "Lowering unrecognised reduction type");
// Copy local lists into the output.
@@ -2098,8 +2098,7 @@ bool ClauseProcessor::processReduction(
currentLocation, converter,
std::get<typename omp::clause::ReductionOperatorList>(clause.t),
reductionVars, reduceVarByRef, reductionDeclSymbols,
- reductionSyms, reductionObjects, converter.getSymbolMap(),
- reductionVarCache))
+ reductionSyms, reductionVarCache))
TODO(currentLocation, "Lowering unrecognised reduction type");
// Copy local lists into the output.
llvm::copy(reductionVars, std::back_inserter(result.reductionVars));
@@ -2128,8 +2127,7 @@ bool ClauseProcessor::processTaskReduction(
currentLocation, converter,
std::get<typename omp::clause::ReductionOperatorList>(clause.t),
taskReductionVars, taskReduceVarByRef, taskReductionDeclSymbols,
- taskReductionSyms, taskReductionObjects,
- converter.getSymbolMap()))
+ taskReductionSyms))
TODO(currentLocation, "Lowering unrecognised reduction type");
// Copy local lists into the output.
llvm::copy(taskReductionVars,
diff --git a/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp b/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp
index 401c039f43973..5f7d2b16d74d4 100644
--- a/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp
+++ b/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp
@@ -66,30 +66,27 @@ DataSharingProcessor::DataSharingProcessor(
lower::AbstractConverter &converter, semantics::SemanticsContext &semaCtx,
const List<Clause> &clauses, lower::pft::Evaluation &eval,
bool shouldCollectPreDeterminedSymbols, bool useDelayedPrivatization,
- lower::SymMap &symTable, bool isTargetPrivatization,
- llvm::ArrayRef<const semantics::Symbol *> symbolsCoveredByReductionElements)
+ lower::SymMap &symTable, bool isTargetPrivatization)
: converter(converter), semaCtx(semaCtx),
firOpBuilder(converter.getFirOpBuilder()), clauses(clauses), eval(eval),
shouldCollectPreDeterminedSymbols(shouldCollectPreDeterminedSymbols),
useDelayedPrivatization(useDelayedPrivatization), symTable(symTable),
isTargetPrivatization(isTargetPrivatization), visitor(semaCtx) {
- this->symbolsCoveredByReductionElements.insert(
- symbolsCoveredByReductionElements.begin(),
- symbolsCoveredByReductionElements.end());
eval.visit([&](const auto &functionParserNode) {
parser::Walk(functionParserNode, visitor);
});
}
-DataSharingProcessor::DataSharingProcessor(
- lower::AbstractConverter &converter, semantics::SemanticsContext &semaCtx,
- lower::pft::Evaluation &eval, bool useDelayedPrivatization,
- lower::SymMap &symTable, bool isTargetPrivatization,
- llvm::ArrayRef<const semantics::Symbol *> symbolsCoveredByReductionElements)
- : DataSharingProcessor(
- converter, semaCtx, {}, eval,
- /*shouldCollectPreDeterminedSymols=*/false, useDelayedPrivatization,
- symTable, isTargetPrivatization, symbolsCoveredByReductionElements) {}
+DataSharingProcessor::DataSharingProcessor(lower::AbstractConverter &converter,
+ semantics::SemanticsContext &semaCtx,
+ lower::pft::Evaluation &eval,
+ bool useDelayedPrivatization,
+ lower::SymMap &symTable,
+ bool isTargetPrivatization)
+ : DataSharingProcessor(converter, semaCtx, {}, eval,
+ /*shouldCollectPreDeterminedSymols=*/false,
+ useDelayedPrivatization, symTable,
+ isTargetPrivatization) {}
void DataSharingProcessor::processStep1(
mlir::omp::PrivateClauseOps *clauseOps,
@@ -289,20 +286,6 @@ void DataSharingProcessor::collectSymbolsForPrivatization() {
allPrivatizedSymbols.insert(sym);
}
-bool DataSharingProcessor::isCoveredByReductionElement(
- const semantics::Symbol *sym) const {
- if (symbolsCoveredByReductionElements.contains(sym) ||
- symbolsCoveredByReductionElements.contains(&sym->GetUltimate()))
- return true;
-
- if (const auto *hostAssoc = sym->detailsIf<semantics::HostAssocDetails>())
- return symbolsCoveredByReductionElements.contains(&hostAssoc->symbol()) ||
- symbolsCoveredByReductionElements.contains(
- &hostAssoc->symbol().GetUltimate());
-
- return false;
-}
-
bool DataSharingProcessor::needBarrier() {
// Emit implicit barrier to synchronize threads and avoid data races on
// initialization of firstprivate variables and post-update of lastprivate
@@ -519,11 +502,6 @@ void DataSharingProcessor::collectPrivatizedSymbols(
return false;
if (collectImplicit) {
- // If all uses of a privatisaed variable are covered by an expr in a
- // reduction clause, these should be ignored.
- if (isCoveredByReductionElement(sym))
- return false;
-
// If we're a combined construct with a target region, implicit
// firstprivate captures, should only belong to the target region
// and not be added/captured by later directives. Parallel regions
diff --git a/flang/lib/Lower/OpenMP/DataSharingProcessor.h b/flang/lib/Lower/OpenMP/DataSharingProcessor.h
index 01a25e041ef15..a9b57cada9d92 100644
--- a/flang/lib/Lower/OpenMP/DataSharingProcessor.h
+++ b/flang/lib/Lower/OpenMP/DataSharingProcessor.h
@@ -19,8 +19,6 @@
#include "flang/Parser/parse-tree.h"
#include "flang/Semantics/symbol.h"
#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/SmallPtrSet.h"
#include <variant>
namespace mlir {
@@ -109,8 +107,6 @@ class DataSharingProcessor {
bool useDelayedPrivatization;
bool forceHeapAllocationForPrivateDynamicArrays = false;
llvm::SmallPtrSet<const semantics::Symbol *, 16> mightHaveReadHostSym;
- llvm::SmallPtrSet<const semantics::Symbol *, 4>
- symbolsCoveredByReductionElements;
lower::SymMap &symTable;
bool isTargetPrivatization;
OMPConstructSymbolVisitor visitor;
@@ -131,7 +127,6 @@ class DataSharingProcessor {
const omp::ObjectList &objects,
llvm::SetVector<const semantics::Symbol *> &symbolSet);
void collectSymbolsForPrivatization();
- bool isCoveredByReductionElement(const semantics::Symbol *sym) const;
void insertBarrier(mlir::omp::PrivateClauseOps *clauseOps);
void collectDefaultSymbols();
void collectImplicitSymbols();
@@ -160,17 +155,13 @@ class DataSharingProcessor {
lower::pft::Evaluation &eval,
bool shouldCollectPreDeterminedSymbols,
bool useDelayedPrivatization, lower::SymMap &symTable,
- bool isTargetPrivatization = false,
- llvm::ArrayRef<const semantics::Symbol *>
- symbolsCoveredByReductionElements = {});
+ bool isTargetPrivatization = false);
DataSharingProcessor(lower::AbstractConverter &converter,
semantics::SemanticsContext &semaCtx,
lower::pft::Evaluation &eval,
bool useDelayedPrivatization, lower::SymMap &symTable,
- bool isTargetPrivatization = false,
- llvm::ArrayRef<const semantics::Symbol *>
- symbolsCoveredByReductionElements = {});
+ bool isTargetPrivatization = false);
// Privatisation is split into two steps.
// Step1 performs cloning of all privatisation clauses and copying for
diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index ed3e989daab7e..eb1c0d7be5f67 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -834,31 +834,18 @@ static void bindEntryBlockArgs(lower::AbstractConverter &converter,
llvm::ArrayRef<mlir::Value> vars,
llvm::ArrayRef<mlir::BlockArgument> args) {
llvm::SmallVector<const semantics::Symbol *> processedSyms;
- llvm::SmallVector<const Object *> processedObjects;
for (const Object &object : objects) {
const semantics::Symbol *sym = object.sym();
if (const auto *commonDet =
sym->detailsIf<semantics::CommonBlockDetails>()) {
- for (auto &mem : commonDet->objects()) {
- processedSyms.push_back(&*mem);
- processedObjects.push_back(&object);
- }
+ llvm::transform(commonDet->objects(), std::back_inserter(processedSyms),
+ [&](const auto &mem) { return &*mem; });
} else {
processedSyms.push_back(sym);
- processedObjects.push_back(&object);
}
}
- assert(processedSyms.size() == processedObjects.size());
- for (auto [sym, var, arg, object] :
- llvm::zip_equal(processedSyms, vars, args, processedObjects)) {
- bool skipBind =
- ReductionProcessor::isExpressionLoweredAsReductionObject(object) ||
- (object && sym->Rank() > 0 &&
- !fir::unwrapUntilSeqType(arg.getType()));
- if (skipBind)
- continue;
-
+ for (auto [sym, var, arg] : llvm::zip_equal(processedSyms, vars, args))
converter.bindSymbol(
*sym,
hlfir::translateToExtendedValue(
@@ -866,7 +853,6 @@ static void bindEntryBlockArgs(lower::AbstractConverter &converter,
/*contiguousHint=*/
evaluate::IsSimplyContiguous(*sym, converter.getFoldingContext()))
.first);
- }
};
// Process in clause name alphabetical order to match block arguments order.
@@ -1343,44 +1329,13 @@ genLoopVars(mlir::Operation *op, lower::AbstractConverter &converter,
// next one would result in 'hlfir.declare' operations being introduced inside
// of a wrapper, which is illegal.
mlir::IRMapping mapper;
- llvm::SmallVector<std::pair<Object, mlir::Value>> mappedReductionObjects;
- auto mapEquivalentReductionObjects =
- [&](const ObjectEntryBlockArgsEntry &entry) {
- for (auto [object, var] : llvm::zip(entry.objects, entry.vars)) {
- for (auto [mappedObject, mappedValue] :
- llvm::reverse(mappedReductionObjects)) {
- if (object.id() == mappedObject.id()) {
- mapper.map(var, mappedValue);
- break;
- }
- }
- }
- };
- auto rememberReductionObjects =
- [&](const ObjectEntryBlockArgsEntry &entry,
- llvm::ArrayRef<mlir::BlockArgument> args) {
- for (auto [object, arg] : llvm::zip(entry.objects, args))
- mappedReductionObjects.emplace_back(object, arg);
- };
-
for (auto [argGeneratingOp, blockArgs] : wrapperArgs) {
- mapEquivalentReductionObjects(blockArgs.inReduction);
- mapEquivalentReductionObjects(blockArgs.reduction);
- mapEquivalentReductionObjects(blockArgs.taskReduction);
-
for (mlir::OpOperand &operand : argGeneratingOp->getOpOperands())
operand.set(mapper.lookupOrDefault(operand.get()));
for (const auto [arg, var] : llvm::zip_equal(
argGeneratingOp->getRegion(0).getArguments(), blockArgs.getVars()))
mapper.map(var, arg);
-
- rememberReductionObjects(blockArgs.inReduction,
- argGeneratingOp.getInReductionBlockArgs());
- rememberReductionObjects(blockArgs.reduction,
- argGeneratingOp.getReductionBlockArgs());
- rememberReductionObjects(blockArgs.taskReduction,
- argGeneratingOp.getTaskReductionBlockArgs());
}
// Bind the entry block arguments of parent wrappers to the corresponding
@@ -1653,186 +1608,6 @@ struct OpWithBodyGenInfo {
bool privatize = true;
};
-static mlir::Value getReductionOverrideValue(fir::FirOpBuilder &builder,
- mlir::Location loc,
- const Object *object,
- mlir::BlockArgument arg) {
- if (hlfir::isFortranEntityWithAttributes(arg))
- return arg;
-
- fir::FortranVariableFlagsAttr attributes;
- llvm::SmallVector<mlir::Value> typeParams;
- auto declareOp = hlfir::DeclareOp::create(
- builder, loc, arg, "omp.reduction.element", nullptr, typeParams, nullptr,
- nullptr, 0, attributes);
- return declareOp.getBase();
-}
-
-static void
-addReductionObjectOverrides(fir::FirOpBuilder &builder, mlir::Location loc,
- lower::ExprToValueMap &overrides,
- const ObjectEntryBlockArgsEntry &entry,
- llvm::ArrayRef<mlir::BlockArgument> blockArgs) {
- if (entry.objects.empty())
- return;
-
- for (auto pair : llvm::zip_equal(entry.objects, blockArgs)) {
- const Object &object = std::get<0>(pair);
- const mlir::BlockArgument &arg = std::get<1>(pair);
- if (!ReductionProcessor::isExpressionLoweredAsReductionObject(&object))
- continue;
- const SomeExpr *expr = &object.ref().value();
-
- // Evict any outer-scope entry for the same array element so the
- // innermost scope always wins regardless of DenseMap iteration order.
- llvm::SmallVector<const SomeExpr *> toEvict;
- for (auto [key, value] : overrides) {
- if (Fortran::lower::isEqual(key, expr)) {
- toEvict.push_back(key);
- }
- }
- for (const SomeExpr *key : toEvict) {
- overrides.erase(key);
- }
-
- overrides[expr] = getReductionOverrideValue(builder, loc, &object, arg);
- }
-}
-
-static const semantics::Symbol *getArrayElementSymbol(const SomeExpr &expr) {
- std::optional<Fortran::evaluate::DataRef> dataRef =
- Fortran::evaluate::ExtractDataRef(expr);
- if (!dataRef)
- return nullptr;
-
- if (const auto *arrayRef =
- std::get_if<Fortran::evaluate::ArrayRef>(&dataRef->u))
- return &arrayRef->GetLastSymbol();
-
- return nullptr;
-}
-
-static void
-addSymbolAliases(llvm::SmallVectorImpl<const semantics::Symbol *> &aliases,
- const semantics::Symbol *symbol) {
- aliases.push_back(symbol);
- aliases.push_back(&symbol->GetUltimate());
- if (const auto *hostAssoc =
- symbol->detailsIf<semantics::HostAssocDetails>()) {
- aliases.push_back(&hostAssoc->symbol());
- aliases.push_back(&hostAssoc->symbol().GetUltimate());
- }
-}
-
-struct ArrayElementReductionUseCollector {
- explicit ArrayElementReductionUseCollector(
- const llvm::DenseMap<const semantics::Symbol *, const semantics::Symbol *>
- &aliasToReductionSymbol,
- llvm::DenseMap<const semantics::Symbol *,
- llvm::SmallVector<const SomeExpr *>>
- &reductionElementExprs)
- : aliasToReductionSymbol(aliasToReductionSymbol),
- reductionElementExprs(reductionElementExprs) {}
-
- const llvm::DenseMap<const semantics::Symbol *, const semantics::Symbol *>
- &aliasToReductionSymbol;
- llvm::DenseMap<const semantics::Symbol *, llvm::SmallVector<const SomeExpr *>>
- &reductionElementExprs;
- llvm::SmallPtrSet<const semantics::Symbol *, 16> seen;
- llvm::SmallPtrSet<const semantics::Symbol *, 16> uncovered;
-
- void classifyReductionElementUses(const SomeExpr &expr) {
- llvm::SmallPtrSet<const semantics::Symbol *, 4> exprCandidates;
- auto getReductionSymbol = [this](const semantics::Symbol &symbol) {
- auto it = aliasToReductionSymbol.find(&symbol);
- return it == aliasToReductionSymbol.end() ? nullptr : it->second;
- };
- for (const semantics::Symbol &symbol :
- Fortran::evaluate::CollectSymbols(expr))
- if (const semantics::Symbol *reductionSymbol = getReductionSymbol(symbol))
- exprCandidates.insert(reductionSymbol);
- if (exprCandidates.empty())
- return;
-
- auto isCoveredReductionUse =
- [this](const semantics::Symbol *reductionSymbol, const SomeExpr &expr) {
- auto it = reductionElementExprs.find(reductionSymbol);
- return it != reductionElementExprs.end() &&
- llvm::any_of(it->second, [&](const SomeExpr *reductionExpr) {
- return Fortran::lower::isEqual(&expr, reductionExpr);
- });
- };
- llvm::SmallPtrSet<const semantics::Symbol *, 4> seenInExpr;
- for (const SomeExpr &designator :
- semantics::omp::GetTopLevelDesignators(expr)) {
- const semantics::Symbol *symbol = getArrayElementSymbol(designator);
- const semantics::Symbol *reductionSymbol =
- symbol ? getReductionSymbol(*symbol) : nullptr;
- if (!reductionSymbol)
- continue;
-
- if (isCoveredReductionUse(reductionSymbol, designator)) {
- seen.insert(reductionSymbol);
- seenInExpr.insert(reductionSymbol);
- } else {
- uncovered.insert(reductionSymbol);
- }
- }
-
- for (const semantics::Symbol *symbol : exprCandidates)
- if (!seenInExpr.contains(symbol))
- uncovered.insert(symbol);
- }
-
- template <typename T>
- bool Pre(const T &node) {
- if constexpr (parser::HasTypedExpr<T>::value) {
- if (const SomeExpr *expr = semantics::GetExpr(nullptr, node)) {
- classifyReductionElementUses(*expr);
- return false;
- }
- }
- return true;
- }
-
- bool Pre(const parser::Name &name) { return false; }
-
- template <typename T>
- void Post(const T &) {}
-};
-
-static llvm::SmallVector<const semantics::Symbol *>
-getSymbolsCoveredByReductionElements(lower::pft::Evaluation &eval,
- llvm::ArrayRef<Object> reductionObjects) {
- llvm::DenseMap<const semantics::Symbol *, const semantics::Symbol *>
- aliasToReductionSymbol;
- llvm::DenseMap<const semantics::Symbol *, llvm::SmallVector<const SomeExpr *>>
- reductionElementExprs;
- for (const Object &object : reductionObjects) {
- if (!ReductionProcessor::isExpressionLoweredAsReductionObject(&object))
- continue;
- llvm::SmallVector<const semantics::Symbol *> aliases;
- addSymbolAliases(aliases, object.sym());
- for (const semantics::Symbol *alias : aliases)
- aliasToReductionSymbol[alias] = object.sym();
- reductionElementExprs[object.sym()].push_back(&*object.ref());
- }
-
- if (reductionElementExprs.empty())
- return {};
-
- ArrayElementReductionUseCollector collector(aliasToReductionSymbol,
- reductionElementExprs);
- eval.visit([&](const auto &node) { parser::Walk(node, collector); });
-
- llvm::SmallVector<const semantics::Symbol *> suppressList;
- for (auto &[symbol, exprs] : reductionElementExprs)
- if (collector.seen.contains(symbol) &&
- !collector.uncovered.contains(symbol))
- suppressList.push_back(symbol);
- return suppressList;
-}
-
/// Create the body (block) for an OpenMP Operation.
///
/// \param [in] op - the operation the body belongs to.
@@ -1917,27 +1692,6 @@ static void createBodyOfOp(mlir::Operation &op, const OpWithBodyGenInfo &info,
groupprivatizeVars(info.converter, info.eval);
if (!info.genSkeletonOnly) {
- lower::ExprToValueMap local;
- if (auto *old = info.converter.getExprOverrides())
- local.insert(old->begin(), old->end());
- if (info.blockArgs) {
- if (auto ompBlockArgOp =
- mlir::dyn_cast<mlir::omp::BlockArgOpenMPOpInterface>(op)) {
- addReductionObjectOverrides(firOpBuilder, info.loc, local,
- info.blockArgs->inReduction,
- ompBlockArgOp.getInReductionBlockArgs());
- addReductionObjectOverrides(firOpBuilder, info.loc, local,
- info.blockArgs->reduction,
- ompBlockArgOp.getReductionBlockArgs());
- addReductionObjectOverrides(firOpBuilder, info.loc, local,
- info.blockArgs->taskReduction,
- ompBlockArgOp.getTaskReductionBlockArgs());
- }
- }
-
- auto *old = info.converter.getExprOverrides();
- info.converter.overrideExprValues(local.empty() ? old : &local);
-
if (ConstructQueue::const_iterator next = std::next(item);
next != queue.end()) {
genOMPDispatch(info.converter, info.symTable, info.semaCtx, info.eval,
@@ -1953,8 +1707,6 @@ static void createBodyOfOp(mlir::Operation &op, const OpWithBodyGenInfo &info,
genNestedEvaluations(info.converter, info.eval);
temp->erase();
}
-
- info.converter.overrideExprValues(old);
}
// Get or create a unique exiting block from the given region, or
@@ -2776,40 +2528,21 @@ genLoopNestOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
const ObjectEntryBlockArgs &>>
wrapperArgs,
llvm::omp::Directive directive, DataSharingProcessor &dsp) {
- const lower::ExprToValueMap *oldOverrides = converter.getExprOverrides();
- lower::ExprToValueMap loopNestOverrides;
auto ivCallback = [&](mlir::Operation *op) {
genLoopVars(op, converter, loc, iv, wrapperArgs);
- if (oldOverrides)
- loopNestOverrides.insert(oldOverrides->begin(), oldOverrides->end());
- for (auto [argGeneratingOp, blockArgs] : wrapperArgs) {
- addReductionObjectOverrides(converter.getFirOpBuilder(), loc,
- loopNestOverrides, blockArgs.inReduction,
- argGeneratingOp.getInReductionBlockArgs());
- addReductionObjectOverrides(converter.getFirOpBuilder(), loc,
- loopNestOverrides, blockArgs.reduction,
- argGeneratingOp.getReductionBlockArgs());
- addReductionObjectOverrides(converter.getFirOpBuilder(), loc,
- loopNestOverrides, blockArgs.taskReduction,
- argGeneratingOp.getTaskReductionBlockArgs());
- }
- converter.overrideExprValues(
- loopNestOverrides.empty() ? oldOverrides : &loopNestOverrides);
return llvm::SmallVector<const semantics::Symbol *>(iv);
};
uint64_t nestValue = getCollapseValue(item->clauses);
nestValue = nestValue < iv.size() ? iv.size() : nestValue;
auto *nestedEval = getCollapsedLoopEval(eval, nestValue);
- auto loopNestOp = genOpWithBody<mlir::omp::LoopNestOp>(
+ return genOpWithBody<mlir::omp::LoopNestOp>(
OpWithBodyGenInfo(converter, symTable, semaCtx, loc, *nestedEval,
directive)
.setClauses(&item->clauses)
.setDataSharingProcessor(&dsp)
.setGenRegionEntryCb(ivCallback),
queue, item, clauseOps);
- converter.overrideExprValues(oldOverrides);
- return loopNestOp;
}
static mlir::omp::LoopOp
@@ -3856,14 +3589,9 @@ genTaskOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
.setClauses(&item->clauses),
queue, item, clauseOps);
- llvm::SmallVector<const semantics::Symbol *>
- symbolsCoveredByReductionElements =
- getSymbolsCoveredByReductionElements(eval, inReductionObjects);
DataSharingProcessor dsp(converter, semaCtx, item->clauses, eval,
lower::omp::isLastItemInQueue(item, queue),
- /*useDelayedPrivatization=*/true, symTable,
- /*isTargetPrivatization=*/false,
- symbolsCoveredByReductionElements);
+ /*useDelayedPrivatization=*/true, symTable);
dsp.processStep1(&clauseOps);
ObjectEntryBlockArgs taskArgs;
@@ -4126,17 +3854,9 @@ static mlir::omp::TaskloopContextOp genStandaloneTaskloop(
genTaskloopClauses(converter, semaCtx, stmtCtx, item->clauses, loc,
taskloopClauseOps, reductionObjects, inReductionObjects);
- llvm::SmallVector<Object> allReductionObjects;
- llvm::append_range(allReductionObjects, reductionObjects);
- llvm::append_range(allReductionObjects, inReductionObjects);
- llvm::SmallVector<const semantics::Symbol *>
- symbolsCoveredByReductionElements =
- getSymbolsCoveredByReductionElements(eval, allReductionObjects);
DataSharingProcessor dsp(converter, semaCtx, item->clauses, eval,
/*shouldCollectPreDeterminedSymbols=*/true,
- enableDelayedPrivatization, symTable,
- /*isTargetPrivatization=*/false,
- symbolsCoveredByReductionElements);
+ enableDelayedPrivatization, symTable);
dsp.processStep1(&taskloopClauseOps);
mlir::omp::LoopNestOperands loopNestClauseOps;
diff --git a/flang/lib/Lower/Support/ReductionProcessor.cpp b/flang/lib/Lower/Support/ReductionProcessor.cpp
index 80d34285101f1..e1b4684bd8871 100644
--- a/flang/lib/Lower/Support/ReductionProcessor.cpp
+++ b/flang/lib/Lower/Support/ReductionProcessor.cpp
@@ -13,7 +13,6 @@
#include "flang/Lower/Support/ReductionProcessor.h"
#include "flang/Lower/AbstractConverter.h"
-#include "flang/Lower/ConvertExprToHLFIR.h"
#include "flang/Lower/ConvertType.h"
#include "flang/Lower/OpenMP/Clauses.h"
#include "flang/Lower/Support/PrivateReductionUtils.h"
@@ -48,7 +47,6 @@ template bool ReductionProcessor::processReductionArguments<
llvm::SmallVectorImpl<bool> &reduceVarByRef,
llvm::SmallVectorImpl<mlir::Attribute> &reductionDeclSymbols,
const llvm::SmallVectorImpl<const semantics::Symbol *> &reductionSymbols,
- llvm::ArrayRef<Object> reductionObjects, lower::SymMap &symMap,
llvm::DenseMap<const semantics::Symbol *, mlir::Value> *reductionVarCache);
template bool ReductionProcessor::processReductionArguments<
@@ -59,7 +57,6 @@ template bool ReductionProcessor::processReductionArguments<
llvm::SmallVectorImpl<bool> &reduceVarByRef,
llvm::SmallVectorImpl<mlir::Attribute> &reductionDeclSymbols,
const llvm::SmallVectorImpl<const semantics::Symbol *> &reductionSymbols,
- llvm::ArrayRef<Object> reductionObjects, lower::SymMap &symMap,
llvm::DenseMap<const semantics::Symbol *, mlir::Value> *reductionVarCache);
template mlir::omp::DeclareReductionOp
@@ -382,18 +379,6 @@ mlir::Value ReductionProcessor::createScalarCombiner(
return reductionOp;
}
-bool ReductionProcessor::isExpressionLoweredAsReductionObject(
- const Object *object) {
- if (!object || !object->ref())
- return false;
- const SomeExpr &expr = *object->ref();
- // Only genuine single array elements (rank 0) are lowered via the element
- // path. Array sections such as a(2:96) and vector subscripts have rank > 0;
- // lowering them here produces an unsupported sequence type and aborts in
- // PrivateReductionUtils. Let them fall back to the boxed whole-array path.
- return evaluate::IsArrayElement(expr) && expr.Rank() == 0;
-}
-
template <typename ParentDeclOpType>
static void genYield(fir::FirOpBuilder &builder, mlir::Location loc,
mlir::Value yieldedValue) {
@@ -701,7 +686,6 @@ bool ReductionProcessor::processReductionArguments(
llvm::SmallVectorImpl<bool> &reduceVarByRef,
llvm::SmallVectorImpl<mlir::Attribute> &reductionDeclSymbols,
const llvm::SmallVectorImpl<const semantics::Symbol *> &reductionSymbols,
- llvm::ArrayRef<Object> reductionObjects, lower::SymMap &symMap,
llvm::DenseMap<const semantics::Symbol *, mlir::Value> *reductionVarCache) {
fir::FirOpBuilder &builder = converter.getFirOpBuilder();
@@ -748,105 +732,79 @@ bool ReductionProcessor::processReductionArguments(
builder.getRegion().getParentOfType<fir::DoConcurrentOp>());
}
- assert((reductionObjects.empty() ||
- reductionSymbols.size() == reductionObjects.size()) &&
- "mismatched reduction symbol and object lists");
-
- for (unsigned i = 0; i < reductionSymbols.size(); ++i) {
- const Object *object =
- reductionObjects.empty() ? nullptr : &reductionObjects[i];
- const semantics::Symbol *symbol =
- object ? object->sym() : reductionSymbols[i];
- const SomeExpr *expr = object && object->ref() ? &*object->ref() : nullptr;
- const bool isObjectExpr =
- ReductionProcessor::isExpressionLoweredAsReductionObject(object);
-
+ for (const semantics::Symbol *symbol : reductionSymbols) {
// If a cached reduction variable exists for this symbol, reuse it.
// This ensures that composite constructs (e.g. DO SIMD) where both
// the outer wrapper (wsloop) and inner wrapper (simd) process the same
// reduction clause share the same SSA value, enabling genLoopVars()'s
// IRMapping to correctly remap inner wrapper operands to outer wrapper
- // block arguments. Array element reductions are intentionally not cached:
- // block-argument object tracking maps their scoped uses.
- if (reductionVarCache && !isObjectExpr) {
- if (auto it = reductionVarCache->find(symbol);
- it != reductionVarCache->end()) {
+ // block arguments.
+ if (reductionVarCache) {
+ auto it = reductionVarCache->find(symbol);
+ if (it != reductionVarCache->end()) {
reductionVars.push_back(it->second);
reduceVarByRef.push_back(doReductionByRef(it->second));
continue;
}
}
- mlir::Value reductionVal;
- mlir::Type refTy;
+ mlir::Value symVal = converter.getSymbolAddress(*symbol);
+
+ if (auto declOp = symVal.getDefiningOp<hlfir::DeclareOp>())
+ symVal = declOp.getBase();
+
+ mlir::Type eleType;
+ auto refType = mlir::dyn_cast_or_null<fir::ReferenceType>(symVal.getType());
+ if (refType)
+ eleType = refType.getEleTy();
+ else
+ eleType = symVal.getType();
+
+ // all arrays must be boxed so that we have convenient access to all the
+ // information needed to iterate over the array
+ if (mlir::isa<fir::SequenceType>(eleType)) {
+ // For Host associated symbols, use `SymbolBox` instead
+ lower::SymbolBox symBox = converter.lookupOneLevelUpSymbol(*symbol);
+ hlfir::Entity entity{symBox.getAddr()};
+ entity = genVariableBox(currentLocation, builder, entity);
+ mlir::Value box = entity.getBase();
+
+ // Always pass the box by reference so that the OpenMP dialect
+ // verifiers don't need to know anything about fir.box
+ auto alloca =
+ fir::AllocaOp::create(builder, currentLocation, box.getType());
+ fir::StoreOp::create(builder, currentLocation, box, alloca);
+
+ symVal = alloca;
+ } else if (mlir::isa<fir::BaseBoxType>(symVal.getType())) {
+ // boxed arrays are passed as values not by reference. Unfortunately,
+ // we can't pass a box by value to omp.redution_declare, so turn it
+ // into a reference
+ auto oldIP = builder.saveInsertionPoint();
+ builder.setInsertionPointToStart(builder.getAllocaBlock());
+ auto alloca =
+ fir::AllocaOp::create(builder, currentLocation, symVal.getType());
+ builder.restoreInsertionPoint(oldIP);
+ fir::StoreOp::create(builder, currentLocation, symVal, alloca);
+ symVal = alloca;
+ }
- if (isObjectExpr) {
- StatementContext stmtCtx;
- hlfir::EntityWithAttributes entity = convertExprToHLFIR(
- converter.getCurrentLocation(), converter, *expr, symMap, stmtCtx);
- reductionVal = entity.getBase();
- // TODO Add support for Boxed and Sequenced types once these are supported
- refTy = reductionVal.getType();
- } else {
- mlir::Value symVal = converter.getSymbolAddress(*symbol);
-
- if (auto declOp = symVal.getDefiningOp<hlfir::DeclareOp>())
- symVal = declOp.getBase();
-
- mlir::Type eleType;
- auto refType =
- mlir::dyn_cast_or_null<fir::ReferenceType>(symVal.getType());
- if (refType)
- eleType = refType.getEleTy();
- else
- eleType = symVal.getType();
-
- // all arrays must be boxed so that we have convenient access to all the
- // information needed to iterate over the array
- if (mlir::isa<fir::SequenceType>(eleType)) {
- // For Host associated symbols, use `SymbolBox` instead
- lower::SymbolBox symBox = converter.lookupOneLevelUpSymbol(*symbol);
- hlfir::Entity entity{symBox.getAddr()};
- entity = genVariableBox(currentLocation, builder, entity);
- mlir::Value box = entity.getBase();
-
- // Always pass the box by reference so that the OpenMP dialect
- // verifiers don't need to know anything about fir.box
- auto alloca =
- fir::AllocaOp::create(builder, currentLocation, box.getType());
- fir::StoreOp::create(builder, currentLocation, box, alloca);
-
- symVal = alloca;
- } else if (mlir::isa<fir::BaseBoxType>(symVal.getType())) {
- // boxed arrays are passed as values not by reference. Unfortunately,
- // we can't pass a box by value to omp.redution_declare, so turn it
- // into a reference
- auto oldIP = builder.saveInsertionPoint();
- builder.setInsertionPointToStart(builder.getAllocaBlock());
- auto alloca =
- fir::AllocaOp::create(builder, currentLocation, symVal.getType());
- builder.restoreInsertionPoint(oldIP);
- fir::StoreOp::create(builder, currentLocation, symVal, alloca);
- symVal = alloca;
- }
+ // this isn't the same as the by-val and by-ref passing later in the
+ // pipeline. Both styles assume that the variable is a reference at
+ // this point
+ assert(fir::isa_ref_type(symVal.getType()) &&
+ "reduction input var is passed by reference");
+ mlir::Type elementType = fir::dyn_cast_ptrEleTy(symVal.getType());
+ const bool symIsVolatile = fir::isa_volatile_type(symVal.getType());
+ mlir::Type refTy = fir::ReferenceType::get(elementType, symIsVolatile);
- // this isn't the same as the by-val and by-ref passing later in the
- // pipeline. Both styles assume that the variable is a reference at
- // this point
- assert(fir::isa_ref_type(symVal.getType()) &&
- "reduction input var is passed by reference");
- mlir::Type elementType = fir::dyn_cast_ptrEleTy(symVal.getType());
- const bool symIsVolatile = fir::isa_volatile_type(symVal.getType());
- refTy = fir::ReferenceType::get(elementType, symIsVolatile);
- reductionVal = symVal;
- }
reductionVars.push_back(
- builder.createConvert(currentLocation, refTy, reductionVal));
+ builder.createConvert(currentLocation, refTy, symVal));
reduceVarByRef.push_back(doReductionByRef(reductionVars.back()));
// Cache the final SSA value for this symbol so that subsequent calls
// (e.g. for the inner wrapper in a composite construct) reuse it.
- if (reductionVarCache && !isObjectExpr)
+ if (reductionVarCache)
reductionVarCache->try_emplace(symbol, reductionVars.back());
}
diff --git a/flang/test/Lower/OpenMP/reduction-array-element.f90 b/flang/test/Lower/OpenMP/reduction-array-element.f90
index 1aabc7b54401e..f62f91a457735 100644
--- a/flang/test/Lower/OpenMP/reduction-array-element.f90
+++ b/flang/test/Lower/OpenMP/reduction-array-element.f90
@@ -1,4 +1,10 @@
-! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %s -o - | FileCheck %s --implicit-check-not=add_reduction_byref_box
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %s -o - | FileCheck %s --implicit-check-not=omp.reduction.element
+
+! Array-element reductions currently use the whole-array boxed reduction path.
+! Keep lowering coverage for these constructs so that this limitation does not
+! hide failures to compile them.
+
+! CHECK: omp.declare_reduction @[[BOX_RED:add_reduction_byref_box_4xi32]] : !fir.ref<!fir.box<!fir.array<4xi32>>>
subroutine reduction_literal(a, n)
integer :: a(4), n
@@ -9,10 +15,10 @@ subroutine reduction_literal(a, n)
end subroutine
! CHECK-LABEL: func.func @_QPreduction_literal
-! CHECK: omp.wsloop {{.*}} reduction(@add_reduction_i32 {{.*}} : !fir.ref<i32>) {
-! CHECK: hlfir.declare %arg{{[0-9]+}} {uniq_name = "omp.reduction.element"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
-! CHECK: fir.load %{{[0-9]+}}#0 : !fir.ref<i32>
-! CHECK: hlfir.assign {{.*}} to %{{[0-9]+}}#0 : i32, !fir.ref<i32>
+! CHECK: omp.wsloop {{.*}} reduction(byref @[[BOX_RED]] {{.*}} : !fir.ref<!fir.box<!fir.array<4xi32>>>) {
+! CHECK: hlfir.declare %{{.*}} {uniq_name = "_QFreduction_literalEa"} : (!fir.ref<!fir.box<!fir.array<4xi32>>>)
+! CHECK: fir.load %{{.*}} : !fir.ref<!fir.box<!fir.array<4xi32>>>
+! CHECK: hlfir.designate %{{.*}} (%c2) {{.*}} -> !fir.ref<i32>
subroutine reduction_multiple(a, n)
integer :: a(4), n
@@ -24,11 +30,9 @@ subroutine reduction_multiple(a, n)
end subroutine
! CHECK-LABEL: func.func @_QPreduction_multiple
-! CHECK: omp.wsloop {{.*}} reduction(@add_reduction_i32 {{.*}}, @add_reduction_i32 {{.*}} : !fir.ref<i32>, !fir.ref<i32>) {
-! CHECK: hlfir.declare %arg{{[0-9]+}} {uniq_name = "omp.reduction.element"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
-! CHECK: hlfir.declare %arg{{[0-9]+}} {uniq_name = "omp.reduction.element"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
-! CHECK: hlfir.assign {{.*}} to %{{[0-9]+}}#0 : i32, !fir.ref<i32>
-! CHECK: hlfir.assign {{.*}} to %{{[0-9]+}}#0 : i32, !fir.ref<i32>
+! CHECK: omp.wsloop {{.*}} reduction(byref @[[BOX_RED]] {{.*}}, byref @[[BOX_RED]] {{.*}} : !fir.ref<!fir.box<!fir.array<4xi32>>>, !fir.ref<!fir.box<!fir.array<4xi32>>>) {
+! CHECK: hlfir.designate %{{.*}} (%c2) {{.*}} -> !fir.ref<i32>
+! CHECK: hlfir.designate %{{.*}} (%c3) {{.*}} -> !fir.ref<i32>
subroutine reduction_arrays(a, b, n)
integer :: a(4), b(4), n
@@ -39,9 +43,10 @@ subroutine reduction_arrays(a, b, n)
end subroutine
! CHECK-LABEL: func.func @_QPreduction_arrays
-! CHECK: omp.wsloop {{.*}} reduction(@add_reduction_i32 {{.*}}, @add_reduction_i32 {{.*}} : !fir.ref<i32>, !fir.ref<i32>) {
-! CHECK: hlfir.declare %arg{{[0-9]+}} {uniq_name = "omp.reduction.element"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
-! CHECK: hlfir.declare %arg{{[0-9]+}} {uniq_name = "omp.reduction.element"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+! CHECK: omp.wsloop {{.*}} reduction(byref @[[BOX_RED]] {{.*}}, byref @[[BOX_RED]] {{.*}} : !fir.ref<!fir.box<!fir.array<4xi32>>>, !fir.ref<!fir.box<!fir.array<4xi32>>>) {
+! CHECK: hlfir.declare %{{.*}} {uniq_name = "_QFreduction_arraysEa"} : (!fir.ref<!fir.box<!fir.array<4xi32>>>)
+! CHECK: hlfir.declare %{{.*}} {uniq_name = "_QFreduction_arraysEb"} : (!fir.ref<!fir.box<!fir.array<4xi32>>>)
+! CHECK: hlfir.designate %{{.*}} (%c2{{.*}}) {{.*}} -> !fir.ref<i32>
subroutine reduction_variable(a, n, j)
integer :: a(4), n, j
@@ -52,9 +57,9 @@ subroutine reduction_variable(a, n, j)
end subroutine
! CHECK-LABEL: func.func @_QPreduction_variable
-! CHECK: omp.wsloop {{.*}} reduction(@add_reduction_i32 {{.*}} : !fir.ref<i32>) {
-! CHECK: hlfir.declare %arg{{[0-9]+}} {uniq_name = "omp.reduction.element"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
-! CHECK: hlfir.assign {{.*}} to %{{[0-9]+}}#0 : i32, !fir.ref<i32>
+! CHECK: omp.wsloop {{.*}} reduction(byref @[[BOX_RED]] {{.*}} : !fir.ref<!fir.box<!fir.array<4xi32>>>) {
+! CHECK: hlfir.declare %{{.*}} {uniq_name = "_QFreduction_variableEa"} : (!fir.ref<!fir.box<!fir.array<4xi32>>>)
+! CHECK: hlfir.designate %{{.*}} (%{{.*}}) {{.*}} -> !fir.ref<i32>
subroutine reduction_do_simd(a, n)
integer :: a(4), n
@@ -65,10 +70,9 @@ subroutine reduction_do_simd(a, n)
end subroutine
! CHECK-LABEL: func.func @_QPreduction_do_simd
-! CHECK: omp.wsloop reduction(@add_reduction_i32 {{.*}} -> [[WSARG:%arg[0-9]+]] : !fir.ref<i32>) {
-! CHECK: omp.simd {{.*}} reduction(@add_reduction_i32 [[WSARG]] -> [[SIMDARG:%arg[0-9]+]] : !fir.ref<i32>) {
-! CHECK: hlfir.declare [[SIMDARG]] {uniq_name = "omp.reduction.element"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
-! CHECK: hlfir.assign {{.*}} to %{{[0-9]+}}#0 : i32, !fir.ref<i32>
+! CHECK: omp.wsloop reduction(byref @[[BOX_RED]] {{.*}} -> %[[WSARG:.*]] : !fir.ref<!fir.box<!fir.array<4xi32>>>) {
+! CHECK: omp.simd {{.*}} reduction(byref @[[BOX_RED]] %[[WSARG]] -> %{{.*}} : !fir.ref<!fir.box<!fir.array<4xi32>>>) {
+! CHECK: hlfir.designate %{{.*}} (%c2) {{.*}} -> !fir.ref<i32>
subroutine task_reduction_element(a)
integer :: a(4)
@@ -80,13 +84,9 @@ subroutine task_reduction_element(a)
end subroutine
! CHECK-LABEL: func.func @_QPtask_reduction_element
-! CHECK-NOT: _QFtask_reduction_elementEa_firstprivate_box_4xi32
-! CHECK: omp.taskgroup task_reduction(@add_reduction_i32 {{.*}} -> [[TGARG:%arg[0-9]+]] : !fir.ref<i32>) {
-! CHECK: [[TGDECL:%[0-9]+]]:2 = hlfir.declare [[TGARG]] {uniq_name = "omp.reduction.element"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
-! CHECK: omp.task in_reduction(@add_reduction_i32 [[TGDECL]]#0 -> [[TASKARG:%arg[0-9]+]] : !fir.ref<i32>)
-! CHECK: [[TASKDECL:%[0-9]+]]:2 = hlfir.declare [[TASKARG]] {uniq_name = "omp.reduction.element"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
-! CHECK: fir.load [[TASKDECL]]#0 : !fir.ref<i32>
-! CHECK: hlfir.assign {{.*}} to [[TASKDECL]]#0 : i32, !fir.ref<i32>
+! CHECK: omp.taskgroup task_reduction(byref @[[BOX_RED]] {{.*}} -> %{{.*}} : !fir.ref<!fir.box<!fir.array<4xi32>>>) {
+! CHECK: omp.task in_reduction(byref @[[BOX_RED]] {{.*}} -> %{{.*}} : !fir.ref<!fir.box<!fir.array<4xi32>>>) private({{.*}}_firstprivate_box_4xi32
+! CHECK: hlfir.designate %{{.*}} (%c2) {{.*}} -> !fir.ref<i32>
subroutine taskloop_in_reduction_element(a, n)
integer :: a(4), n
@@ -97,10 +97,8 @@ subroutine taskloop_in_reduction_element(a, n)
end subroutine
! CHECK-LABEL: func.func @_QPtaskloop_in_reduction_element
-! CHECK-NOT: _QFtaskloop_in_reduction_elementEa_firstprivate_box_4xi32
-! CHECK: omp.taskloop.context in_reduction(@add_reduction_i32 {{.*}} -> [[TLARG:%arg[0-9]+]] : !fir.ref<i32>)
-! CHECK: hlfir.declare [[TLARG]] {uniq_name = "omp.reduction.element"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
-! CHECK: hlfir.assign {{.*}} to %{{[0-9]+}}#0 : i32, !fir.ref<i32>
+! CHECK: omp.taskloop.context in_reduction(byref @[[BOX_RED]] {{.*}} : !fir.ref<!fir.box<!fir.array<4xi32>>>) private({{.*}}_firstprivate_box_4xi32
+! CHECK: hlfir.designate %{{.*}} (%c2) {{.*}} -> !fir.ref<i32>
subroutine taskloop_reduction_element(a, n)
integer :: a(4), n
@@ -111,10 +109,8 @@ subroutine taskloop_reduction_element(a, n)
end subroutine
! CHECK-LABEL: func.func @_QPtaskloop_reduction_element
-! CHECK-NOT: _QFtaskloop_reduction_elementEa_firstprivate_box_4xi32
-! CHECK: omp.taskloop.context {{.*}} reduction(@add_reduction_i32 {{.*}} -> [[TLRARG:%arg[0-9]+]] : !fir.ref<i32>)
-! CHECK: hlfir.declare [[TLRARG]] {uniq_name = "omp.reduction.element"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
-! CHECK: hlfir.assign {{.*}} to %{{[0-9]+}}#0 : i32, !fir.ref<i32>
+! CHECK: omp.taskloop.context private({{.*}}_firstprivate_box_4xi32{{.*}}) reduction(byref @[[BOX_RED]] {{.*}} : !fir.ref<!fir.box<!fir.array<4xi32>>>) {
+! CHECK: hlfir.designate %{{.*}} (%c2) {{.*}} -> !fir.ref<i32>
subroutine taskloop_reduction_mixed_use(a, n)
integer :: a(4), n
@@ -126,8 +122,9 @@ subroutine taskloop_reduction_mixed_use(a, n)
end subroutine
! CHECK-LABEL: func.func @_QPtaskloop_reduction_mixed_use
-! CHECK: omp.taskloop.context private({{.*}}@_QFtaskloop_reduction_mixed_useEa_firstprivate_box_4xi32{{.*}}) reduction(@add_reduction_i32 {{.*}} -> [[TLMARG:%arg[0-9]+]] : !fir.ref<i32>)
-! CHECK: hlfir.declare [[TLMARG]] {uniq_name = "omp.reduction.element"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+! CHECK: omp.taskloop.context private({{.*}}_firstprivate_box_4xi32{{.*}}) reduction(byref @[[BOX_RED]] {{.*}} : !fir.ref<!fir.box<!fir.array<4xi32>>>) {
+! CHECK: hlfir.designate %{{.*}} (%c2) {{.*}} -> !fir.ref<i32>
+! CHECK: hlfir.designate %{{.*}} (%c1) {{.*}} -> !fir.ref<i32>
subroutine taskloop_reduction_nested_index_use(a, b, n)
integer :: a(4), b(4), n
@@ -139,5 +136,6 @@ subroutine taskloop_reduction_nested_index_use(a, b, n)
end subroutine
! CHECK-LABEL: func.func @_QPtaskloop_reduction_nested_index_use
-! CHECK: omp.taskloop.context private({{.*}}@_QFtaskloop_reduction_nested_index_useEa_firstprivate_box_4xi32{{.*}}) reduction(@add_reduction_i32 {{.*}} -> [[TLNARG:%arg[0-9]+]] : !fir.ref<i32>)
-! CHECK: hlfir.declare [[TLNARG]] {uniq_name = "omp.reduction.element"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+! CHECK: omp.taskloop.context private({{.*}}_firstprivate_box_4xi32{{.*}}) reduction(byref @[[BOX_RED]] {{.*}} : !fir.ref<!fir.box<!fir.array<4xi32>>>) {
+! CHECK: hlfir.designate %{{.*}} (%c2) {{.*}} -> !fir.ref<i32>
+! CHECK: hlfir.designate %{{.*}} (%{{.*}}) {{.*}} -> !fir.ref<i32>
diff --git a/flang/test/Lower/OpenMP/reduction-array-section.f90 b/flang/test/Lower/OpenMP/reduction-array-section.f90
deleted file mode 100644
index b081c275b1929..0000000000000
--- a/flang/test/Lower/OpenMP/reduction-array-section.f90
+++ /dev/null
@@ -1,39 +0,0 @@
-! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %s -o - | FileCheck %s --implicit-check-not=omp.reduction.element
-
-! Regression test for reductions on array *sections* (e.g. a(2:96)).
-!
-! An array section has rank > 0, so it must be lowered using the boxed
-! whole-array reduction (@add_reduction_byref_box_*) and the section applied
-! via hlfir.designate inside the region. It must NOT be routed through the
-! single-element path (uniq_name = "omp.reduction.element"), which only supports
-! rank-0 references and otherwise aborts in PrivateReductionUtils with
-! "creating reduction/privatization init region for unsupported type".
-
-subroutine reduction_array_section(a, n)
- integer :: a(100), n
-!$omp parallel do reduction(+: a(2:96))
- do i = 1, n
- a(2:96) = a(2:96) + i
- end do
-end subroutine
-
-! CHECK: omp.declare_reduction @[[RED:add_reduction_byref_box_100xi32]] : !fir.ref<!fir.box<!fir.array<100xi32>>>
-
-! CHECK-LABEL: func.func @_QPreduction_array_section
-! CHECK: omp.wsloop {{.*}} reduction(byref @[[RED]] %{{[0-9]+}} -> %[[ARG:.*]] : !fir.ref<!fir.box<!fir.array<100xi32>>>) {
-! CHECK: %[[DECL:.*]]:2 = hlfir.declare %[[ARG]] {uniq_name = "_QFreduction_array_sectionEa"}
-! CHECK: %[[BOX:.*]] = fir.load %[[DECL]]#0 : !fir.ref<!fir.box<!fir.array<100xi32>>>
-! CHECK: hlfir.designate %[[BOX]] (%c2:%c96:%c1) {{.*}} -> !fir.ref<!fir.array<95xi32>>
-
-subroutine reduction_array_section_simd(a, n)
- integer :: a(100), n
-!$omp parallel do simd reduction(+: a(2:96))
- do i = 1, n
- a(2:96) = a(2:96) + i
- end do
-end subroutine
-
-! CHECK-LABEL: func.func @_QPreduction_array_section_simd
-! CHECK: omp.wsloop reduction(byref @[[RED]] %{{[0-9]+}} -> %[[WSARG:.*]] : !fir.ref<!fir.box<!fir.array<100xi32>>>) {
-! CHECK: omp.simd {{.*}} reduction(byref @[[RED]] %[[WSARG]] -> %[[SIMDARG:.*]] : !fir.ref<!fir.box<!fir.array<100xi32>>>) {
-! CHECK: hlfir.declare %[[SIMDARG]] {uniq_name = "_QFreduction_array_section_simdEa"}
More information about the llvm-branch-commits
mailing list