[flang-commits] [flang] [llvm] [mlir] Changes for invoking scan Op (PR #123254)

Anchu Rajendran S via flang-commits flang-commits at lists.llvm.org
Thu Jan 16 15:18:38 PST 2025


https://github.com/anchuraj created https://github.com/llvm/llvm-project/pull/123254

Frontend changes to invoke scan Op. It will build successfully after https://github.com/llvm/llvm-project/pull/114737 is merged.

>From d8652f50fb008ca306608e3e7d231754756dae0c Mon Sep 17 00:00:00 2001
From: Anchu Rajendran <asudhaku at amd.com>
Date: Thu, 16 Jan 2025 17:13:56 -0600
Subject: [PATCH] Changes for invoking scan Op

---
 flang/lib/Lower/OpenMP/ClauseProcessor.cpp    |  39 +-
 flang/lib/Lower/OpenMP/ClauseProcessor.h      |   4 +
 flang/lib/Lower/OpenMP/Clauses.cpp            |   8 +-
 flang/lib/Lower/OpenMP/OpenMP.cpp             |  23 +-
 flang/lib/Lower/OpenMP/ReductionProcessor.cpp |  36 +-
 flang/lib/Lower/OpenMP/ReductionProcessor.h   |   4 +-
 .../Lower/OpenMP/Todo/reduction-inscan.f90    |  15 -
 .../Lower/OpenMP/Todo/reduction-modifiers.f90 |  14 -
 .../test/Lower/OpenMP/Todo/reduction-task.f90 |   2 +-
 flang/test/Lower/OpenMP/scan.f90              |  34 ++
 .../Conversion/OpenMPToLLVM/OpenMPToLLVM.cpp  |   3 +-
 patch                                         | 456 ++++++++++++++++++
 patch.diff                                    | 370 ++++++++++++++
 13 files changed, 963 insertions(+), 45 deletions(-)
 delete mode 100644 flang/test/Lower/OpenMP/Todo/reduction-inscan.f90
 delete mode 100644 flang/test/Lower/OpenMP/Todo/reduction-modifiers.f90
 create mode 100644 flang/test/Lower/OpenMP/scan.f90
 create mode 100644 patch
 create mode 100644 patch.diff

diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
index fb8e007c7af574..619f4a57205a05 100644
--- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
+++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
@@ -344,6 +344,22 @@ bool ClauseProcessor::processDistSchedule(
   return false;
 }
 
+bool ClauseProcessor::processExclusive(
+    mlir::Location currentLocation,
+    mlir::omp::ExclusiveClauseOps &result) const {
+  return findRepeatableClause<omp::clause::Exclusive>(
+      [&](const omp::clause::Exclusive &clause, const parser::CharBlock &) {
+        for (const Object &object : clause.v) {
+          semantics::Symbol *sym = object.sym();
+          mlir::Value symVal = converter.getSymbolAddress(*sym);
+          if (auto declOp = symVal.getDefiningOp<hlfir::DeclareOp>()) {
+            symVal = declOp.getBase();
+          }
+          result.exclusiveVars.push_back(symVal);
+        }
+      });
+}
+
 bool ClauseProcessor::processFilter(lower::StatementContext &stmtCtx,
                                     mlir::omp::FilterClauseOps &result) const {
   if (auto *clause = findUniqueClause<omp::clause::Filter>()) {
@@ -380,6 +396,22 @@ bool ClauseProcessor::processHint(mlir::omp::HintClauseOps &result) const {
   return false;
 }
 
+bool ClauseProcessor::processInclusive(
+    mlir::Location currentLocation,
+    mlir::omp::InclusiveClauseOps &result) const {
+  return findRepeatableClause<omp::clause::Inclusive>(
+      [&](const omp::clause::Inclusive &clause, const parser::CharBlock &) {
+        for (const Object &object : clause.v) {
+          const semantics::Symbol *symbol = object.sym();
+          mlir::Value symVal = converter.getSymbolAddress(*symbol);
+          if (auto declOp = symVal.getDefiningOp<hlfir::DeclareOp>()) {
+            symVal = declOp.getBase();
+          }
+          result.inclusiveVars.push_back(symVal);
+        }
+      });
+}
+
 bool ClauseProcessor::processMergeable(
     mlir::omp::MergeableClauseOps &result) const {
   return markClauseOccurrence<omp::clause::Mergeable>(result.mergeable);
@@ -1135,10 +1167,9 @@ bool ClauseProcessor::processReduction(
         llvm::SmallVector<mlir::Attribute> reductionDeclSymbols;
         llvm::SmallVector<const semantics::Symbol *> reductionSyms;
         ReductionProcessor rp;
-        rp.addDeclareReduction(currentLocation, converter, clause,
-                               reductionVars, reduceVarByRef,
-                               reductionDeclSymbols, reductionSyms);
-
+        rp.addDeclareReduction(
+            currentLocation, converter, clause, reductionVars, reduceVarByRef,
+            reductionDeclSymbols, reductionSyms, &result.reductionMod);
         // Copy local lists into the output.
         llvm::copy(reductionVars, std::back_inserter(result.reductionVars));
         llvm::copy(reduceVarByRef, std::back_inserter(result.reductionByref));
diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.h b/flang/lib/Lower/OpenMP/ClauseProcessor.h
index 7b047d4a7567ad..e05f66c7666844 100644
--- a/flang/lib/Lower/OpenMP/ClauseProcessor.h
+++ b/flang/lib/Lower/OpenMP/ClauseProcessor.h
@@ -64,6 +64,8 @@ class ClauseProcessor {
   bool processDeviceType(mlir::omp::DeviceTypeClauseOps &result) const;
   bool processDistSchedule(lower::StatementContext &stmtCtx,
                            mlir::omp::DistScheduleClauseOps &result) const;
+  bool processExclusive(mlir::Location currentLocation,
+                        mlir::omp::ExclusiveClauseOps &result) const;
   bool processFilter(lower::StatementContext &stmtCtx,
                      mlir::omp::FilterClauseOps &result) const;
   bool processFinal(lower::StatementContext &stmtCtx,
@@ -72,6 +74,8 @@ class ClauseProcessor {
       mlir::omp::HasDeviceAddrClauseOps &result,
       llvm::SmallVectorImpl<const semantics::Symbol *> &isDeviceSyms) const;
   bool processHint(mlir::omp::HintClauseOps &result) const;
+  bool processInclusive(mlir::Location currentLocation,
+                        mlir::omp::InclusiveClauseOps &result) const;
   bool processMergeable(mlir::omp::MergeableClauseOps &result) const;
   bool processNowait(mlir::omp::NowaitClauseOps &result) const;
   bool processNumTeams(lower::StatementContext &stmtCtx,
diff --git a/flang/lib/Lower/OpenMP/Clauses.cpp b/flang/lib/Lower/OpenMP/Clauses.cpp
index b424e209d56da9..a26bdcdf343e13 100644
--- a/flang/lib/Lower/OpenMP/Clauses.cpp
+++ b/flang/lib/Lower/OpenMP/Clauses.cpp
@@ -728,8 +728,8 @@ Enter make(const parser::OmpClause::Enter &inp,
 
 Exclusive make(const parser::OmpClause::Exclusive &inp,
                semantics::SemanticsContext &semaCtx) {
-  // inp -> empty
-  llvm_unreachable("Empty: exclusive");
+  // inp.v -> parser::OmpObjectList
+  return Exclusive{makeObjects(/*List=*/inp.v, semaCtx)};
 }
 
 Fail make(const parser::OmpClause::Fail &inp,
@@ -838,8 +838,8 @@ If make(const parser::OmpClause::If &inp,
 
 Inclusive make(const parser::OmpClause::Inclusive &inp,
                semantics::SemanticsContext &semaCtx) {
-  // inp -> empty
-  llvm_unreachable("Empty: inclusive");
+  // inp.v -> parser::OmpObjectList
+  return Inclusive{makeObjects(/*List=*/inp.v, semaCtx)};
 }
 
 Indirect make(const parser::OmpClause::Indirect &inp,
diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index 158f76250572ea..1e9926024b0504 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -1577,6 +1577,15 @@ static void genParallelClauses(
   cp.processReduction(loc, clauseOps, reductionSyms);
 }
 
+static void genScanClauses(lower::AbstractConverter &converter,
+                           semantics::SemanticsContext &semaCtx,
+                           const List<Clause> &clauses, mlir::Location loc,
+                           mlir::omp::ScanOperands &clauseOps) {
+  ClauseProcessor cp(converter, semaCtx, clauses);
+  cp.processInclusive(loc, clauseOps);
+  cp.processExclusive(loc, clauseOps);
+}
+
 static void genSectionsClauses(
     lower::AbstractConverter &converter, semantics::SemanticsContext &semaCtx,
     const List<Clause> &clauses, mlir::Location loc,
@@ -1974,6 +1983,18 @@ genParallelOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
   return parallelOp;
 }
 
+static mlir::omp::ScanOp
+genScanOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
+          semantics::SemanticsContext &semaCtx, mlir::Location loc,
+          const ConstructQueue &queue, ConstructQueue::const_iterator item) {
+
+  mlir::omp::ScanOperands clauseOps;
+  genScanClauses(converter, semaCtx, item->clauses, loc, clauseOps);
+
+  return converter.getFirOpBuilder().create<mlir::omp::ScanOp>(
+      converter.getCurrentLocation(), clauseOps);
+}
+
 /// This breaks the normal prototype of the gen*Op functions: adding the
 /// sectionBlocks argument so that the enclosed section constructs can be
 /// lowered here with correct reduction symbol remapping.
@@ -2976,7 +2997,7 @@ static void genOMPDispatch(lower::AbstractConverter &converter,
     genStandaloneParallel(converter, symTable, semaCtx, eval, loc, queue, item);
     break;
   case llvm::omp::Directive::OMPD_scan:
-    TODO(loc, "Unhandled directive " + llvm::omp::getOpenMPDirectiveName(dir));
+    genScanOp(converter, symTable, semaCtx, loc, queue, item);
     break;
   case llvm::omp::Directive::OMPD_section:
     llvm_unreachable("genOMPDispatch: OMPD_section");
diff --git a/flang/lib/Lower/OpenMP/ReductionProcessor.cpp b/flang/lib/Lower/OpenMP/ReductionProcessor.cpp
index 2cd21107a916e4..b11c8af168da67 100644
--- a/flang/lib/Lower/OpenMP/ReductionProcessor.cpp
+++ b/flang/lib/Lower/OpenMP/ReductionProcessor.cpp
@@ -25,6 +25,7 @@
 #include "flang/Parser/tools.h"
 #include "mlir/Dialect/OpenMP/OpenMPDialect.h"
 #include "llvm/Support/CommandLine.h"
+#include <string>
 
 static llvm::cl::opt<bool> forceByrefReduction(
     "force-byref-reduction",
@@ -514,18 +515,38 @@ static bool doReductionByRef(mlir::Value reductionVar) {
   return false;
 }
 
+mlir::omp::ReductionModifier
+translateReductionModifier(const omp::clause::Reduction::ReductionModifier &m) {
+  switch (m) {
+  case omp::clause::Reduction::ReductionModifier::Default:
+    return mlir::omp::ReductionModifier::defaultmod;
+  case omp::clause::Reduction::ReductionModifier::Inscan:
+    return mlir::omp::ReductionModifier::inscan;
+  case omp::clause::Reduction::ReductionModifier::Task:
+    return mlir::omp::ReductionModifier::task;
+  }
+  return mlir::omp::ReductionModifier::defaultmod;
+}
+
 void ReductionProcessor::addDeclareReduction(
     mlir::Location currentLocation, lower::AbstractConverter &converter,
     const omp::clause::Reduction &reduction,
     llvm::SmallVectorImpl<mlir::Value> &reductionVars,
     llvm::SmallVectorImpl<bool> &reduceVarByRef,
     llvm::SmallVectorImpl<mlir::Attribute> &reductionDeclSymbols,
-    llvm::SmallVectorImpl<const semantics::Symbol *> &reductionSymbols) {
+    llvm::SmallVectorImpl<const semantics::Symbol *> &reductionSymbols,
+    mlir::omp::ReductionModifierAttr *reductionMod) {
   fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
 
-  if (std::get<std::optional<omp::clause::Reduction::ReductionModifier>>(
-          reduction.t))
-    TODO(currentLocation, "Reduction modifiers are not supported");
+  auto mod = std::get<std::optional<omp::clause::Reduction::ReductionModifier>>(
+      reduction.t);
+  if (mod.has_value() &&
+      (mod.value() != omp::clause::Reduction::ReductionModifier::Inscan)) {
+    std::string modStr = "default";
+    if (mod.value() == omp::clause::Reduction::ReductionModifier::Task)
+      modStr = "task";
+    TODO(currentLocation, "Reduction modifier " + modStr + " is not supported");
+  }
 
   mlir::omp::DeclareReductionOp decl;
   const auto &redOperatorList{
@@ -649,6 +670,13 @@ void ReductionProcessor::addDeclareReduction(
                                   currentLocation, isByRef);
     reductionDeclSymbols.push_back(
         mlir::SymbolRefAttr::get(firOpBuilder.getContext(), decl.getSymName()));
+    auto redMod =
+        std::get<std::optional<omp::clause::Reduction::ReductionModifier>>(
+            reduction.t);
+    if (redMod.has_value())
+      *reductionMod = mlir::omp::ReductionModifierAttr::get(
+          firOpBuilder.getContext(),
+          translateReductionModifier(redMod.value()));
   }
 }
 
diff --git a/flang/lib/Lower/OpenMP/ReductionProcessor.h b/flang/lib/Lower/OpenMP/ReductionProcessor.h
index 5f4d742b62cb10..49e5584088bc61 100644
--- a/flang/lib/Lower/OpenMP/ReductionProcessor.h
+++ b/flang/lib/Lower/OpenMP/ReductionProcessor.h
@@ -19,6 +19,7 @@
 #include "flang/Parser/parse-tree.h"
 #include "flang/Semantics/symbol.h"
 #include "flang/Semantics/type.h"
+#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
 #include "mlir/IR/Location.h"
 #include "mlir/IR/Types.h"
 
@@ -126,7 +127,8 @@ class ReductionProcessor {
       llvm::SmallVectorImpl<mlir::Value> &reductionVars,
       llvm::SmallVectorImpl<bool> &reduceVarByRef,
       llvm::SmallVectorImpl<mlir::Attribute> &reductionDeclSymbols,
-      llvm::SmallVectorImpl<const semantics::Symbol *> &reductionSymbols);
+      llvm::SmallVectorImpl<const semantics::Symbol *> &reductionSymbols,
+      mlir::omp::ReductionModifierAttr *reductionMod);
 };
 
 template <typename FloatOp, typename IntegerOp>
diff --git a/flang/test/Lower/OpenMP/Todo/reduction-inscan.f90 b/flang/test/Lower/OpenMP/Todo/reduction-inscan.f90
deleted file mode 100644
index 152d91a16f80fe..00000000000000
--- a/flang/test/Lower/OpenMP/Todo/reduction-inscan.f90
+++ /dev/null
@@ -1,15 +0,0 @@
-! RUN: %not_todo_cmd bbc -emit-fir -fopenmp -o - %s 2>&1 | FileCheck %s
-! RUN: %not_todo_cmd %flang_fc1 -emit-fir -fopenmp -o - %s 2>&1 | FileCheck %s
-
-! CHECK: not yet implemented: Reduction modifiers are not supported
-subroutine reduction_inscan()
-  integer :: i,j
-  i = 0
-
-  !$omp do reduction(inscan, +:i)
-  do j=1,10
-     !$omp scan inclusive(i)
-     i = i + 1
-  end do
-  !$omp end do
-end subroutine reduction_inscan
diff --git a/flang/test/Lower/OpenMP/Todo/reduction-modifiers.f90 b/flang/test/Lower/OpenMP/Todo/reduction-modifiers.f90
deleted file mode 100644
index 82625ed8c5f31c..00000000000000
--- a/flang/test/Lower/OpenMP/Todo/reduction-modifiers.f90
+++ /dev/null
@@ -1,14 +0,0 @@
-! RUN: %not_todo_cmd bbc -emit-fir -fopenmp -o - %s 2>&1 | FileCheck %s
-! RUN: %not_todo_cmd %flang_fc1 -emit-fir -fopenmp -o - %s 2>&1 | FileCheck %s
-
-! CHECK: not yet implemented: Reduction modifiers are not supported
-
-subroutine foo()
-  integer :: i, j
-  j = 0
-  !$omp do reduction (inscan, *: j)
-  do i = 1, 10
-    !$omp scan inclusive(j)
-    j = j + 1
-  end do
-end subroutine
diff --git a/flang/test/Lower/OpenMP/Todo/reduction-task.f90 b/flang/test/Lower/OpenMP/Todo/reduction-task.f90
index 6707f65e1a4cc3..b746872e9e7edf 100644
--- a/flang/test/Lower/OpenMP/Todo/reduction-task.f90
+++ b/flang/test/Lower/OpenMP/Todo/reduction-task.f90
@@ -1,7 +1,7 @@
 ! RUN: %not_todo_cmd bbc -emit-fir -fopenmp -o - %s 2>&1 | FileCheck %s
 ! RUN: %not_todo_cmd %flang_fc1 -emit-fir -fopenmp -o - %s 2>&1 | FileCheck %s
 
-! CHECK: not yet implemented: Reduction modifiers are not supported
+! CHECK: not yet implemented: Reduction modifier task is not supported
 subroutine reduction_task()
   integer :: i
   i = 0
diff --git a/flang/test/Lower/OpenMP/scan.f90 b/flang/test/Lower/OpenMP/scan.f90
new file mode 100644
index 00000000000000..9cf2174a7f3314
--- /dev/null
+++ b/flang/test/Lower/OpenMP/scan.f90
@@ -0,0 +1,34 @@
+!RUN: %flang_fc1 -emit-hlfir -fopenmp %s -o - | FileCheck %s
+
+subroutine inclusive_scan
+ implicit none
+ integer, parameter :: n = 100
+ integer a(n), b(n)
+ integer x, k
+
+ !CHECK: omp.wsloop reduction(mod: inscan, {{.*}}) {
+ !$omp parallel do reduction(inscan, +: x)
+ do k = 1, n
+   x = x + a(k)
+   !CHECK: omp.scan inclusive({{.*}})
+   !$omp scan inclusive(x)
+   b(k) = x
+ end do
+end subroutine inclusive_scan
+
+
+subroutine exclusive_scan
+ implicit none
+ integer, parameter :: n = 100
+ integer a(n), b(n)
+ integer x, k
+
+ !CHECK: omp.wsloop reduction(mod: inscan, {{.*}}) {
+ !$omp parallel do reduction(inscan, +: x)
+ do k = 1, n
+   x = x + a(k)
+   !CHECK: omp.scan exclusive({{.*}})
+   !$omp scan exclusive(x)
+   b(k) = x
+ end do
+end subroutine exclusive_scan
diff --git a/mlir/lib/Conversion/OpenMPToLLVM/OpenMPToLLVM.cpp b/mlir/lib/Conversion/OpenMPToLLVM/OpenMPToLLVM.cpp
index 5d0003911bca87..056b7f989128a4 100644
--- a/mlir/lib/Conversion/OpenMPToLLVM/OpenMPToLLVM.cpp
+++ b/mlir/lib/Conversion/OpenMPToLLVM/OpenMPToLLVM.cpp
@@ -226,7 +226,7 @@ void mlir::configureOpenMPToLLVMConversionLegality(
   target.addDynamicallyLegalOp<
       omp::AtomicReadOp, omp::AtomicWriteOp, omp::CancellationPointOp,
       omp::CancelOp, omp::CriticalDeclareOp, omp::FlushOp, omp::MapBoundsOp,
-      omp::MapInfoOp, omp::OrderedOp, omp::TargetEnterDataOp,
+      omp::MapInfoOp, omp::ScanOp, omp::OrderedOp, omp::TargetEnterDataOp,
       omp::TargetExitDataOp, omp::TargetUpdateOp, omp::ThreadprivateOp,
       omp::YieldOp>([&](Operation *op) {
     return typeConverter.isLegal(op->getOperandTypes()) &&
@@ -264,6 +264,7 @@ void mlir::populateOpenMPToLLVMConversionPatterns(LLVMTypeConverter &converter,
       RegionLessOpConversion<omp::CancelOp>,
       RegionLessOpConversion<omp::CriticalDeclareOp>,
       RegionLessOpConversion<omp::OrderedOp>,
+      RegionLessOpConversion<omp::ScanOp>,
       RegionLessOpConversion<omp::TargetEnterDataOp>,
       RegionLessOpConversion<omp::TargetExitDataOp>,
       RegionLessOpConversion<omp::TargetUpdateOp>,
diff --git a/patch b/patch
new file mode 100644
index 00000000000000..0e62246fa4915a
--- /dev/null
+++ b/patch
@@ -0,0 +1,456 @@
+diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
+index fb8e007c7af5..a4aaf4111cd1 100644
+--- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
++++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
+@@ -344,6 +344,22 @@ bool ClauseProcessor::processDistSchedule(
+   return false;
+ }
+ 
++bool ClauseProcessor::processExclusive(
++    mlir::Location currentLocation,
++    mlir::omp::ExclusiveClauseOps &result) const {
++  return findRepeatableClause<omp::clause::Exclusive>(
++      [&](const omp::clause::Exclusive &clause, const parser::CharBlock &) {
++        for (const Object &object : clause.v) {
++          semantics::Symbol *sym = object.sym();
++          mlir::Value symVal = converter.getSymbolAddress(*sym);
++          if (auto declOp = symVal.getDefiningOp<hlfir::DeclareOp>()) {
++            symVal = declOp.getBase();
++          }
++          result.exclusiveVars.push_back(symVal);
++        }
++      });
++}
++
+ bool ClauseProcessor::processFilter(lower::StatementContext &stmtCtx,
+                                     mlir::omp::FilterClauseOps &result) const {
+   if (auto *clause = findUniqueClause<omp::clause::Filter>()) {
+@@ -380,6 +396,22 @@ bool ClauseProcessor::processHint(mlir::omp::HintClauseOps &result) const {
+   return false;
+ }
+ 
++bool ClauseProcessor::processInclusive(
++    mlir::Location currentLocation,
++    mlir::omp::InclusiveClauseOps &result) const {
++  return findRepeatableClause<omp::clause::Inclusive>(
++      [&](const omp::clause::Inclusive &clause, const parser::CharBlock &) {
++        for (const Object &object : clause.v) {
++          const semantics::Symbol *symbol = object.sym();
++          mlir::Value symVal = converter.getSymbolAddress(*symbol);
++          if (auto declOp = symVal.getDefiningOp<hlfir::DeclareOp>()) {
++            symVal = declOp.getBase();
++          }
++          result.inclusiveVars.push_back(symVal);
++        }
++      });
++}
++
+ bool ClauseProcessor::processMergeable(
+     mlir::omp::MergeableClauseOps &result) const {
+   return markClauseOccurrence<omp::clause::Mergeable>(result.mergeable);
+@@ -1135,9 +1167,9 @@ bool ClauseProcessor::processReduction(
+         llvm::SmallVector<mlir::Attribute> reductionDeclSymbols;
+         llvm::SmallVector<const semantics::Symbol *> reductionSyms;
+         ReductionProcessor rp;
+-        rp.addDeclareReduction(currentLocation, converter, clause,
+-                               reductionVars, reduceVarByRef,
+-                               reductionDeclSymbols, reductionSyms);
++        rp.addDeclareReduction(
++            currentLocation, converter, clause, reductionVars, reduceVarByRef,
++            reductionDeclSymbols, reductionSyms, &result.reductionMod);
+ 
+         // Copy local lists into the output.
+         llvm::copy(reductionVars, std::back_inserter(result.reductionVars));
+diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.h b/flang/lib/Lower/OpenMP/ClauseProcessor.h
+index 7b047d4a7567..e05f66c76668 100644
+--- a/flang/lib/Lower/OpenMP/ClauseProcessor.h
++++ b/flang/lib/Lower/OpenMP/ClauseProcessor.h
+@@ -64,6 +64,8 @@ public:
+   bool processDeviceType(mlir::omp::DeviceTypeClauseOps &result) const;
+   bool processDistSchedule(lower::StatementContext &stmtCtx,
+                            mlir::omp::DistScheduleClauseOps &result) const;
++  bool processExclusive(mlir::Location currentLocation,
++                        mlir::omp::ExclusiveClauseOps &result) const;
+   bool processFilter(lower::StatementContext &stmtCtx,
+                      mlir::omp::FilterClauseOps &result) const;
+   bool processFinal(lower::StatementContext &stmtCtx,
+@@ -72,6 +74,8 @@ public:
+       mlir::omp::HasDeviceAddrClauseOps &result,
+       llvm::SmallVectorImpl<const semantics::Symbol *> &isDeviceSyms) const;
+   bool processHint(mlir::omp::HintClauseOps &result) const;
++  bool processInclusive(mlir::Location currentLocation,
++                        mlir::omp::InclusiveClauseOps &result) const;
+   bool processMergeable(mlir::omp::MergeableClauseOps &result) const;
+   bool processNowait(mlir::omp::NowaitClauseOps &result) const;
+   bool processNumTeams(lower::StatementContext &stmtCtx,
+diff --git a/flang/lib/Lower/OpenMP/Clauses.cpp b/flang/lib/Lower/OpenMP/Clauses.cpp
+index b424e209d56d..a26bdcdf343e 100644
+--- a/flang/lib/Lower/OpenMP/Clauses.cpp
++++ b/flang/lib/Lower/OpenMP/Clauses.cpp
+@@ -728,8 +728,8 @@ Enter make(const parser::OmpClause::Enter &inp,
+ 
+ Exclusive make(const parser::OmpClause::Exclusive &inp,
+                semantics::SemanticsContext &semaCtx) {
+-  // inp -> empty
+-  llvm_unreachable("Empty: exclusive");
++  // inp.v -> parser::OmpObjectList
++  return Exclusive{makeObjects(/*List=*/inp.v, semaCtx)};
+ }
+ 
+ Fail make(const parser::OmpClause::Fail &inp,
+@@ -838,8 +838,8 @@ If make(const parser::OmpClause::If &inp,
+ 
+ Inclusive make(const parser::OmpClause::Inclusive &inp,
+                semantics::SemanticsContext &semaCtx) {
+-  // inp -> empty
+-  llvm_unreachable("Empty: inclusive");
++  // inp.v -> parser::OmpObjectList
++  return Inclusive{makeObjects(/*List=*/inp.v, semaCtx)};
+ }
+ 
+ Indirect make(const parser::OmpClause::Indirect &inp,
+diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
+index 158f76250572..1e9926024b05 100644
+--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
++++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
+@@ -1577,6 +1577,15 @@ static void genParallelClauses(
+   cp.processReduction(loc, clauseOps, reductionSyms);
+ }
+ 
++static void genScanClauses(lower::AbstractConverter &converter,
++                           semantics::SemanticsContext &semaCtx,
++                           const List<Clause> &clauses, mlir::Location loc,
++                           mlir::omp::ScanOperands &clauseOps) {
++  ClauseProcessor cp(converter, semaCtx, clauses);
++  cp.processInclusive(loc, clauseOps);
++  cp.processExclusive(loc, clauseOps);
++}
++
+ static void genSectionsClauses(
+     lower::AbstractConverter &converter, semantics::SemanticsContext &semaCtx,
+     const List<Clause> &clauses, mlir::Location loc,
+@@ -1974,6 +1983,18 @@ genParallelOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
+   return parallelOp;
+ }
+ 
++static mlir::omp::ScanOp
++genScanOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
++          semantics::SemanticsContext &semaCtx, mlir::Location loc,
++          const ConstructQueue &queue, ConstructQueue::const_iterator item) {
++
++  mlir::omp::ScanOperands clauseOps;
++  genScanClauses(converter, semaCtx, item->clauses, loc, clauseOps);
++
++  return converter.getFirOpBuilder().create<mlir::omp::ScanOp>(
++      converter.getCurrentLocation(), clauseOps);
++}
++
+ /// This breaks the normal prototype of the gen*Op functions: adding the
+ /// sectionBlocks argument so that the enclosed section constructs can be
+ /// lowered here with correct reduction symbol remapping.
+@@ -2976,7 +2997,7 @@ static void genOMPDispatch(lower::AbstractConverter &converter,
+     genStandaloneParallel(converter, symTable, semaCtx, eval, loc, queue, item);
+     break;
+   case llvm::omp::Directive::OMPD_scan:
+-    TODO(loc, "Unhandled directive " + llvm::omp::getOpenMPDirectiveName(dir));
++    genScanOp(converter, symTable, semaCtx, loc, queue, item);
+     break;
+   case llvm::omp::Directive::OMPD_section:
+     llvm_unreachable("genOMPDispatch: OMPD_section");
+diff --git a/flang/lib/Lower/OpenMP/ReductionProcessor.cpp b/flang/lib/Lower/OpenMP/ReductionProcessor.cpp
+index 2cd21107a916..69e4779bf002 100644
+--- a/flang/lib/Lower/OpenMP/ReductionProcessor.cpp
++++ b/flang/lib/Lower/OpenMP/ReductionProcessor.cpp
+@@ -25,6 +25,7 @@
+ #include "flang/Parser/tools.h"
+ #include "mlir/Dialect/OpenMP/OpenMPDialect.h"
+ #include "llvm/Support/CommandLine.h"
++#include <string>
+ 
+ static llvm::cl::opt<bool> forceByrefReduction(
+     "force-byref-reduction",
+@@ -514,18 +515,37 @@ static bool doReductionByRef(mlir::Value reductionVar) {
+   return false;
+ }
+ 
++mlir::omp::ReductionModifier
++translateReductionModifier(const omp::clause::Reduction::ReductionModifier &m) {
++  switch (m) {
++  case omp::clause::Reduction::ReductionModifier::Default:
++    return mlir::omp::ReductionModifier::defaultmod;
++  case omp::clause::Reduction::ReductionModifier::Inscan:
++    return mlir::omp::ReductionModifier::inscan;
++  case omp::clause::Reduction::ReductionModifier::Task:
++    return mlir::omp::ReductionModifier::task;
++  }
++  return mlir::omp::ReductionModifier::defaultmod;
++}
++
+ void ReductionProcessor::addDeclareReduction(
+     mlir::Location currentLocation, lower::AbstractConverter &converter,
+     const omp::clause::Reduction &reduction,
+     llvm::SmallVectorImpl<mlir::Value> &reductionVars,
+     llvm::SmallVectorImpl<bool> &reduceVarByRef,
+     llvm::SmallVectorImpl<mlir::Attribute> &reductionDeclSymbols,
+-    llvm::SmallVectorImpl<const semantics::Symbol *> &reductionSymbols) {
++    llvm::SmallVectorImpl<const semantics::Symbol *> &reductionSymbols,
++    mlir::omp::ReductionModifierAttr *reductionMod) {
+   fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
+-
+-  if (std::get<std::optional<omp::clause::Reduction::ReductionModifier>>(
+-          reduction.t))
+-    TODO(currentLocation, "Reduction modifiers are not supported");
++  auto mod = std::get<std::optional<omp::clause::Reduction::ReductionModifier>>(
++      reduction.t);
++  if (mod.has_value() &&
++      (mod.value() != omp::clause::Reduction::ReductionModifier::Inscan)) {
++    std::string modStr = "default";
++    if (mod.value() == omp::clause::Reduction::ReductionModifier::Task)
++      modStr = "task";
++    TODO(currentLocation, "Reduction modifier " + modStr + " is not supported");
++  }
+ 
+   mlir::omp::DeclareReductionOp decl;
+   const auto &redOperatorList{
+@@ -649,6 +669,13 @@ void ReductionProcessor::addDeclareReduction(
+                                   currentLocation, isByRef);
+     reductionDeclSymbols.push_back(
+         mlir::SymbolRefAttr::get(firOpBuilder.getContext(), decl.getSymName()));
++    auto redMod =
++        std::get<std::optional<omp::clause::Reduction::ReductionModifier>>(
++            reduction.t);
++    if (redMod.has_value())
++      *reductionMod = mlir::omp::ReductionModifierAttr::get(
++          firOpBuilder.getContext(),
++          translateReductionModifier(redMod.value()));
+   }
+ }
+ 
+diff --git a/flang/lib/Lower/OpenMP/ReductionProcessor.h b/flang/lib/Lower/OpenMP/ReductionProcessor.h
+index 5f4d742b62cb..547925de8c8b 100644
+--- a/flang/lib/Lower/OpenMP/ReductionProcessor.h
++++ b/flang/lib/Lower/OpenMP/ReductionProcessor.h
+@@ -19,6 +19,7 @@
+ #include "flang/Parser/parse-tree.h"
+ #include "flang/Semantics/symbol.h"
+ #include "flang/Semantics/type.h"
++#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
+ #include "mlir/IR/Location.h"
+ #include "mlir/IR/Types.h"
+ 
+@@ -120,13 +121,15 @@ public:
+ 
+   /// Creates a reduction declaration and associates it with an OpenMP block
+   /// directive.
++
+   static void addDeclareReduction(
+       mlir::Location currentLocation, lower::AbstractConverter &converter,
+       const omp::clause::Reduction &reduction,
+       llvm::SmallVectorImpl<mlir::Value> &reductionVars,
+       llvm::SmallVectorImpl<bool> &reduceVarByRef,
+       llvm::SmallVectorImpl<mlir::Attribute> &reductionDeclSymbols,
+-      llvm::SmallVectorImpl<const semantics::Symbol *> &reductionSymbols);
++      llvm::SmallVectorImpl<const semantics::Symbol *> &reductionSymbols,
++      mlir::omp::ReductionModifierAttr *reductionMod);
+ };
+ 
+ template <typename FloatOp, typename IntegerOp>
+diff --git a/flang/test/Lower/OpenMP/Todo/reduction-inscan.f90 b/flang/test/Lower/OpenMP/Todo/reduction-inscan.f90
+deleted file mode 100644
+index 152d91a16f80..000000000000
+--- a/flang/test/Lower/OpenMP/Todo/reduction-inscan.f90
++++ /dev/null
+@@ -1,15 +0,0 @@
+-! RUN: %not_todo_cmd bbc -emit-fir -fopenmp -o - %s 2>&1 | FileCheck %s
+-! RUN: %not_todo_cmd %flang_fc1 -emit-fir -fopenmp -o - %s 2>&1 | FileCheck %s
+-
+-! CHECK: not yet implemented: Reduction modifiers are not supported
+-subroutine reduction_inscan()
+-  integer :: i,j
+-  i = 0
+-
+-  !$omp do reduction(inscan, +:i)
+-  do j=1,10
+-     !$omp scan inclusive(i)
+-     i = i + 1
+-  end do
+-  !$omp end do
+-end subroutine reduction_inscan
+diff --git a/flang/test/Lower/OpenMP/Todo/reduction-modifiers.f90 b/flang/test/Lower/OpenMP/Todo/reduction-modifiers.f90
+deleted file mode 100644
+index 82625ed8c5f3..000000000000
+--- a/flang/test/Lower/OpenMP/Todo/reduction-modifiers.f90
++++ /dev/null
+@@ -1,14 +0,0 @@
+-! RUN: %not_todo_cmd bbc -emit-fir -fopenmp -o - %s 2>&1 | FileCheck %s
+-! RUN: %not_todo_cmd %flang_fc1 -emit-fir -fopenmp -o - %s 2>&1 | FileCheck %s
+-
+-! CHECK: not yet implemented: Reduction modifiers are not supported
+-
+-subroutine foo()
+-  integer :: i, j
+-  j = 0
+-  !$omp do reduction (inscan, *: j)
+-  do i = 1, 10
+-    !$omp scan inclusive(j)
+-    j = j + 1
+-  end do
+-end subroutine
+diff --git a/flang/test/Lower/OpenMP/Todo/reduction-task.f90 b/flang/test/Lower/OpenMP/Todo/reduction-task.f90
+index 6707f65e1a4c..b746872e9e7e 100644
+--- a/flang/test/Lower/OpenMP/Todo/reduction-task.f90
++++ b/flang/test/Lower/OpenMP/Todo/reduction-task.f90
+@@ -1,7 +1,7 @@
+ ! RUN: %not_todo_cmd bbc -emit-fir -fopenmp -o - %s 2>&1 | FileCheck %s
+ ! RUN: %not_todo_cmd %flang_fc1 -emit-fir -fopenmp -o - %s 2>&1 | FileCheck %s
+ 
+-! CHECK: not yet implemented: Reduction modifiers are not supported
++! CHECK: not yet implemented: Reduction modifier task is not supported
+ subroutine reduction_task()
+   integer :: i
+   i = 0
+diff --git a/flang/test/Lower/OpenMP/scan.f90 b/flang/test/Lower/OpenMP/scan.f90
+new file mode 100644
+index 000000000000..fb6a7c702817
+--- /dev/null
++++ b/flang/test/Lower/OpenMP/scan.f90
+@@ -0,0 +1,34 @@
++!RUN: %flang_fc1 -emit-hlfir -fopenmp %s -o - | FileCheck %s
++
++subroutine inclusive_scan
++ implicit none
++ integer, parameter :: n = 100
++ integer a(n), b(n)
++ integer x, k
++ 
++ !CHECK: omp.wsloop reduction(mod: inscan, {{.*}}) {
++ !$omp parallel do reduction(inscan, +: x)
++ do k = 1, n
++   x = x + a(k)
++   !CHECK: omp.scan inclusive({{.*}})
++   !$omp scan inclusive(x)
++   b(k) = x
++ end do
++end subroutine inclusive_scan
++
++
++subroutine exclusive_scan
++ implicit none
++ integer, parameter :: n = 100
++ integer a(n), b(n)
++ integer x, k
++ 
++ !CHECK: omp.wsloop reduction(mod: inscan, {{.*}}) {
++ !$omp parallel do reduction(inscan, +: x)
++ do k = 1, n
++   x = x + a(k)
++   !CHECK: omp.scan exclusive({{.*}})
++   !$omp scan exclusive(x)
++   b(k) = x
++ end do
++end subroutine exclusive_scan
+diff --git a/mlir/lib/Conversion/OpenMPToLLVM/OpenMPToLLVM.cpp b/mlir/lib/Conversion/OpenMPToLLVM/OpenMPToLLVM.cpp
+index 5d0003911bca..056b7f989128 100644
+--- a/mlir/lib/Conversion/OpenMPToLLVM/OpenMPToLLVM.cpp
++++ b/mlir/lib/Conversion/OpenMPToLLVM/OpenMPToLLVM.cpp
+@@ -226,7 +226,7 @@ void mlir::configureOpenMPToLLVMConversionLegality(
+   target.addDynamicallyLegalOp<
+       omp::AtomicReadOp, omp::AtomicWriteOp, omp::CancellationPointOp,
+       omp::CancelOp, omp::CriticalDeclareOp, omp::FlushOp, omp::MapBoundsOp,
+-      omp::MapInfoOp, omp::OrderedOp, omp::TargetEnterDataOp,
++      omp::MapInfoOp, omp::ScanOp, omp::OrderedOp, omp::TargetEnterDataOp,
+       omp::TargetExitDataOp, omp::TargetUpdateOp, omp::ThreadprivateOp,
+       omp::YieldOp>([&](Operation *op) {
+     return typeConverter.isLegal(op->getOperandTypes()) &&
+@@ -264,6 +264,7 @@ void mlir::populateOpenMPToLLVMConversionPatterns(LLVMTypeConverter &converter,
+       RegionLessOpConversion<omp::CancelOp>,
+       RegionLessOpConversion<omp::CriticalDeclareOp>,
+       RegionLessOpConversion<omp::OrderedOp>,
++      RegionLessOpConversion<omp::ScanOp>,
+       RegionLessOpConversion<omp::TargetEnterDataOp>,
+       RegionLessOpConversion<omp::TargetExitDataOp>,
+       RegionLessOpConversion<omp::TargetUpdateOp>,
+diff --git a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
+index a8bf501ef28e..aaa0eb8455d2 100644
+--- a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
++++ b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
+@@ -3167,38 +3167,19 @@ LogicalResult ScanOp::verify() {
+     return emitError(
+         "Exactly one of EXCLUSIVE or INCLUSIVE clause is expected");
+   }
+-  const OperandRange &scanVars =
+-      hasExclusiveVars() ? getExclusiveVars() : getInclusiveVars();
+-  auto verifyScanVarsInReduction = [&scanVars](ValueRange reductionVars) {
+-    for (const auto &it : scanVars)
+-      if (!llvm::is_contained(reductionVars, it))
+-        return false;
+-    return true;
+-  };
+   if (mlir::omp::WsloopOp parentWsLoopOp =
+           (*this)->getParentOfType<mlir::omp::WsloopOp>()) {
+     if (parentWsLoopOp.getReductionModAttr() &&
+         parentWsLoopOp.getReductionModAttr().getValue() ==
+             mlir::omp::ReductionModifier::inscan) {
+-      auto iface = llvm::cast<mlir::omp::BlockArgOpenMPOpInterface>(
+-          parentWsLoopOp.getOperation());
+-      if (!verifyScanVarsInReduction(iface.getReductionBlockArgs())) {
+-        return emitError(
+-            "List item should appear in REDUCTION clause of the parent");
+-      }
+       return success();
+     }
+-  } else if (mlir::omp::SimdOp parentSimdOp =
+-                 (*this)->getParentOfType<mlir::omp::SimdOp>()) {
++  }
++  if (mlir::omp::SimdOp parentSimdOp =
++          (*this)->getParentOfType<mlir::omp::SimdOp>()) {
+     if (parentSimdOp.getReductionModAttr() &&
+         parentSimdOp.getReductionModAttr().getValue() ==
+             mlir::omp::ReductionModifier::inscan) {
+-      auto iface = llvm::cast<mlir::omp::BlockArgOpenMPOpInterface>(
+-          parentSimdOp.getOperation());
+-      if (!verifyScanVarsInReduction(iface.getReductionBlockArgs())) {
+-        return emitError(
+-            "List item should appear in REDUCTION clause of the parent");
+-      }
+       return success();
+     }
+   }
+diff --git a/mlir/test/Dialect/OpenMP/invalid.mlir b/mlir/test/Dialect/OpenMP/invalid.mlir
+index e3e6397d84d7..514792e425f8 100644
+--- a/mlir/test/Dialect/OpenMP/invalid.mlir
++++ b/mlir/test/Dialect/OpenMP/invalid.mlir
+@@ -1837,33 +1837,6 @@ combiner {
+   omp.yield (%1 : f32)
+ }
+ 
+-func.func @scan_test_1(%lb: i32, %ub: i32, %step: i32) {
+-  %test1f32 = "test.f32"() : () -> (!llvm.ptr)
+-  %test2f32 = "test.f32"() : () -> (!llvm.ptr)
+-  omp.wsloop reduction(mod:inscan, @add_f32 %test1f32 -> %arg1 : !llvm.ptr) {
+-    omp.loop_nest (%i, %j) : i32 = (%lb, %ub) to (%ub, %lb) step (%step, %step) {
+-  // expected-error @below {{List item should appear in REDUCTION clause of the parent}}
+-       omp.scan inclusive(%test2f32 : !llvm.ptr)
+-        omp.yield
+-    }
+-  }
+-  return
+-}
+-
+-// -----
+-
+-omp.declare_reduction @add_f32 : f32
+-init {
+- ^bb0(%arg: f32):
+-  %0 = arith.constant 0.0 : f32
+-  omp.yield (%0 : f32)
+-}
+-combiner {
+-  ^bb1(%arg0: f32, %arg1: f32):
+-  %1 = arith.addf %arg0, %arg1 : f32
+-  omp.yield (%1 : f32)
+-}
+-
+ func.func @scan_test_2(%lb: i32, %ub: i32, %step: i32) {
+   %test1f32 = "test.f32"() : () -> (!llvm.ptr)
+   omp.wsloop reduction(mod:inscan, @add_f32 %test1f32 -> %arg1 : !llvm.ptr) {
diff --git a/patch.diff b/patch.diff
new file mode 100644
index 00000000000000..8019e0b0781a8d
--- /dev/null
+++ b/patch.diff
@@ -0,0 +1,370 @@
+diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
+index fb8e007c7af5..a4aaf4111cd1 100644
+--- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
++++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
+@@ -344,6 +344,22 @@ bool ClauseProcessor::processDistSchedule(
+   return false;
+ }
+ 
++bool ClauseProcessor::processExclusive(
++    mlir::Location currentLocation,
++    mlir::omp::ExclusiveClauseOps &result) const {
++  return findRepeatableClause<omp::clause::Exclusive>(
++      [&](const omp::clause::Exclusive &clause, const parser::CharBlock &) {
++        for (const Object &object : clause.v) {
++          semantics::Symbol *sym = object.sym();
++          mlir::Value symVal = converter.getSymbolAddress(*sym);
++          if (auto declOp = symVal.getDefiningOp<hlfir::DeclareOp>()) {
++            symVal = declOp.getBase();
++          }
++          result.exclusiveVars.push_back(symVal);
++        }
++      });
++}
++
+ bool ClauseProcessor::processFilter(lower::StatementContext &stmtCtx,
+                                     mlir::omp::FilterClauseOps &result) const {
+   if (auto *clause = findUniqueClause<omp::clause::Filter>()) {
+@@ -380,6 +396,22 @@ bool ClauseProcessor::processHint(mlir::omp::HintClauseOps &result) const {
+   return false;
+ }
+ 
++bool ClauseProcessor::processInclusive(
++    mlir::Location currentLocation,
++    mlir::omp::InclusiveClauseOps &result) const {
++  return findRepeatableClause<omp::clause::Inclusive>(
++      [&](const omp::clause::Inclusive &clause, const parser::CharBlock &) {
++        for (const Object &object : clause.v) {
++          const semantics::Symbol *symbol = object.sym();
++          mlir::Value symVal = converter.getSymbolAddress(*symbol);
++          if (auto declOp = symVal.getDefiningOp<hlfir::DeclareOp>()) {
++            symVal = declOp.getBase();
++          }
++          result.inclusiveVars.push_back(symVal);
++        }
++      });
++}
++
+ bool ClauseProcessor::processMergeable(
+     mlir::omp::MergeableClauseOps &result) const {
+   return markClauseOccurrence<omp::clause::Mergeable>(result.mergeable);
+@@ -1135,9 +1167,9 @@ bool ClauseProcessor::processReduction(
+         llvm::SmallVector<mlir::Attribute> reductionDeclSymbols;
+         llvm::SmallVector<const semantics::Symbol *> reductionSyms;
+         ReductionProcessor rp;
+-        rp.addDeclareReduction(currentLocation, converter, clause,
+-                               reductionVars, reduceVarByRef,
+-                               reductionDeclSymbols, reductionSyms);
++        rp.addDeclareReduction(
++            currentLocation, converter, clause, reductionVars, reduceVarByRef,
++            reductionDeclSymbols, reductionSyms, &result.reductionMod);
+ 
+         // Copy local lists into the output.
+         llvm::copy(reductionVars, std::back_inserter(result.reductionVars));
+diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.h b/flang/lib/Lower/OpenMP/ClauseProcessor.h
+index 7b047d4a7567..e05f66c76668 100644
+--- a/flang/lib/Lower/OpenMP/ClauseProcessor.h
++++ b/flang/lib/Lower/OpenMP/ClauseProcessor.h
+@@ -64,6 +64,8 @@ public:
+   bool processDeviceType(mlir::omp::DeviceTypeClauseOps &result) const;
+   bool processDistSchedule(lower::StatementContext &stmtCtx,
+                            mlir::omp::DistScheduleClauseOps &result) const;
++  bool processExclusive(mlir::Location currentLocation,
++                        mlir::omp::ExclusiveClauseOps &result) const;
+   bool processFilter(lower::StatementContext &stmtCtx,
+                      mlir::omp::FilterClauseOps &result) const;
+   bool processFinal(lower::StatementContext &stmtCtx,
+@@ -72,6 +74,8 @@ public:
+       mlir::omp::HasDeviceAddrClauseOps &result,
+       llvm::SmallVectorImpl<const semantics::Symbol *> &isDeviceSyms) const;
+   bool processHint(mlir::omp::HintClauseOps &result) const;
++  bool processInclusive(mlir::Location currentLocation,
++                        mlir::omp::InclusiveClauseOps &result) const;
+   bool processMergeable(mlir::omp::MergeableClauseOps &result) const;
+   bool processNowait(mlir::omp::NowaitClauseOps &result) const;
+   bool processNumTeams(lower::StatementContext &stmtCtx,
+diff --git a/flang/lib/Lower/OpenMP/Clauses.cpp b/flang/lib/Lower/OpenMP/Clauses.cpp
+index b424e209d56d..a26bdcdf343e 100644
+--- a/flang/lib/Lower/OpenMP/Clauses.cpp
++++ b/flang/lib/Lower/OpenMP/Clauses.cpp
+@@ -728,8 +728,8 @@ Enter make(const parser::OmpClause::Enter &inp,
+ 
+ Exclusive make(const parser::OmpClause::Exclusive &inp,
+                semantics::SemanticsContext &semaCtx) {
+-  // inp -> empty
+-  llvm_unreachable("Empty: exclusive");
++  // inp.v -> parser::OmpObjectList
++  return Exclusive{makeObjects(/*List=*/inp.v, semaCtx)};
+ }
+ 
+ Fail make(const parser::OmpClause::Fail &inp,
+@@ -838,8 +838,8 @@ If make(const parser::OmpClause::If &inp,
+ 
+ Inclusive make(const parser::OmpClause::Inclusive &inp,
+                semantics::SemanticsContext &semaCtx) {
+-  // inp -> empty
+-  llvm_unreachable("Empty: inclusive");
++  // inp.v -> parser::OmpObjectList
++  return Inclusive{makeObjects(/*List=*/inp.v, semaCtx)};
+ }
+ 
+ Indirect make(const parser::OmpClause::Indirect &inp,
+diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
+index 158f76250572..1e9926024b05 100644
+--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
++++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
+@@ -1577,6 +1577,15 @@ static void genParallelClauses(
+   cp.processReduction(loc, clauseOps, reductionSyms);
+ }
+ 
++static void genScanClauses(lower::AbstractConverter &converter,
++                           semantics::SemanticsContext &semaCtx,
++                           const List<Clause> &clauses, mlir::Location loc,
++                           mlir::omp::ScanOperands &clauseOps) {
++  ClauseProcessor cp(converter, semaCtx, clauses);
++  cp.processInclusive(loc, clauseOps);
++  cp.processExclusive(loc, clauseOps);
++}
++
+ static void genSectionsClauses(
+     lower::AbstractConverter &converter, semantics::SemanticsContext &semaCtx,
+     const List<Clause> &clauses, mlir::Location loc,
+@@ -1974,6 +1983,18 @@ genParallelOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
+   return parallelOp;
+ }
+ 
++static mlir::omp::ScanOp
++genScanOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
++          semantics::SemanticsContext &semaCtx, mlir::Location loc,
++          const ConstructQueue &queue, ConstructQueue::const_iterator item) {
++
++  mlir::omp::ScanOperands clauseOps;
++  genScanClauses(converter, semaCtx, item->clauses, loc, clauseOps);
++
++  return converter.getFirOpBuilder().create<mlir::omp::ScanOp>(
++      converter.getCurrentLocation(), clauseOps);
++}
++
+ /// This breaks the normal prototype of the gen*Op functions: adding the
+ /// sectionBlocks argument so that the enclosed section constructs can be
+ /// lowered here with correct reduction symbol remapping.
+@@ -2976,7 +2997,7 @@ static void genOMPDispatch(lower::AbstractConverter &converter,
+     genStandaloneParallel(converter, symTable, semaCtx, eval, loc, queue, item);
+     break;
+   case llvm::omp::Directive::OMPD_scan:
+-    TODO(loc, "Unhandled directive " + llvm::omp::getOpenMPDirectiveName(dir));
++    genScanOp(converter, symTable, semaCtx, loc, queue, item);
+     break;
+   case llvm::omp::Directive::OMPD_section:
+     llvm_unreachable("genOMPDispatch: OMPD_section");
+diff --git a/flang/lib/Lower/OpenMP/ReductionProcessor.cpp b/flang/lib/Lower/OpenMP/ReductionProcessor.cpp
+index 2cd21107a916..69e4779bf002 100644
+--- a/flang/lib/Lower/OpenMP/ReductionProcessor.cpp
++++ b/flang/lib/Lower/OpenMP/ReductionProcessor.cpp
+@@ -25,6 +25,7 @@
+ #include "flang/Parser/tools.h"
+ #include "mlir/Dialect/OpenMP/OpenMPDialect.h"
+ #include "llvm/Support/CommandLine.h"
++#include <string>
+ 
+ static llvm::cl::opt<bool> forceByrefReduction(
+     "force-byref-reduction",
+@@ -514,18 +515,37 @@ static bool doReductionByRef(mlir::Value reductionVar) {
+   return false;
+ }
+ 
++mlir::omp::ReductionModifier
++translateReductionModifier(const omp::clause::Reduction::ReductionModifier &m) {
++  switch (m) {
++  case omp::clause::Reduction::ReductionModifier::Default:
++    return mlir::omp::ReductionModifier::defaultmod;
++  case omp::clause::Reduction::ReductionModifier::Inscan:
++    return mlir::omp::ReductionModifier::inscan;
++  case omp::clause::Reduction::ReductionModifier::Task:
++    return mlir::omp::ReductionModifier::task;
++  }
++  return mlir::omp::ReductionModifier::defaultmod;
++}
++
+ void ReductionProcessor::addDeclareReduction(
+     mlir::Location currentLocation, lower::AbstractConverter &converter,
+     const omp::clause::Reduction &reduction,
+     llvm::SmallVectorImpl<mlir::Value> &reductionVars,
+     llvm::SmallVectorImpl<bool> &reduceVarByRef,
+     llvm::SmallVectorImpl<mlir::Attribute> &reductionDeclSymbols,
+-    llvm::SmallVectorImpl<const semantics::Symbol *> &reductionSymbols) {
++    llvm::SmallVectorImpl<const semantics::Symbol *> &reductionSymbols,
++    mlir::omp::ReductionModifierAttr *reductionMod) {
+   fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
+-
+-  if (std::get<std::optional<omp::clause::Reduction::ReductionModifier>>(
+-          reduction.t))
+-    TODO(currentLocation, "Reduction modifiers are not supported");
++  auto mod = std::get<std::optional<omp::clause::Reduction::ReductionModifier>>(
++      reduction.t);
++  if (mod.has_value() &&
++      (mod.value() != omp::clause::Reduction::ReductionModifier::Inscan)) {
++    std::string modStr = "default";
++    if (mod.value() == omp::clause::Reduction::ReductionModifier::Task)
++      modStr = "task";
++    TODO(currentLocation, "Reduction modifier " + modStr + " is not supported");
++  }
+ 
+   mlir::omp::DeclareReductionOp decl;
+   const auto &redOperatorList{
+@@ -649,6 +669,13 @@ void ReductionProcessor::addDeclareReduction(
+                                   currentLocation, isByRef);
+     reductionDeclSymbols.push_back(
+         mlir::SymbolRefAttr::get(firOpBuilder.getContext(), decl.getSymName()));
++    auto redMod =
++        std::get<std::optional<omp::clause::Reduction::ReductionModifier>>(
++            reduction.t);
++    if (redMod.has_value())
++      *reductionMod = mlir::omp::ReductionModifierAttr::get(
++          firOpBuilder.getContext(),
++          translateReductionModifier(redMod.value()));
+   }
+ }
+ 
+diff --git a/flang/lib/Lower/OpenMP/ReductionProcessor.h b/flang/lib/Lower/OpenMP/ReductionProcessor.h
+index 5f4d742b62cb..547925de8c8b 100644
+--- a/flang/lib/Lower/OpenMP/ReductionProcessor.h
++++ b/flang/lib/Lower/OpenMP/ReductionProcessor.h
+@@ -19,6 +19,7 @@
+ #include "flang/Parser/parse-tree.h"
+ #include "flang/Semantics/symbol.h"
+ #include "flang/Semantics/type.h"
++#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
+ #include "mlir/IR/Location.h"
+ #include "mlir/IR/Types.h"
+ 
+@@ -120,13 +121,15 @@ public:
+ 
+   /// Creates a reduction declaration and associates it with an OpenMP block
+   /// directive.
++
+   static void addDeclareReduction(
+       mlir::Location currentLocation, lower::AbstractConverter &converter,
+       const omp::clause::Reduction &reduction,
+       llvm::SmallVectorImpl<mlir::Value> &reductionVars,
+       llvm::SmallVectorImpl<bool> &reduceVarByRef,
+       llvm::SmallVectorImpl<mlir::Attribute> &reductionDeclSymbols,
+-      llvm::SmallVectorImpl<const semantics::Symbol *> &reductionSymbols);
++      llvm::SmallVectorImpl<const semantics::Symbol *> &reductionSymbols,
++      mlir::omp::ReductionModifierAttr *reductionMod);
+ };
+ 
+ template <typename FloatOp, typename IntegerOp>
+diff --git a/flang/test/Lower/OpenMP/Todo/reduction-inscan.f90 b/flang/test/Lower/OpenMP/Todo/reduction-inscan.f90
+deleted file mode 100644
+index 152d91a16f80..000000000000
+--- a/flang/test/Lower/OpenMP/Todo/reduction-inscan.f90
++++ /dev/null
+@@ -1,15 +0,0 @@
+-! RUN: %not_todo_cmd bbc -emit-fir -fopenmp -o - %s 2>&1 | FileCheck %s
+-! RUN: %not_todo_cmd %flang_fc1 -emit-fir -fopenmp -o - %s 2>&1 | FileCheck %s
+-
+-! CHECK: not yet implemented: Reduction modifiers are not supported
+-subroutine reduction_inscan()
+-  integer :: i,j
+-  i = 0
+-
+-  !$omp do reduction(inscan, +:i)
+-  do j=1,10
+-     !$omp scan inclusive(i)
+-     i = i + 1
+-  end do
+-  !$omp end do
+-end subroutine reduction_inscan
+diff --git a/flang/test/Lower/OpenMP/Todo/reduction-modifiers.f90 b/flang/test/Lower/OpenMP/Todo/reduction-modifiers.f90
+deleted file mode 100644
+index 82625ed8c5f3..000000000000
+--- a/flang/test/Lower/OpenMP/Todo/reduction-modifiers.f90
++++ /dev/null
+@@ -1,14 +0,0 @@
+-! RUN: %not_todo_cmd bbc -emit-fir -fopenmp -o - %s 2>&1 | FileCheck %s
+-! RUN: %not_todo_cmd %flang_fc1 -emit-fir -fopenmp -o - %s 2>&1 | FileCheck %s
+-
+-! CHECK: not yet implemented: Reduction modifiers are not supported
+-
+-subroutine foo()
+-  integer :: i, j
+-  j = 0
+-  !$omp do reduction (inscan, *: j)
+-  do i = 1, 10
+-    !$omp scan inclusive(j)
+-    j = j + 1
+-  end do
+-end subroutine
+diff --git a/flang/test/Lower/OpenMP/Todo/reduction-task.f90 b/flang/test/Lower/OpenMP/Todo/reduction-task.f90
+index 6707f65e1a4c..b746872e9e7e 100644
+--- a/flang/test/Lower/OpenMP/Todo/reduction-task.f90
++++ b/flang/test/Lower/OpenMP/Todo/reduction-task.f90
+@@ -1,7 +1,7 @@
+ ! RUN: %not_todo_cmd bbc -emit-fir -fopenmp -o - %s 2>&1 | FileCheck %s
+ ! RUN: %not_todo_cmd %flang_fc1 -emit-fir -fopenmp -o - %s 2>&1 | FileCheck %s
+ 
+-! CHECK: not yet implemented: Reduction modifiers are not supported
++! CHECK: not yet implemented: Reduction modifier task is not supported
+ subroutine reduction_task()
+   integer :: i
+   i = 0
+diff --git a/flang/test/Lower/OpenMP/scan.f90 b/flang/test/Lower/OpenMP/scan.f90
+new file mode 100644
+index 000000000000..fb6a7c702817
+--- /dev/null
++++ b/flang/test/Lower/OpenMP/scan.f90
+@@ -0,0 +1,34 @@
++!RUN: %flang_fc1 -emit-hlfir -fopenmp %s -o - | FileCheck %s
++
++subroutine inclusive_scan
++ implicit none
++ integer, parameter :: n = 100
++ integer a(n), b(n)
++ integer x, k
++ !CHECK: omp.wsloop reduction(mod: inscan, {{.*}}) {
++ !$omp parallel do reduction(inscan, +: x)
++ do k = 1, n
++   x = x + a(k)
++   !CHECK: omp.scan inclusive({{.*}})
++   !$omp scan inclusive(x)
++   b(k) = x
++ end do
++end subroutine inclusive_scan
++
++
++subroutine exclusive_scan
++ implicit none
++ integer, parameter :: n = 100
++ integer a(n), b(n)
++ integer x, k
++ !CHECK: omp.wsloop reduction(mod: inscan, {{.*}}) {
++ !$omp parallel do reduction(inscan, +: x)
++ do k = 1, n
++   x = x + a(k)
++   !CHECK: omp.scan exclusive({{.*}})
++   !$omp scan exclusive(x)
++   b(k) = x
++ end do
++end subroutine exclusive_scan
+diff --git a/mlir/lib/Conversion/OpenMPToLLVM/OpenMPToLLVM.cpp b/mlir/lib/Conversion/OpenMPToLLVM/OpenMPToLLVM.cpp
+index 5d0003911bca..056b7f989128 100644
+--- a/mlir/lib/Conversion/OpenMPToLLVM/OpenMPToLLVM.cpp
++++ b/mlir/lib/Conversion/OpenMPToLLVM/OpenMPToLLVM.cpp
+@@ -226,7 +226,7 @@ void mlir::configureOpenMPToLLVMConversionLegality(
+   target.addDynamicallyLegalOp<
+       omp::AtomicReadOp, omp::AtomicWriteOp, omp::CancellationPointOp,
+       omp::CancelOp, omp::CriticalDeclareOp, omp::FlushOp, omp::MapBoundsOp,
+-      omp::MapInfoOp, omp::OrderedOp, omp::TargetEnterDataOp,
++      omp::MapInfoOp, omp::ScanOp, omp::OrderedOp, omp::TargetEnterDataOp,
+       omp::TargetExitDataOp, omp::TargetUpdateOp, omp::ThreadprivateOp,
+       omp::YieldOp>([&](Operation *op) {
+     return typeConverter.isLegal(op->getOperandTypes()) &&
+@@ -264,6 +264,7 @@ void mlir::populateOpenMPToLLVMConversionPatterns(LLVMTypeConverter &converter,
+       RegionLessOpConversion<omp::CancelOp>,
+       RegionLessOpConversion<omp::CriticalDeclareOp>,
+       RegionLessOpConversion<omp::OrderedOp>,
++      RegionLessOpConversion<omp::ScanOp>,
+       RegionLessOpConversion<omp::TargetEnterDataOp>,
+       RegionLessOpConversion<omp::TargetExitDataOp>,
+       RegionLessOpConversion<omp::TargetUpdateOp>,



More information about the flang-commits mailing list