From f61f3c34d22eb594cce99226c313869a82f28ee6 Mon Sep 17 00:00:00 2001 From: Razvan Lupusoru Date: Tue, 9 Sep 2025 09:46:43 -0700 Subject: [PATCH] [flang][acc] Fix incorrect loop body nesting and IV value use Two issues are being resolved: - Incorrect loop body nesting caused by insertion point not being updated after the loop. The scenario is now being tested through `nested_do_loops` function in the test. - Incorrect IV ssa values due to incorrect handling of scoping. Additionally, this also adds `--openacc-do-loop-to-acc-loop` flag so that the implicit conversion can be disabled for testing. --- flang/lib/Lower/Bridge.cpp | 8 + flang/lib/Lower/OpenACC.cpp | 12 +- .../Lower/OpenACC/do-loops-to-acc-loops.f90 | 189 ++++++++++++++++-- 3 files changed, 192 insertions(+), 17 deletions(-) diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp index e91fa2db15fa2..6125ea9153662 100644 --- a/flang/lib/Lower/Bridge.cpp +++ b/flang/lib/Lower/Bridge.cpp @@ -72,6 +72,7 @@ #include "mlir/Parser/Parser.h" #include "mlir/Support/StateStack.h" #include "mlir/Transforms/RegionUtils.h" +#include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/CommandLine.h" @@ -2198,6 +2199,11 @@ class FirConverter : public Fortran::lower::AbstractConverter { // Loops with induction variables inside OpenACC compute constructs // need special handling to ensure that the IVs are privatized. if (Fortran::lower::isInsideOpenACCComputeConstruct(*builder)) { + // Open up a new scope for the loop variables. + localSymbols.pushScope(); + auto scopeGuard = + llvm::make_scope_exit([&]() { localSymbols.popScope(); }); + mlir::Operation *loopOp = Fortran::lower::genOpenACCLoopFromDoConstruct( *this, bridge.getSemanticsContext(), localSymbols, doConstruct, eval); bool success = loopOp != nullptr; @@ -2214,6 +2220,8 @@ class FirConverter : public Fortran::lower::AbstractConverter { for (auto end = --eval.getNestedEvaluations().end(); iter != end; ++iter) genFIR(*iter, unstructuredContext); + + builder->setInsertionPointAfter(loopOp); return; } // Fall back to normal loop handling. diff --git a/flang/lib/Lower/OpenACC.cpp b/flang/lib/Lower/OpenACC.cpp index bbe749f8c8805..d8a0e4d8a8fa0 100644 --- a/flang/lib/Lower/OpenACC.cpp +++ b/flang/lib/Lower/OpenACC.cpp @@ -61,6 +61,11 @@ static llvm::cl::opt strideIncludeLowerExtent( "Whether to include the lower dimensions extents in the stride."), llvm::cl::init(true)); +static llvm::cl::opt lowerDoLoopToAccLoop( + "openacc-do-loop-to-acc-loop", + llvm::cl::desc("Whether to lower do loops as `acc.loop` operations."), + llvm::cl::init(true)); + // Special value for * passed in device_type or gang clauses. static constexpr std::int64_t starCst = -1; @@ -5005,6 +5010,9 @@ mlir::Operation *Fortran::lower::genOpenACCLoopFromDoConstruct( Fortran::semantics::SemanticsContext &semanticsContext, Fortran::lower::SymMap &localSymbols, const Fortran::parser::DoConstruct &doConstruct, pft::Evaluation &eval) { + if (!lowerDoLoopToAccLoop) + return nullptr; + // Only convert loops which have induction variables that need privatized. if (!doConstruct.IsDoNormal() && !doConstruct.IsDoConcurrent()) return nullptr; @@ -5027,10 +5035,6 @@ mlir::Operation *Fortran::lower::genOpenACCLoopFromDoConstruct( return nullptr; } - // Open up a new scope for the loop variables. - localSymbols.pushScope(); - auto scopeGuard = llvm::make_scope_exit([&]() { localSymbols.popScope(); }); - // Prepare empty operand vectors since there are no associated `acc loop` // clauses with the Fortran do loops being handled here. llvm::SmallVector privateOperands, gangOperands, diff --git a/flang/test/Lower/OpenACC/do-loops-to-acc-loops.f90 b/flang/test/Lower/OpenACC/do-loops-to-acc-loops.f90 index 5f8ea03d43a5d..a75a022690fcc 100644 --- a/flang/test/Lower/OpenACC/do-loops-to-acc-loops.f90 +++ b/flang/test/Lower/OpenACC/do-loops-to-acc-loops.f90 @@ -2,6 +2,7 @@ ! Tests the new functionality that converts Fortran iteration constructs to acc.loop with proper IV handling. ! RUN: bbc -fopenacc -emit-hlfir %s -o - | FileCheck %s +! RUN: bbc -fopenacc -emit-hlfir --openacc-do-loop-to-acc-loop=false %s -o - | FileCheck %s --check-prefix=CHECK-NOACCLOOP ! CHECK-LABEL: func.func @_QPbasic_do_loop subroutine basic_do_loop() @@ -17,10 +18,19 @@ subroutine basic_do_loop() !$acc end kernels ! CHECK: acc.kernels { -! CHECK: acc.loop {{.*}} control(%{{.*}} : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) +! CHECK: %[[PRIVATE_IV:.*]] = acc.private varPtr(%{{.*}} : !fir.ref) -> !fir.ref {implicit = true, name = "i"} +! CHECK: %[[PRIVATE_DECLARE:.*]]:2 = hlfir.declare %[[PRIVATE_IV]] {uniq_name = "_QFbasic_do_loopEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: acc.loop private(@privatization_ref_i32 -> %[[PRIVATE_IV]] : !fir.ref) control(%{{.*}} : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) +! CHECK: fir.store %{{.*}} to %[[PRIVATE_DECLARE]]#0 : !fir.ref +! CHECK: %{{.*}} = fir.load %[[PRIVATE_DECLARE]]#0 : !fir.ref +! CHECK: %{{.*}} = fir.load %[[PRIVATE_DECLARE]]#0 : !fir.ref ! CHECK: acc.yield ! CHECK: attributes {auto_ = [#acc.device_type], inclusiveUpperbound = array} +! CHECK-NOACCLOOP-LABEL: func.func @_QPbasic_do_loop +! CHECK-NOACCLOOP: acc.kernels { +! CHECK-NOACCLOOP-NOT: acc.loop + end subroutine ! CHECK-LABEL: func.func @_QPbasic_do_concurrent @@ -37,10 +47,19 @@ subroutine basic_do_concurrent() !$acc end kernels ! CHECK: acc.kernels { -! CHECK: acc.loop {{.*}} control(%{{.*}} : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) +! CHECK: %[[PRIVATE_IV:.*]] = acc.private varPtr(%{{.*}} : !fir.ref) -> !fir.ref {implicit = true, name = "i"} +! CHECK: %[[PRIVATE_DECLARE:.*]]:2 = hlfir.declare %[[PRIVATE_IV]] {uniq_name = "_QFbasic_do_concurrentEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: acc.loop private(@privatization_ref_i32 -> %[[PRIVATE_IV]] : !fir.ref) control(%{{.*}} : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) +! CHECK: fir.store %{{.*}} to %[[PRIVATE_DECLARE]]#0 : !fir.ref +! CHECK: %{{.*}} = fir.load %[[PRIVATE_DECLARE]]#0 : !fir.ref +! CHECK: %{{.*}} = fir.load %[[PRIVATE_DECLARE]]#0 : !fir.ref ! CHECK: acc.yield ! CHECK: attributes {auto_ = [#acc.device_type], inclusiveUpperbound = array} +! CHECK-NOACCLOOP-LABEL: func.func @_QPbasic_do_concurrent +! CHECK-NOACCLOOP: acc.kernels { +! CHECK-NOACCLOOP-NOT: acc.loop + end subroutine ! CHECK-LABEL: func.func @_QPbasic_do_loop_parallel @@ -57,10 +76,19 @@ subroutine basic_do_loop_parallel() !$acc end parallel ! CHECK: acc.parallel { -! CHECK: acc.loop {{.*}} control(%{{.*}} : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) +! CHECK: %[[PRIVATE_IV:.*]] = acc.private varPtr(%{{.*}} : !fir.ref) -> !fir.ref {implicit = true, name = "i"} +! CHECK: %[[PRIVATE_DECLARE:.*]]:2 = hlfir.declare %[[PRIVATE_IV]] {uniq_name = "_QFbasic_do_loop_parallelEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: acc.loop private(@privatization_ref_i32 -> %[[PRIVATE_IV]] : !fir.ref) control(%{{.*}} : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) +! CHECK: fir.store %{{.*}} to %[[PRIVATE_DECLARE]]#0 : !fir.ref +! CHECK: %{{.*}} = fir.load %[[PRIVATE_DECLARE]]#0 : !fir.ref +! CHECK: %{{.*}} = fir.load %[[PRIVATE_DECLARE]]#0 : !fir.ref ! CHECK: acc.yield ! CHECK: attributes {auto_ = [#acc.device_type], inclusiveUpperbound = array} +! CHECK-NOACCLOOP-LABEL: func.func @_QPbasic_do_loop_parallel +! CHECK-NOACCLOOP: acc.parallel { +! CHECK-NOACCLOOP-NOT: acc.loop + end subroutine ! CHECK-LABEL: func.func @_QPbasic_do_loop_serial @@ -77,10 +105,19 @@ subroutine basic_do_loop_serial() !$acc end serial ! CHECK: acc.serial { -! CHECK: acc.loop {{.*}} control(%{{.*}} : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) +! CHECK: %[[PRIVATE_IV:.*]] = acc.private varPtr(%{{.*}} : !fir.ref) -> !fir.ref {implicit = true, name = "i"} +! CHECK: %[[PRIVATE_DECLARE:.*]]:2 = hlfir.declare %[[PRIVATE_IV]] {uniq_name = "_QFbasic_do_loop_serialEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: acc.loop private(@privatization_ref_i32 -> %[[PRIVATE_IV]] : !fir.ref) control(%{{.*}} : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) +! CHECK: fir.store %{{.*}} to %[[PRIVATE_DECLARE]]#0 : !fir.ref +! CHECK: %{{.*}} = fir.load %[[PRIVATE_DECLARE]]#0 : !fir.ref +! CHECK: %{{.*}} = fir.load %[[PRIVATE_DECLARE]]#0 : !fir.ref ! CHECK: acc.yield ! CHECK: attributes {inclusiveUpperbound = array, seq = [#acc.device_type]} +! CHECK-NOACCLOOP-LABEL: func.func @_QPbasic_do_loop_serial +! CHECK-NOACCLOOP: acc.serial { +! CHECK-NOACCLOOP-NOT: acc.loop + end subroutine ! CHECK-LABEL: func.func @_QPbasic_do_concurrent_parallel @@ -97,10 +134,19 @@ subroutine basic_do_concurrent_parallel() !$acc end parallel ! CHECK: acc.parallel { -! CHECK: acc.loop {{.*}} control(%{{.*}} : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) +! CHECK: %[[PRIVATE_IV:.*]] = acc.private varPtr(%{{.*}} : !fir.ref) -> !fir.ref {implicit = true, name = "i"} +! CHECK: %[[PRIVATE_DECLARE:.*]]:2 = hlfir.declare %[[PRIVATE_IV]] {uniq_name = "_QFbasic_do_concurrent_parallelEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: acc.loop private(@privatization_ref_i32 -> %[[PRIVATE_IV]] : !fir.ref) control(%{{.*}} : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) +! CHECK: fir.store %{{.*}} to %[[PRIVATE_DECLARE]]#0 : !fir.ref +! CHECK: %{{.*}} = fir.load %[[PRIVATE_DECLARE]]#0 : !fir.ref +! CHECK: %{{.*}} = fir.load %[[PRIVATE_DECLARE]]#0 : !fir.ref ! CHECK: acc.yield ! CHECK: attributes {inclusiveUpperbound = array, independent = [#acc.device_type]} +! CHECK-NOACCLOOP-LABEL: func.func @_QPbasic_do_concurrent_parallel +! CHECK-NOACCLOOP: acc.parallel { +! CHECK-NOACCLOOP-NOT: acc.loop + end subroutine ! CHECK-LABEL: func.func @_QPbasic_do_concurrent_serial @@ -117,10 +163,19 @@ subroutine basic_do_concurrent_serial() !$acc end serial ! CHECK: acc.serial { -! CHECK: acc.loop {{.*}} control(%{{.*}} : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) +! CHECK: %[[PRIVATE_IV:.*]] = acc.private varPtr(%{{.*}} : !fir.ref) -> !fir.ref {implicit = true, name = "i"} +! CHECK: %[[PRIVATE_DECLARE:.*]]:2 = hlfir.declare %[[PRIVATE_IV]] {uniq_name = "_QFbasic_do_concurrent_serialEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: acc.loop private(@privatization_ref_i32 -> %[[PRIVATE_IV]] : !fir.ref) control(%{{.*}} : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) +! CHECK: fir.store %{{.*}} to %[[PRIVATE_DECLARE]]#0 : !fir.ref +! CHECK: %{{.*}} = fir.load %[[PRIVATE_DECLARE]]#0 : !fir.ref +! CHECK: %{{.*}} = fir.load %[[PRIVATE_DECLARE]]#0 : !fir.ref ! CHECK: acc.yield ! CHECK: attributes {inclusiveUpperbound = array, seq = [#acc.device_type]} +! CHECK-NOACCLOOP-LABEL: func.func @_QPbasic_do_concurrent_serial +! CHECK-NOACCLOOP: acc.serial { +! CHECK-NOACCLOOP-NOT: acc.loop + end subroutine ! CHECK-LABEL: func.func @_QPmulti_dimension_do_concurrent @@ -137,9 +192,29 @@ subroutine multi_dimension_do_concurrent() !$acc end kernels ! CHECK: acc.kernels { -! CHECK: acc.loop {{.*}} control(%{{.*}} : i32, %{{.*}} : i32, %{{.*}} : i32) = (%c1{{.*}}, %c1{{.*}}, %c1{{.*}} : i32, i32, i32) to (%{{.*}}, %{{.*}}, %{{.*}} : i32, i32, i32) step (%c1{{.*}}, %c1{{.*}}, %c1{{.*}} : i32, i32, i32) +! CHECK-DAG: %[[PRIVATE_I:.*]] = acc.private varPtr(%{{.*}} : !fir.ref) -> !fir.ref {implicit = true, name = "i"} +! CHECK-DAG: %[[PRIVATE_J:.*]] = acc.private varPtr(%{{.*}} : !fir.ref) -> !fir.ref {implicit = true, name = "j"} +! CHECK-DAG: %[[PRIVATE_K:.*]] = acc.private varPtr(%{{.*}} : !fir.ref) -> !fir.ref {implicit = true, name = "k"} +! CHECK-DAG: %[[PRIVATE_I_DECLARE:.*]]:2 = hlfir.declare %[[PRIVATE_I]] {uniq_name = "_QFmulti_dimension_do_concurrentEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK-DAG: %[[PRIVATE_J_DECLARE:.*]]:2 = hlfir.declare %[[PRIVATE_J]] {uniq_name = "_QFmulti_dimension_do_concurrentEj"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK-DAG: %[[PRIVATE_K_DECLARE:.*]]:2 = hlfir.declare %[[PRIVATE_K]] {uniq_name = "_QFmulti_dimension_do_concurrentEk"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: acc.loop private(@privatization_ref_i32 -> %[[PRIVATE_I]] : !fir.ref, @privatization_ref_i32 -> %[[PRIVATE_J]] : !fir.ref, @privatization_ref_i32 -> %[[PRIVATE_K]] : !fir.ref) control(%{{.*}} : i32, %{{.*}} : i32, %{{.*}} : i32) = (%c1{{.*}}, %c1{{.*}}, %c1{{.*}} : i32, i32, i32) to (%{{.*}}, %{{.*}}, %{{.*}} : i32, i32, i32) step (%c1{{.*}}, %c1{{.*}}, %c1{{.*}} : i32, i32, i32) +! CHECK: fir.store %{{.*}} to %[[PRIVATE_I_DECLARE]]#0 : !fir.ref +! CHECK: fir.store %{{.*}} to %[[PRIVATE_J_DECLARE]]#0 : !fir.ref +! CHECK: fir.store %{{.*}} to %[[PRIVATE_K_DECLARE]]#0 : !fir.ref +! CHECK: %{{.*}} = fir.load %[[PRIVATE_I_DECLARE]]#0 : !fir.ref +! CHECK: %{{.*}} = fir.load %[[PRIVATE_J_DECLARE]]#0 : !fir.ref +! CHECK: %{{.*}} = fir.load %[[PRIVATE_K_DECLARE]]#0 : !fir.ref +! CHECK: %{{.*}} = fir.load %[[PRIVATE_I_DECLARE]]#0 : !fir.ref +! CHECK: %{{.*}} = fir.load %[[PRIVATE_J_DECLARE]]#0 : !fir.ref +! CHECK: %{{.*}} = fir.load %[[PRIVATE_K_DECLARE]]#0 : !fir.ref ! CHECK: acc.yield ! CHECK: attributes {auto_ = [#acc.device_type], inclusiveUpperbound = array} + +! CHECK-NOACCLOOP-LABEL: func.func @_QPmulti_dimension_do_concurrent +! CHECK-NOACCLOOP: acc.kernels { +! CHECK-NOACCLOOP-NOT: acc.loop + end subroutine @@ -159,13 +234,27 @@ subroutine nested_do_loops() !$acc end kernels ! CHECK: acc.kernels { -! CHECK: acc.loop {{.*}} control(%{{.*}} : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) -! CHECK: acc.loop {{.*}} control(%{{.*}} : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) +! CHECK-DAG: %[[PRIVATE_I:.*]] = acc.private varPtr(%{{.*}} : !fir.ref) -> !fir.ref {implicit = true, name = "i"} +! CHECK-DAG: %[[PRIVATE_I_DECLARE:.*]]:2 = hlfir.declare %[[PRIVATE_I]] {uniq_name = "_QFnested_do_loopsEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: acc.loop private(@privatization_ref_i32 -> %[[PRIVATE_I]] : !fir.ref) control(%{{.*}} : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) +! CHECK: fir.store %{{.*}} to %[[PRIVATE_I_DECLARE]]#0 : !fir.ref +! CHECK-DAG: %[[PRIVATE_J:.*]] = acc.private varPtr(%{{.*}} : !fir.ref) -> !fir.ref {implicit = true, name = "j"} +! CHECK-DAG: %[[PRIVATE_J_DECLARE:.*]]:2 = hlfir.declare %[[PRIVATE_J]] {uniq_name = "_QFnested_do_loopsEj"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: acc.loop private(@privatization_ref_i32 -> %[[PRIVATE_J]] : !fir.ref) control(%{{.*}} : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) +! CHECK: fir.store %{{.*}} to %[[PRIVATE_J_DECLARE]]#0 : !fir.ref +! CHECK: %{{.*}} = fir.load %[[PRIVATE_I_DECLARE]]#0 : !fir.ref +! CHECK: %{{.*}} = fir.load %[[PRIVATE_J_DECLARE]]#0 : !fir.ref +! CHECK: %{{.*}} = fir.load %[[PRIVATE_I_DECLARE]]#0 : !fir.ref +! CHECK: %{{.*}} = fir.load %[[PRIVATE_J_DECLARE]]#0 : !fir.ref ! CHECK: acc.yield ! CHECK: attributes {auto_ = [#acc.device_type], inclusiveUpperbound = array} ! CHECK: acc.yield ! CHECK: attributes {auto_ = [#acc.device_type], inclusiveUpperbound = array} +! CHECK-NOACCLOOP-LABEL: func.func @_QPnested_do_loops +! CHECK-NOACCLOOP: acc.kernels { +! CHECK-NOACCLOOP-NOT: acc.loop + end subroutine ! CHECK-LABEL: func.func @_QPvariable_bounds_and_step @@ -182,10 +271,19 @@ subroutine variable_bounds_and_step(n, start_val, step_val) !$acc end kernels ! CHECK: acc.kernels { -! CHECK: acc.loop {{.*}} control(%{{.*}} : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) +! CHECK: %[[PRIVATE_IV:.*]] = acc.private varPtr(%{{.*}} : !fir.ref) -> !fir.ref {implicit = true, name = "i"} +! CHECK: %[[PRIVATE_DECLARE:.*]]:2 = hlfir.declare %[[PRIVATE_IV]] {uniq_name = "_QFvariable_bounds_and_stepEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: acc.loop private(@privatization_ref_i32 -> %[[PRIVATE_IV]] : !fir.ref) control(%{{.*}} : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) +! CHECK: fir.store %{{.*}} to %[[PRIVATE_DECLARE]]#0 : !fir.ref +! CHECK: %{{.*}} = fir.load %[[PRIVATE_DECLARE]]#0 : !fir.ref +! CHECK: %{{.*}} = fir.load %[[PRIVATE_DECLARE]]#0 : !fir.ref ! CHECK: acc.yield ! CHECK: attributes {auto_ = [#acc.device_type], inclusiveUpperbound = array} +! CHECK-NOACCLOOP-LABEL: func.func @_QPvariable_bounds_and_step +! CHECK-NOACCLOOP: acc.kernels { +! CHECK-NOACCLOOP-NOT: acc.loop + end subroutine ! CHECK-LABEL: func.func @_QPdifferent_iv_types @@ -216,11 +314,76 @@ subroutine different_iv_types() !$acc end kernels ! CHECK: acc.kernels { -! CHECK: acc.loop {{.*}} control(%{{.*}} : i64) = (%{{.*}} : i64) to (%{{.*}} : i64) step (%{{.*}} : i64) +! CHECK: %[[PRIVATE_I8:.*]] = acc.private varPtr(%{{.*}} : !fir.ref) -> !fir.ref {implicit = true, name = "i8"} +! CHECK: %[[PRIVATE_I8_DECLARE:.*]]:2 = hlfir.declare %[[PRIVATE_I8]] {uniq_name = "_QFdifferent_iv_typesEi8"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: acc.loop private(@privatization_ref_i64 -> %[[PRIVATE_I8]] : !fir.ref) control(%{{.*}} : i64) = (%{{.*}} : i64) to (%{{.*}} : i64) step (%{{.*}} : i64) +! CHECK: fir.store %{{.*}} to %[[PRIVATE_I8_DECLARE]]#0 : !fir.ref +! CHECK: %{{.*}} = fir.load %[[PRIVATE_I8_DECLARE]]#0 : !fir.ref +! CHECK: %{{.*}} = fir.load %[[PRIVATE_I8_DECLARE]]#0 : !fir.ref ! CHECK: acc.kernels { -! CHECK: acc.loop {{.*}} control(%{{.*}} : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) +! CHECK: %[[PRIVATE_I4:.*]] = acc.private varPtr(%{{.*}} : !fir.ref) -> !fir.ref {implicit = true, name = "i4"} +! CHECK: %[[PRIVATE_I4_DECLARE:.*]]:2 = hlfir.declare %[[PRIVATE_I4]] {uniq_name = "_QFdifferent_iv_typesEi4"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: acc.loop private(@privatization_ref_i32 -> %[[PRIVATE_I4]] : !fir.ref) control(%{{.*}} : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) +! CHECK: fir.store %{{.*}} to %[[PRIVATE_I4_DECLARE]]#0 : !fir.ref +! CHECK: %{{.*}} = fir.load %[[PRIVATE_I4_DECLARE]]#0 : !fir.ref +! CHECK: %{{.*}} = fir.load %[[PRIVATE_I4_DECLARE]]#0 : !fir.ref ! CHECK: acc.kernels { -! CHECK: acc.loop {{.*}} control(%{{.*}} : i16) = (%{{.*}} : i16) to (%{{.*}} : i16) step (%{{.*}} : i16) +! CHECK: %[[PRIVATE_I2:.*]] = acc.private varPtr(%{{.*}} : !fir.ref) -> !fir.ref {implicit = true, name = "i2"} +! CHECK: %[[PRIVATE_I2_DECLARE:.*]]:2 = hlfir.declare %[[PRIVATE_I2]] {uniq_name = "_QFdifferent_iv_typesEi2"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: acc.loop private(@privatization_ref_i16 -> %[[PRIVATE_I2]] : !fir.ref) control(%{{.*}} : i16) = (%{{.*}} : i16) to (%{{.*}} : i16) step (%{{.*}} : i16) +! CHECK: fir.store %{{.*}} to %[[PRIVATE_I2_DECLARE]]#0 : !fir.ref +! CHECK: %{{.*}} = fir.load %[[PRIVATE_I2_DECLARE]]#0 : !fir.ref +! CHECK: %{{.*}} = fir.load %[[PRIVATE_I2_DECLARE]]#0 : !fir.ref + +! CHECK-NOACCLOOP-LABEL: func.func @_QPdifferent_iv_types +! CHECK-NOACCLOOP: acc.kernels { +! CHECK-NOACCLOOP-NOT: acc.loop + +end subroutine + +! CHECK-LABEL: func.func @_QPnested_loop_with_reduction +subroutine nested_loop_with_reduction(x, y) + integer :: x, y + integer :: i, j + + ! Nested loop with reduction variables - check that reduction operations + ! are correctly scoped (outer loop reduction should not be inside inner loop) + !$acc parallel + !$acc loop reduction(+:x,y) + do i = 1, 10 + do j = 1, 20 + y = y + 1 + end do + x = x + 1 + end do + !$acc end parallel + +! CHECK: acc.parallel { +! CHECK: %[[REDUCTION_X:.*]] = acc.reduction varPtr(%{{.*}} : !fir.ref) -> !fir.ref {name = "x"} +! CHECK: %[[REDUCTION_Y:.*]] = acc.reduction varPtr(%{{.*}} : !fir.ref) -> !fir.ref {name = "y"} +! CHECK: %[[PRIVATE_I:.*]] = acc.private varPtr(%{{.*}} : !fir.ref) -> !fir.ref {implicit = true, name = "i"} +! CHECK: %[[PRIVATE_I_DECLARE:.*]]:2 = hlfir.declare %[[PRIVATE_I]] {uniq_name = "_QFnested_loop_with_reductionEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: acc.loop private(@privatization_ref_i32 -> %[[PRIVATE_I]] : !fir.ref) reduction(@reduction_add_ref_i32 -> %[[REDUCTION_X]] : !fir.ref, @reduction_add_ref_i32 -> %[[REDUCTION_Y]] : !fir.ref) control(%{{.*}} : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) +! CHECK: fir.store %{{.*}} to %[[PRIVATE_I_DECLARE]]#0 : !fir.ref +! CHECK: %[[PRIVATE_J:.*]] = acc.private varPtr(%{{.*}} : !fir.ref) -> !fir.ref {implicit = true, name = "j"} +! CHECK: %[[PRIVATE_J_DECLARE:.*]]:2 = hlfir.declare %[[PRIVATE_J]] {uniq_name = "_QFnested_loop_with_reductionEj"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: acc.loop private(@privatization_ref_i32 -> %[[PRIVATE_J]] : !fir.ref) control(%{{.*}} : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) +! CHECK: fir.store %{{.*}} to %[[PRIVATE_J_DECLARE]]#0 : !fir.ref +! CHECK: %{{.*}} = fir.load %{{.*}} : !fir.ref +! CHECK: %{{.*}} = arith.addi %{{.*}}, %{{.*}} : i32 +! CHECK: hlfir.assign %{{.*}} to %{{.*}} : i32, !fir.ref +! CHECK: acc.yield +! CHECK: attributes {auto_ = [#acc.device_type], inclusiveUpperbound = array} +! CHECK: %{{.*}} = fir.load %{{.*}} : !fir.ref +! CHECK: %{{.*}} = arith.addi %{{.*}}, %{{.*}} : i32 +! CHECK: hlfir.assign %{{.*}} to %{{.*}} : i32, !fir.ref +! CHECK: acc.yield +! CHECK: attributes {inclusiveUpperbound = array, independent = [#acc.device_type]} + +! CHECK-NOACCLOOP-LABEL: func.func @_QPnested_loop_with_reduction +! CHECK-NOACCLOOP: acc.parallel { +! CHECK-NOACCLOOP: acc.loop{{.*}}reduction{{.*}}control +! CHECK-NOACCLOOP-NOT: acc.loop end subroutine