[flang-commits] [flang] [flang][OpenMP] Scope-qualify user-defined reduction names in lowering (PR #202474)

via flang-commits flang-commits at lists.llvm.org
Mon Jun 8 18:12:04 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-flang-fir-hlfir

Author: Carlos Seo (ceseo)

<details>
<summary>Changes</summary>

A named !$omp declare reduction was lowered to an omp.declare_reduction operation whose symbol name was just the bare reduction name (e.g. `@<!-- -->a`), without any scope qualification. Semantic name resolution was correct and gave each scope its own reduction symbol, but lowering deduplicates the declare reduction op by name, so two subroutines that declared a reduction with the same name collapsed onto a single op.

As a result, a reduction(name:var) clause could bind to a declaration that leaked in from a different scope.

Per OpenMP 6.0 7.6.14, a user-defined reduction has the same visibility and accessibility as a variable declared at the same location.

Qualify the generated op name with the scope in which the reduction is declared using mangleName, the same approach already used for omp.private and declare mapper. This is applied consistently when the op is created, when a clause references it, and when its existence is checked, so the names always agree.

Fixes #<!-- -->181270

---
Full diff: https://github.com/llvm/llvm-project/pull/202474.diff


16 Files Affected:

- (modified) flang/lib/Lower/OpenMP/OpenMP.cpp (+6-1) 
- (modified) flang/lib/Lower/Support/ReductionProcessor.cpp (+14-4) 
- (modified) flang/test/Lower/OpenMP/Todo/multiple-types-declare_reduction.f90 (+3-3) 
- (modified) flang/test/Lower/OpenMP/declare-reduction-character-allocatable.f90 (+2-2) 
- (modified) flang/test/Lower/OpenMP/declare-reduction-finalizer.f90 (+1-1) 
- (modified) flang/test/Lower/OpenMP/declare-reduction-initializer-component.f90 (+1-1) 
- (modified) flang/test/Lower/OpenMP/declare-reduction-initializer-defined-assign.f90 (+1-1) 
- (modified) flang/test/Lower/OpenMP/declare-reduction-initializer-rhs-call.f90 (+1-1) 
- (modified) flang/test/Lower/OpenMP/declare-reduction-no-initializer-intrinsic.f90 (+2-2) 
- (modified) flang/test/Lower/OpenMP/declare-reduction-no-initializer-target-derived.f90 (+1-1) 
- (added) flang/test/Lower/OpenMP/declare-reduction-same-name-different-scope.f90 (+35) 
- (modified) flang/test/Lower/OpenMP/declare-reduction-target-intrinsic.f90 (+9-9) 
- (modified) flang/test/Lower/OpenMP/omp-declare-reduction-combsub.f90 (+1-1) 
- (modified) flang/test/Lower/OpenMP/omp-declare-reduction-derivedtype.f90 (+1-1) 
- (modified) flang/test/Lower/OpenMP/omp-declare-reduction-initsub.f90 (+1-1) 
- (modified) flang/test/Lower/OpenMP/omp-declare-reduction.f90 (+1-1) 


``````````diff
diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index ec4067974f2f0..d35a75970531e 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -4409,7 +4409,12 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
                   defOp.u);
             },
             [&](const clause::ProcedureDesignator &pd) -> std::string {
-              return pd.v.sym()->name().ToString();
+              // Qualify the name with the scope in which the user-defined
+              // reduction is declared so that reductions with the same name
+              // in different scopes produce distinct omp.declare_reduction ops.
+              const semantics::Symbol *sym = pd.v.sym();
+              std::string name = sym->name().ToString();
+              return converter.mangleName(name, sym->GetUltimate().owner());
             },
         },
         redOp.u);
diff --git a/flang/lib/Lower/Support/ReductionProcessor.cpp b/flang/lib/Lower/Support/ReductionProcessor.cpp
index b3a27736d1616..7db48601d5aba 100644
--- a/flang/lib/Lower/Support/ReductionProcessor.cpp
+++ b/flang/lib/Lower/Support/ReductionProcessor.cpp
@@ -692,10 +692,14 @@ bool ReductionProcessor::processReductionArguments(
         if (!ReductionProcessor::supportedIntrinsicProcReduction(
                 *reductionIntrinsic)) {
           // If not an intrinsic is has to be a custom reduction op, and should
-          // be available in the module.
+          // be available in the module. The op is named using the scope in
+          // which the user-defined reduction was declared, so qualify the
+          // lookup name the same way the declaration and use sides do.
           semantics::Symbol *sym = reductionIntrinsic->v.sym();
           mlir::ModuleOp module = builder.getModule();
-          auto decl = module.lookupSymbol<OpType>(getRealName(sym).ToString());
+          std::string declName = getRealName(sym).ToString();
+          declName = converter.mangleName(declName, sym->GetUltimate().owner());
+          auto decl = module.lookupSymbol<OpType>(declName);
           if (!decl)
             return false;
         }
@@ -843,8 +847,14 @@ bool ReductionProcessor::processReductionArguments(
           // Custom reductions we can just add to the symbols without
           // generating the declare reduction op.
           semantics::Symbol *sym = reductionIntrinsic->v.sym();
-          reductionDeclSymbols.push_back(mlir::SymbolRefAttr::get(
-              builder.getContext(), sym->name().ToString()));
+          // Qualify the name with the scope in which the user-defined
+          // reduction was declared so that reductions with the same name in
+          // different scopes refer to distinct omp.declare_reduction ops.
+          std::string reductionName = getRealName(sym).ToString();
+          reductionName =
+              converter.mangleName(reductionName, sym->GetUltimate().owner());
+          reductionDeclSymbols.push_back(
+              mlir::SymbolRefAttr::get(builder.getContext(), reductionName));
           ++idx;
           continue;
         }
diff --git a/flang/test/Lower/OpenMP/Todo/multiple-types-declare_reduction.f90 b/flang/test/Lower/OpenMP/Todo/multiple-types-declare_reduction.f90
index e4931018b07ec..aa83d7f832c9b 100644
--- a/flang/test/Lower/OpenMP/Todo/multiple-types-declare_reduction.f90
+++ b/flang/test/Lower/OpenMP/Todo/multiple-types-declare_reduction.f90
@@ -29,7 +29,7 @@ program main
 end program main
 
 ! Verify declare reduction is created for integer
-! CHECK-LABEL: omp.declare_reduction @myred : i32
+! CHECK-LABEL: omp.declare_reduction @_QQFmyred : i32
 ! CHECK: init {
 ! CHECK: arith.constant 0 : i32
 ! CHECK: omp.yield
@@ -42,10 +42,10 @@ end program main
 ! Verify reduction is used in first parallel loop (integer)
 ! CHECK: omp.parallel
 ! CHECK: omp.wsloop
-! CHECK-SAME: reduction(@myred
+! CHECK-SAME: reduction(@_QQFmyred
 
 ! Verify reduction is used in second parallel loop (real)
 ! CHECK: omp.parallel
 ! CHECK: omp.wsloop
-! CHECK-SAME: reduction(@myred
+! CHECK-SAME: reduction(@_QQFmyred
 ! CHECK: arith.addf
diff --git a/flang/test/Lower/OpenMP/declare-reduction-character-allocatable.f90 b/flang/test/Lower/OpenMP/declare-reduction-character-allocatable.f90
index daa0d41063858..e4af5818ecb71 100644
--- a/flang/test/Lower/OpenMP/declare-reduction-character-allocatable.f90
+++ b/flang/test/Lower/OpenMP/declare-reduction-character-allocatable.f90
@@ -19,7 +19,7 @@ program test_character_reduction
 end program test_character_reduction
 
 ! Verify the declare_reduction is generated with reference type for character
-! CHECK-LABEL: omp.declare_reduction @char_max : !fir.ref<!fir.char<1>>
+! CHECK-LABEL: omp.declare_reduction @_QQFchar_max : !fir.ref<!fir.char<1>>
 ! CHECK: init {
 ! CHECK: omp.yield
 
@@ -30,4 +30,4 @@ end program test_character_reduction
 
 ! Verify the reduction is used in the parallel sections
 ! CHECK: omp.parallel
-! CHECK:   omp.sections reduction(byref @char_max
+! CHECK:   omp.sections reduction(byref @_QQFchar_max
diff --git a/flang/test/Lower/OpenMP/declare-reduction-finalizer.f90 b/flang/test/Lower/OpenMP/declare-reduction-finalizer.f90
index 22a653179ce2d..d0f8cbc2edbc3 100644
--- a/flang/test/Lower/OpenMP/declare-reduction-finalizer.f90
+++ b/flang/test/Lower/OpenMP/declare-reduction-finalizer.f90
@@ -25,7 +25,7 @@ end subroutine cleanup
 
 end module m1
 
-! CHECK-LABEL: omp.declare_reduction @plus_t{{.*}} : !fir.ref<{{.*}}>
+! CHECK-LABEL: omp.declare_reduction @_QQFplus_t{{.*}} : !fir.ref<{{.*}}>
 !
 ! -- alloc region
 ! CHECK:        alloc {
diff --git a/flang/test/Lower/OpenMP/declare-reduction-initializer-component.f90 b/flang/test/Lower/OpenMP/declare-reduction-initializer-component.f90
index b42fa610d17e0..39f1eb6e71f44 100644
--- a/flang/test/Lower/OpenMP/declare-reduction-initializer-component.f90
+++ b/flang/test/Lower/OpenMP/declare-reduction-initializer-component.f90
@@ -25,7 +25,7 @@ subroutine test_component_init()
   !$omp end parallel do
 end subroutine
 
-!CHECK: omp.declare_reduction @add_member : !fir.ref<!fir.type<_QFtest_component_initTt{member:i32}>>
+!CHECK: omp.declare_reduction @_QQFtest_component_initadd_member : !fir.ref<!fir.type<_QFtest_component_initTt{member:i32}>>
 !CHECK-SAME: alloc {
 !CHECK:   %[[ALLOCA:.*]] = fir.alloca !fir.type<_QFtest_component_initTt{member:i32}>
 !CHECK:   omp.yield(%[[ALLOCA]] : !fir.ref<!fir.type<_QFtest_component_initTt{member:i32}>>)
diff --git a/flang/test/Lower/OpenMP/declare-reduction-initializer-defined-assign.f90 b/flang/test/Lower/OpenMP/declare-reduction-initializer-defined-assign.f90
index bdf48626fd2b3..366d28c47b706 100644
--- a/flang/test/Lower/OpenMP/declare-reduction-initializer-defined-assign.f90
+++ b/flang/test/Lower/OpenMP/declare-reduction-initializer-defined-assign.f90
@@ -41,7 +41,7 @@ subroutine test_defined_assign_init()
   !$omp end parallel do
 end subroutine
 
-!CHECK: omp.declare_reduction @add_t :
+!CHECK: omp.declare_reduction @_QQFtest_defined_assign_initadd_t :
 !CHECK-SAME: alloc {
 !CHECK:   %[[ALLOCA:.*]] = fir.alloca
 !CHECK:   omp.yield(%[[ALLOCA]] :
diff --git a/flang/test/Lower/OpenMP/declare-reduction-initializer-rhs-call.f90 b/flang/test/Lower/OpenMP/declare-reduction-initializer-rhs-call.f90
index 7d409b27464e2..988219d65b1a6 100644
--- a/flang/test/Lower/OpenMP/declare-reduction-initializer-rhs-call.f90
+++ b/flang/test/Lower/OpenMP/declare-reduction-initializer-rhs-call.f90
@@ -36,7 +36,7 @@ subroutine test_rhs_call()
   !$omp end parallel do
 end subroutine
 
-!CHECK: omp.declare_reduction @add_t :
+!CHECK: omp.declare_reduction @_QQFtest_rhs_calladd_t :
 !CHECK-SAME: alloc {
 !CHECK:   %[[ALLOCA:.*]] = fir.alloca !fir.type<_QMmTt{member:i32}>
 !CHECK:   omp.yield(%[[ALLOCA]] :
diff --git a/flang/test/Lower/OpenMP/declare-reduction-no-initializer-intrinsic.f90 b/flang/test/Lower/OpenMP/declare-reduction-no-initializer-intrinsic.f90
index 225aa8ccd3aec..cb768d3b92744 100644
--- a/flang/test/Lower/OpenMP/declare-reduction-no-initializer-intrinsic.f90
+++ b/flang/test/Lower/OpenMP/declare-reduction-no-initializer-intrinsic.f90
@@ -3,7 +3,7 @@
 ! Test declare reduction without initializer clause for intrinsic types.
 ! Without an initializer, the private variable should be zero-initialized.
 
-! CHECK-DAG: omp.declare_reduction @char_max : !fir.ref<!fir.char<1,10>>
+! CHECK-DAG: omp.declare_reduction @_QQFchar_max : !fir.ref<!fir.char<1,10>>
 ! CHECK:       init {
 ! CHECK:       %[[CHZERO:.*]] = fir.zero_bits !fir.char<1,10>
 ! CHECK:       fir.store %[[CHZERO]]
@@ -72,7 +72,7 @@ program test_no_init_intrinsic
   !$omp end parallel do
 
   ! Test fixed-length character reduction without initializer
-  ! CHECK: omp.wsloop {{.*}} reduction(byref @char_max
+  ! CHECK: omp.wsloop {{.*}} reduction(byref @_QQFchar_max
   !$omp parallel do reduction(char_max: s)
   do i = 1, 10
     continue
diff --git a/flang/test/Lower/OpenMP/declare-reduction-no-initializer-target-derived.f90 b/flang/test/Lower/OpenMP/declare-reduction-no-initializer-target-derived.f90
index b3931d6d26238..007a704a6962c 100644
--- a/flang/test/Lower/OpenMP/declare-reduction-no-initializer-target-derived.f90
+++ b/flang/test/Lower/OpenMP/declare-reduction-no-initializer-target-derived.f90
@@ -4,7 +4,7 @@
 ! default component values, used in a target offload region.
 ! The init region must initialize components using the type's default values.
 
-! CHECK-LABEL: omp.declare_reduction @add_pts
+! CHECK-LABEL: omp.declare_reduction @_QQFadd_pts
 ! CHECK-SAME:    : !fir.ref<!fir.type<_QFTpoint{x:f32,y:f32}>>
 ! CHECK:       init {
 ! CHECK:       ^bb0(%{{.*}}: !fir.ref<!fir.type<_QFTpoint{{.*}}>>,
diff --git a/flang/test/Lower/OpenMP/declare-reduction-same-name-different-scope.f90 b/flang/test/Lower/OpenMP/declare-reduction-same-name-different-scope.f90
new file mode 100644
index 0000000000000..066758ae746e9
--- /dev/null
+++ b/flang/test/Lower/OpenMP/declare-reduction-same-name-different-scope.f90
@@ -0,0 +1,35 @@
+! Test that two user-defined reductions sharing the same name but declared in
+! different scopes lower to distinct omp.declare_reduction operations, and that
+! a reduction clause refers to the declaration visible in its own scope rather
+! than one leaking in from another scope (issue #181270).
+
+!RUN: %flang_fc1 -emit-hlfir -fopenmp %s -o - | FileCheck %s
+
+module m
+contains
+  subroutine dummy
+!$omp declare reduction (a:integer:omp_out=omp_out+omp_in) initializer(omp_priv=10000)
+  end subroutine dummy
+
+  subroutine test
+!$omp declare reduction (a:integer:omp_out=omp_out+omp_in) initializer(omp_priv=0)
+    integer::x1,i
+    x1=0
+!$omp parallel do reduction(a:x1)
+    do i=1,10
+       x1=x1+1
+    end do
+!$omp end parallel do
+  end subroutine test
+end module m
+
+! CHECK: omp.declare_reduction @[[TEST_RED:_QQMmFtesta]] : i32 init {
+! CHECK: %[[C0:.*]] = arith.constant 0 : i32
+! CHECK: omp.yield(%[[C0]] : i32)
+
+! CHECK: omp.declare_reduction @[[DUMMY_RED:_QQMmFdummya]] : i32 init {
+! CHECK: %[[C10000:.*]] = arith.constant 10000 : i32
+! CHECK: omp.yield(%[[C10000]] : i32)
+
+! CHECK-LABEL: func.func @_QMmPtest()
+! CHECK: omp.wsloop {{.*}}reduction(@[[TEST_RED]] %{{.*}} -> %{{.*}} : !fir.ref<i32>)
diff --git a/flang/test/Lower/OpenMP/declare-reduction-target-intrinsic.f90 b/flang/test/Lower/OpenMP/declare-reduction-target-intrinsic.f90
index b74133209bf01..43caea5e2dfd4 100644
--- a/flang/test/Lower/OpenMP/declare-reduction-target-intrinsic.f90
+++ b/flang/test/Lower/OpenMP/declare-reduction-target-intrinsic.f90
@@ -4,21 +4,21 @@
 ! These should generate inline constant initialization (no runtime calls),
 ! so they work on GPU targets without requiring the device Fortran runtime.
 
-! CHECK-LABEL: omp.declare_reduction @addc : complex<f32> init {
+! CHECK-LABEL: omp.declare_reduction @_QQFaddc : complex<f32> init {
 ! CHECK:         %[[CZERO:.*]] = fir.zero_bits complex<f32>
 ! CHECK:         omp.yield(%[[CZERO]] : complex<f32>)
 ! CHECK:       } combiner {
 ! CHECK:         fir.addc
 ! CHECK:       }
 
-! CHECK-LABEL: omp.declare_reduction @addr : f32 init {
+! CHECK-LABEL: omp.declare_reduction @_QQFaddr : f32 init {
 ! CHECK:         %[[FZERO:.*]] = fir.zero_bits f32
 ! CHECK:         omp.yield(%[[FZERO]] : f32)
 ! CHECK:       } combiner {
 ! CHECK:         arith.addf
 ! CHECK:       }
 
-! CHECK-LABEL: omp.declare_reduction @addi : i32 init {
+! CHECK-LABEL: omp.declare_reduction @_QQFaddi : i32 init {
 ! CHECK:         %[[IZERO:.*]] = fir.zero_bits i32
 ! CHECK:         omp.yield(%[[IZERO]] : i32)
 ! CHECK:       } combiner {
@@ -26,16 +26,16 @@
 ! CHECK:       }
 
 ! CHECK: omp.target
-! CHECK:   omp.teams reduction(@addi
-! CHECK:     omp.wsloop reduction(@addi
+! CHECK:   omp.teams reduction(@_QQFaddi
+! CHECK:     omp.wsloop reduction(@_QQFaddi
 
 ! CHECK: omp.target
-! CHECK:   omp.teams reduction(@addr
-! CHECK:     omp.wsloop reduction(@addr
+! CHECK:   omp.teams reduction(@_QQFaddr
+! CHECK:     omp.wsloop reduction(@_QQFaddr
 
 ! CHECK: omp.target
-! CHECK:   omp.teams reduction(@addc
-! CHECK:     omp.wsloop reduction(@addc
+! CHECK:   omp.teams reduction(@_QQFaddc
+! CHECK:     omp.wsloop reduction(@_QQFaddc
 
 program test_target_named_reduction
   implicit none
diff --git a/flang/test/Lower/OpenMP/omp-declare-reduction-combsub.f90 b/flang/test/Lower/OpenMP/omp-declare-reduction-combsub.f90
index 098b3f84aa2f3..ae1eb9747bd40 100644
--- a/flang/test/Lower/OpenMP/omp-declare-reduction-combsub.f90
+++ b/flang/test/Lower/OpenMP/omp-declare-reduction-combsub.f90
@@ -17,7 +17,7 @@ subroutine combine_me(out, in)
        integer out, in
      end subroutine combine_me
   end interface
-!CHECK:  omp.declare_reduction @red_add : i32 init {
+!CHECK:  omp.declare_reduction @_QQFfuncred_add : i32 init {
 !CHECK: ^bb0(%[[OMP_ORIG_ARG_I:.*]]: i32):
 !CHECK:    %[[OMP_PRIV:.*]] = fir.alloca i32
 !CHECK:    %[[OMP_ORIG:.*]] = fir.alloca i32
diff --git a/flang/test/Lower/OpenMP/omp-declare-reduction-derivedtype.f90 b/flang/test/Lower/OpenMP/omp-declare-reduction-derivedtype.f90
index 1fea2aee64f69..b92f42e2e25de 100644
--- a/flang/test/Lower/OpenMP/omp-declare-reduction-derivedtype.f90
+++ b/flang/test/Lower/OpenMP/omp-declare-reduction-derivedtype.f90
@@ -41,7 +41,7 @@ function func(x, n, init)
   end function func
 
 end module maxtype_mod
-!CHECK:  omp.declare_reduction @red_add_max : !fir.ref<[[MAXTYPE:.*]]> {{.*}} alloc {
+!CHECK:  omp.declare_reduction @_QQMmaxtype_modFfuncred_add_max : !fir.ref<[[MAXTYPE:.*]]> {{.*}} alloc {
 !CHECK:  %[[ALLOCA:.*]] = fir.alloca [[MAXTYPE:.*]]
 !CHECK:  omp.yield(%[[ALLOCA]] : !fir.ref<[[MAXTYPE]]>)
 !CHECK:  } init {
diff --git a/flang/test/Lower/OpenMP/omp-declare-reduction-initsub.f90 b/flang/test/Lower/OpenMP/omp-declare-reduction-initsub.f90
index 4aacc7cb2efba..2f6e432a72b13 100644
--- a/flang/test/Lower/OpenMP/omp-declare-reduction-initsub.f90
+++ b/flang/test/Lower/OpenMP/omp-declare-reduction-initsub.f90
@@ -17,7 +17,7 @@ subroutine initme(x,n)
        integer x,n
      end subroutine initme
   end interface
-!CHECK:  omp.declare_reduction @red_add : i32 init {
+!CHECK:  omp.declare_reduction @_QQFfuncred_add : i32 init {
 !CHECK: ^bb0(%[[OMP_ORIG_ARG_I:.*]]: i32):
 !CHECK:    %[[OMP_PRIV:.*]] = fir.alloca i32
 !CHECK:    %[[OMP_ORIG:.*]] = fir.alloca i32
diff --git a/flang/test/Lower/OpenMP/omp-declare-reduction.f90 b/flang/test/Lower/OpenMP/omp-declare-reduction.f90
index a41f6b214b9d8..73e3c28622a58 100644
--- a/flang/test/Lower/OpenMP/omp-declare-reduction.f90
+++ b/flang/test/Lower/OpenMP/omp-declare-reduction.f90
@@ -4,7 +4,7 @@
 
 subroutine declare_red()
   integer :: my_var
-!CHECK: omp.declare_reduction @my_red : i32 init {
+!CHECK: omp.declare_reduction @_QQFdeclare_redmy_red : i32 init {
 !CHECK: ^bb0(%[[OMP_ORIG_ARG_I:.*]]: i32):
 !CHECK:    %[[OMP_PRIV:.*]] = fir.alloca i32
 !CHECK:    %[[OMP_ORIG:.*]] = fir.alloca i32

``````````

</details>


https://github.com/llvm/llvm-project/pull/202474


More information about the flang-commits mailing list