[flang-commits] [flang] [flang][OpenMP] Revert array element reduction lowering (PR #215617)

Tom Eccles via flang-commits flang-commits at lists.llvm.org
Wed Aug 12 03:37:42 PDT 2026


https://github.com/tblah updated https://github.com/llvm/llvm-project/pull/215617

>From d9cb0d4ff41877e35ff447879b788d1fb3a9016c Mon Sep 17 00:00:00 2001
From: Tom Eccles <tom.eccles at arm.com>
Date: Tue, 11 Aug 2026 17:04:23 +0100
Subject: [PATCH 1/2] [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 while retaining semantic-context
plumbing needed by later user-defined reduction support. 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
---
 .../flang/Lower/Support/ReductionProcessor.h  |  10 -
 flang/lib/Lower/Bridge.cpp                    |   3 +-
 flang/lib/Lower/ConvertExprToHLFIR.cpp        |  47 +--
 flang/lib/Lower/OpenMP/ClauseProcessor.cpp    |   9 +-
 .../lib/Lower/OpenMP/DataSharingProcessor.cpp |  44 +--
 flang/lib/Lower/OpenMP/DataSharingProcessor.h |  13 +-
 flang/lib/Lower/OpenMP/OpenMP.cpp             | 291 +-----------------
 .../lib/Lower/Support/ReductionProcessor.cpp  | 152 ++++-----
 .../Lower/OpenMP/reduction-array-element.f90  |  76 +++--
 .../Lower/OpenMP/reduction-array-section.f90  |  39 ---
 10 files changed, 119 insertions(+), 565 deletions(-)
 delete mode 100644 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 6b57f02ed06bf..b86cc07159246 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 {
@@ -185,17 +183,9 @@ 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,
       semantics::SemanticsContext *semaCtx = nullptr,
       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 a8e3e4a0aea1a..d8ccedc4675cc 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -2433,8 +2433,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 59ef7143914b2..f8ac40337aaae 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 different 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 2f45b70db8fe6..03b9276f8c4c0 100644
--- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
+++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
@@ -1719,8 +1719,7 @@ bool ClauseProcessor::processInReduction(
                 currentLocation, converter,
                 std::get<typename omp::clause::ReductionOperatorList>(clause.t),
                 inReductionVars, inReduceVarByRef, inReductionDeclSymbols,
-                inReductionSyms, inReductionObjects, converter.getSymbolMap(),
-                &semaCtx))
+                inReductionSyms, &semaCtx))
           TODO(currentLocation, "Lowering unrecognised reduction type");
 
         // Copy local lists into the output.
@@ -2138,8 +2137,7 @@ bool ClauseProcessor::processReduction(
                 currentLocation, converter,
                 std::get<typename omp::clause::ReductionOperatorList>(clause.t),
                 reductionVars, reduceVarByRef, reductionDeclSymbols,
-                reductionSyms, reductionObjects, converter.getSymbolMap(),
-                &semaCtx, reductionVarCache))
+                reductionSyms, &semaCtx, reductionVarCache))
           TODO(currentLocation, "Lowering unrecognised reduction type");
         // Copy local lists into the output.
         llvm::copy(reductionVars, std::back_inserter(result.reductionVars));
@@ -2168,8 +2166,7 @@ bool ClauseProcessor::processTaskReduction(
                 currentLocation, converter,
                 std::get<typename omp::clause::ReductionOperatorList>(clause.t),
                 taskReductionVars, taskReduceVarByRef, taskReductionDeclSymbols,
-                taskReductionSyms, taskReductionObjects,
-                converter.getSymbolMap(), &semaCtx))
+                taskReductionSyms, &semaCtx))
           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 6b57934a087f6..1d39c1a8d4b77 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,
@@ -324,20 +321,6 @@ void DataSharingProcessor::collectSymbolsForPrivatization() {
   // allPrivatizedSymbols is a SetVector, so it is inserted only once.)
 }
 
-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
@@ -555,11 +538,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 f2f34ee32fd20..557584c21123f 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 {
@@ -117,8 +115,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;
@@ -139,7 +135,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();
@@ -168,17 +163,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 dacf578f5f4b8..738343c6c0bac 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -892,7 +892,6 @@ 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 (!sym) {
@@ -903,32 +902,20 @@ static void bindEntryBlockArgs(lower::AbstractConverter &converter,
         // llvm::zip_equal(processedSyms, vars, args) asserts equal lengths.
         // The matching block argument is silently skipped below.
         processedSyms.push_back(nullptr);
-        processedObjects.push_back(nullptr);
         continue;
       }
       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)) {
+    for (auto [sym, var, arg] : llvm::zip_equal(processedSyms, vars, args)) {
       if (!sym)
         continue; // Skip synthetic reduction entries (no Fortran symbol).
-      bool skipBind =
-          ReductionProcessor::isExpressionLoweredAsReductionObject(object) ||
-          (object && sym->Rank() > 0 &&
-           !fir::unwrapUntilSeqType(arg.getType()));
-      if (skipBind)
-        continue;
       converter.bindSymbol(
           *sym,
           hlfir::translateToExtendedValue(
@@ -1608,44 +1595,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
@@ -1929,186 +1885,6 @@ struct OpWithBodyGenInfo {
   int collapseValue = 0;
 };
 
-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.
@@ -2192,27 +1968,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,
@@ -2232,8 +1987,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
@@ -3095,25 +2848,8 @@ static mlir::omp::LoopNestOp genLoopNestOp(
         wrapperArgs,
     llvm::omp::Directive directive, DataSharingProcessor &dsp,
     llvm::function_ref<void(mlir::Operation *)> loopPostIvCb = nullptr) {
-  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);
     if (loopPostIvCb)
       loopPostIvCb(op);
     return llvm::SmallVector<const semantics::Symbol *>(iv);
@@ -3122,7 +2858,7 @@ static mlir::omp::LoopNestOp genLoopNestOp(
   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)
@@ -3130,8 +2866,6 @@ static mlir::omp::LoopNestOp genLoopNestOp(
           .setGenRegionEntryCb(ivCallback)
           .setCollapseInfo(nestValue, eval),
       queue, item, clauseOps);
-  converter.overrideExprValues(oldOverrides);
-  return loopNestOp;
 }
 
 static mlir::omp::LoopOp
@@ -4508,14 +4242,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;
@@ -5131,17 +4860,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 8baf607052e65..de6aeefa48fc4 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.h"
 #include "flang/Lower/OpenMP/Clauses.h"
@@ -52,7 +51,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,
     semantics::SemanticsContext *semaCtx,
     llvm::DenseMap<const semantics::Symbol *, mlir::Value> *reductionVarCache);
 
@@ -64,7 +62,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,
     semantics::SemanticsContext *semaCtx,
     llvm::DenseMap<const semantics::Symbol *, mlir::Value> *reductionVarCache);
 
@@ -436,18 +433,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) {
@@ -914,7 +899,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,
     semantics::SemanticsContext *semaCtx,
     llvm::DenseMap<const semantics::Symbol *, mlir::Value> *reductionVarCache) {
   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
@@ -954,105 +938,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"}

>From edd20242dc320398745866a4750c67c70fe80701 Mon Sep 17 00:00:00 2001
From: Tom Eccles <tom.eccles at arm.com>
Date: Wed, 12 Aug 2026 11:11:33 +0100
Subject: [PATCH 2/2] Diagnose privatized array element reductions

Task and taskloop array-element reductions can introduce both a
reduction block argument and an implicit firstprivate block argument for
the base array. Sequential symbol binding can then select the wrong
argument for references in the construct body.

Reject these cases until lowering can distinguish the reduction element
from other uses of the base array. Keep supported array-element reduction
coverage in the existing test and move the unsupported task forms to
focused TODO tests.

Assisted-by: Codex
---
 flang/lib/Lower/OpenMP/OpenMP.cpp             | 41 +++++++++++
 ...ction-array-element-task-privatization.f90 | 43 ++++++++++++
 .../Lower/OpenMP/reduction-array-element.f90  | 70 +------------------
 3 files changed, 86 insertions(+), 68 deletions(-)
 create mode 100644 flang/test/Lower/OpenMP/Todo/reduction-array-element-task-privatization.f90

diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index 738343c6c0bac..0353b107c6210 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -155,6 +155,33 @@ makeObjects(llvm::ArrayRef<const semantics::Symbol *> syms) {
   return objects;
 }
 
+static bool hasPrivatizedArrayElementReduction(
+    llvm::ArrayRef<Object> reductionObjects,
+    const llvm::SetVector<const semantics::Symbol *> &privatizedSymbols) {
+  for (const Object &object : reductionObjects) {
+    if (!object.sym() || !object.ref())
+      continue;
+    std::optional<evaluate::DataRef> dataRef =
+        evaluate::ExtractDataRef(*object.ref());
+    if (!dataRef)
+      continue;
+    const auto *arrayRef = std::get_if<evaluate::ArrayRef>(&dataRef->u);
+    if (!arrayRef ||
+        llvm::any_of(arrayRef->subscript(), [](const auto &subscript) {
+          return std::holds_alternative<evaluate::Triplet>(subscript.u);
+        }))
+      continue;
+
+    const semantics::Symbol &ultimate = object.sym()->GetUltimate();
+    if (llvm::any_of(privatizedSymbols,
+                     [&](const semantics::Symbol *privatizedSymbol) {
+                       return privatizedSymbol->GetUltimate() == ultimate;
+                     }))
+      return true;
+  }
+  return false;
+}
+
 /// Structure holding the information needed to create and bind entry block
 /// arguments associated to a single clause during OpenMP lowering.
 struct ObjectEntryBlockArgsEntry {
@@ -4247,6 +4274,11 @@ genTaskOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
                            /*useDelayedPrivatization=*/true, symTable);
   dsp.processStep1(&clauseOps);
 
+  if (hasPrivatizedArrayElementReduction(inReductionObjects,
+                                         dsp.getAllSymbolsToPrivatize()))
+    TODO(loc, "TASK construct with IN_REDUCTION of an array element whose "
+              "base array is privatized");
+
   ObjectEntryBlockArgs taskArgs;
   taskArgs.priv.objects = makeObjects(dsp.getDelayedPrivSymbols());
   taskArgs.priv.vars = clauseOps.privateVars;
@@ -4865,6 +4897,15 @@ static mlir::omp::TaskloopContextOp genStandaloneTaskloop(
                            enableDelayedPrivatization, symTable);
   dsp.processStep1(&taskloopClauseOps);
 
+  if (hasPrivatizedArrayElementReduction(inReductionObjects,
+                                         dsp.getAllSymbolsToPrivatize()))
+    TODO(loc, "TASKLOOP construct with IN_REDUCTION of an array element whose "
+              "base array is privatized");
+  if (hasPrivatizedArrayElementReduction(reductionObjects,
+                                         dsp.getAllSymbolsToPrivatize()))
+    TODO(loc, "TASKLOOP construct with REDUCTION of an array element whose "
+              "base array is privatized");
+
   mlir::omp::LoopNestOperands loopNestClauseOps;
   llvm::SmallVector<const semantics::Symbol *> iv;
   genLoopNestClauses(converter, semaCtx, eval, item->clauses, loc,
diff --git a/flang/test/Lower/OpenMP/Todo/reduction-array-element-task-privatization.f90 b/flang/test/Lower/OpenMP/Todo/reduction-array-element-task-privatization.f90
new file mode 100644
index 0000000000000..770f309d1d160
--- /dev/null
+++ b/flang/test/Lower/OpenMP/Todo/reduction-array-element-task-privatization.f90
@@ -0,0 +1,43 @@
+! RUN: split-file %s %t
+! RUN: %not_todo_cmd bbc -emit-hlfir -fopenmp -fopenmp-version=50 -o - %t/task.f90 2>&1 | FileCheck %s --check-prefix=TASK
+! RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 -o - %t/task.f90 2>&1 | FileCheck %s --check-prefix=TASK
+! RUN: %not_todo_cmd bbc -emit-hlfir -fopenmp -fopenmp-version=50 -o - %t/taskloop-in.f90 2>&1 | FileCheck %s --check-prefix=TASKLOOP-IN
+! RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 -o - %t/taskloop-in.f90 2>&1 | FileCheck %s --check-prefix=TASKLOOP-IN
+! RUN: %not_todo_cmd bbc -emit-hlfir -fopenmp -fopenmp-version=50 -o - %t/taskloop-reduction.f90 2>&1 | FileCheck %s --check-prefix=TASKLOOP-REDUCTION
+! RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 -o - %t/taskloop-reduction.f90 2>&1 | FileCheck %s --check-prefix=TASKLOOP-REDUCTION
+
+! An array element in a task reduction and the implicitly firstprivate base
+! array are represented by separate block arguments. Reject these constructs
+! until lowering can bind references to the correct argument.
+
+! TASK: not yet implemented: TASK construct with IN_REDUCTION of an array element whose base array is privatized
+! TASKLOOP-IN: not yet implemented: TASKLOOP construct with IN_REDUCTION of an array element whose base array is privatized
+! TASKLOOP-REDUCTION: not yet implemented: TASKLOOP construct with REDUCTION of an array element whose base array is privatized
+
+!--- task.f90
+subroutine task_reduction_element(a)
+  integer :: a(4)
+  !$omp taskgroup task_reduction(+: a(2))
+  !$omp task in_reduction(+: a(2))
+  a(2) = a(2) + 1
+  !$omp end task
+  !$omp end taskgroup
+end subroutine
+
+!--- taskloop-in.f90
+subroutine taskloop_in_reduction_element(a, n)
+  integer :: a(4), n
+  !$omp taskloop in_reduction(+: a(2))
+  do i = 1, n
+    a(2) = a(2) + i
+  end do
+end subroutine
+
+!--- taskloop-reduction.f90
+subroutine taskloop_reduction_element(a, n)
+  integer :: a(4), n
+  !$omp taskloop reduction(+: a(2))
+  do i = 1, n
+    a(2) = a(2) + i
+  end do
+end subroutine
diff --git a/flang/test/Lower/OpenMP/reduction-array-element.f90 b/flang/test/Lower/OpenMP/reduction-array-element.f90
index f62f91a457735..acb24a2aecc7b 100644
--- a/flang/test/Lower/OpenMP/reduction-array-element.f90
+++ b/flang/test/Lower/OpenMP/reduction-array-element.f90
@@ -1,8 +1,8 @@
 ! 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.
+! Keep lowering coverage for the supported 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>>>
 
@@ -73,69 +73,3 @@ subroutine reduction_do_simd(a, n)
 ! 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)
-!$omp taskgroup task_reduction(+: a(2))
-!$omp task in_reduction(+: a(2))
-  a(2) = a(2) + 1
-!$omp end task
-!$omp end taskgroup
-end subroutine
-
-! CHECK-LABEL: func.func @_QPtask_reduction_element
-! 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
-!$omp taskloop in_reduction(+: a(2))
-  do i = 1, n
-    a(2) = a(2) + i
-  end do
-end subroutine
-
-! CHECK-LABEL: func.func @_QPtaskloop_in_reduction_element
-! 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
-!$omp taskloop reduction(+: a(2))
-  do i = 1, n
-    a(2) = a(2) + i
-  end do
-end subroutine
-
-! CHECK-LABEL: func.func @_QPtaskloop_reduction_element
-! 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
-!$omp taskloop reduction(+: a(2))
-  do i = 1, n
-    a(2) = a(2) + i
-    a(1) = a(1) + 1
-  end do
-end subroutine
-
-! CHECK-LABEL: func.func @_QPtaskloop_reduction_mixed_use
-! 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
-!$omp taskloop reduction(+: a(2))
-  do i = 1, n
-    a(2) = a(2) + i
-    b(a(1)) = b(a(1)) + 1
-  end do
-end subroutine
-
-! CHECK-LABEL: func.func @_QPtaskloop_reduction_nested_index_use
-! 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>



More information about the flang-commits mailing list