Slava Zakharin d6e20c42c1
[flang] Clean-up for fir.do_loop generation in lowering. (#160630)
This patch changes two things:
  1. We do not need to use the loop counter's last value
     for regular do-loops in Lowering.
  2. The loop counter's increment is implied by fir.do_loop
     operation, so there is no need to increment it explicitly.

The last point has been especially confusing to me, because it was
unclear why we have an explicit increment if it is implied.
It looks like CFGConversion somehow still makes the final code
correct, i.e. the counter is not incremented twice.
Anyway, the new lowering should look more concise.
2025-09-26 09:40:04 -07:00

197 lines
6.0 KiB
MLIR

// RUN: fir-opt --split-input-file --verify-diagnostics --omp-simd-only %s | FileCheck %s
// Check that simd operations are not removed and rewritten, but all the other OpenMP ops are.
// Tests the logic in flang/lib/Optimizer/OpenMP/SimdOnly.cpp
// CHECK: omp.private
// CHECK-LABEL: func.func @simd
omp.private {type = private} @_QFEi_private_i32 : i32
func.func @simd(%arg0: i32, %arg1: !fir.ref<i32>, %arg2: !fir.ref<i32>) {
%c1_i32 = arith.constant 1 : i32
%c100000_i32 = arith.constant 100000 : i32
// CHECK: omp.simd private
omp.simd private(@_QFEi_private_i32 %arg2 -> %arg3 : !fir.ref<i32>) {
// CHECK: omp.loop_nest
omp.loop_nest (%arg4) : i32 = (%c1_i32) to (%c100000_i32) inclusive step (%c1_i32) {
// CHECK: fir.store
fir.store %arg0 to %arg1 : !fir.ref<i32>
// CHECK: omp.yield
omp.yield
}
}
return
}
// -----
// CHECK-LABEL: func.func @simd_composite
func.func @simd_composite(%arg0: i32, %arg1: !fir.ref<i32>) {
%c1_i32 = arith.constant 1 : i32
%c100000_i32 = arith.constant 100000 : i32
// CHECK-NOT: omp.parallel
omp.parallel {
// CHECK-NOT: omp.wsloop
omp.wsloop {
// CHECK: omp.simd
omp.simd {
// CHECK: omp.loop_nest
omp.loop_nest (%arg3) : i32 = (%c1_i32) to (%c100000_i32) inclusive step (%c1_i32) {
// CHECK: fir.store
fir.store %arg0 to %arg1 : !fir.ref<i32>
// CHECK: omp.yield
omp.yield
}
// CHECK-NOT: {omp.composite}
} {omp.composite}
} {omp.composite}
omp.terminator
}
return
}
// -----
// CHECK-NOT: omp.private
// CHECK-LABEL: func.func @parallel
omp.private {type = private} @_QFEi_private_i32 : i32
func.func @parallel(%arg0: i32, %arg1: !fir.ref<i32>) {
%c1 = arith.constant 1 : index
%c1_i32 = arith.constant 1 : i32
%c100000_i32 = arith.constant 100000 : i32
// CHECK-NOT: omp.parallel
omp.parallel private(@_QFEi_private_i32 %arg1 -> %arg3 : !fir.ref<i32>) {
// CHECK: fir.convert
%15 = fir.convert %c1_i32 : (i32) -> index
// CHECK: fir.convert
%16 = fir.convert %c100000_i32 : (i32) -> index
// CHECK: fir.do_loop
%18 = fir.do_loop %arg4 = %15 to %16 step %c1 iter_args(%arg2 = %arg0) -> (i32) {
// CHECK: fir.store
fir.store %arg0 to %arg1 : !fir.ref<i32>
fir.result %arg2 : i32
}
// CHECK-NOT: omp.terminator
omp.terminator
}
return
}
// -----
// CHECK-LABEL: func.func @target_map(
// CHECK-SAME: %[[ARG_0:.*]]: i32, %[[ARG_1:.*]]: !fir.ref<i32>
func.func @target_map(%arg5: i32, %arg6: !fir.ref<i32>) {
// CHECK-NOT: omp.map.info
%3 = omp.map.info var_ptr(%arg6 : !fir.ref<i32>, i32) map_clauses(implicit) capture(ByCopy) -> !fir.ref<i32>
// CHECK-NOT: omp.target
omp.target map_entries(%3 -> %arg0 : !fir.ref<i32>) {
// CHECK: arith.constant
%c1_i32 = arith.constant 1 : i32
// CHECK: fir.store %c1_i32 to %[[ARG_1]]
fir.store %c1_i32 to %arg0 : !fir.ref<i32>
// CHECK-NOT: omp.terminator
omp.terminator
}
return
}
// -----
// CHECK-LABEL: func.func @teams
func.func @teams(%arg0: i32, %arg1: !fir.ref<i32>) {
// CHECK-NOT: omp.teams
omp.teams {
// CHECK: fir.store
fir.store %arg0 to %arg1 : !fir.ref<i32>
// CHECK-NOT: omp.terminator
omp.terminator
}
return
}
// -----
// CHECK-LABEL: func.func @distribute_simd
func.func @distribute_simd(%arg0: i32, %arg1: !fir.ref<i32>) {
%c1_i32 = arith.constant 1 : i32
%c100000_i32 = arith.constant 100000 : i32
// CHECK-NOT: omp.distribute
omp.distribute {
// CHECK: omp.simd
omp.simd {
// CHECK: omp.loop_nest
omp.loop_nest (%arg3) : i32 = (%c1_i32) to (%c100000_i32) inclusive step (%c1_i32) {
// CHECK: fir.store
fir.store %arg0 to %arg1 : !fir.ref<i32>
// CHECK: omp.yield
omp.yield
}
// CHECK-NOT: {omp.composite}
} {omp.composite}
// CHECK-NOT: {omp.composite}
} {omp.composite}
return
}
// -----
// CHECK-LABEL: func.func @threadprivate(
// CHECK-SAME: %[[ARG_0:.*]]: i32, %[[ARG_1:.*]]: !fir.ref<i32>
func.func @threadprivate(%arg0: i32, %arg1: !fir.ref<i32>) {
// CHECK-NOT: omp.threadprivate
%1 = omp.threadprivate %arg1 : !fir.ref<i32> -> !fir.ref<i32>
// CHECK: fir.store %[[ARG_0]] to %[[ARG_1]]
fir.store %arg0 to %1 : !fir.ref<i32>
return
}
// -----
// CHECK-LABEL: func.func @multi_block(
// CHECK-SAME: %[[ARG_0:.*]]: i32, %[[ARG_1:.*]]: !fir.ref<i32>, %[[ARG_3:.*]]: i1
func.func @multi_block(%funcArg0: i32, %funcArg1: !fir.ref<i32>, %6: i1) {
%false = arith.constant false
%c0_i32 = arith.constant 0 : i32
// CHECK-NOT: omp.parallel
omp.parallel {
// CHECK: cf.cond_br %[[ARG_3]], ^[[BB1:.*]], ^[[BB2:.*]]
cf.cond_br %6, ^bb1, ^bb2
// CHECK: ^[[BB1]]
^bb1: // pred: ^bb0
// CHECK: fir.call
fir.call @_FortranAStopStatement(%c0_i32, %false, %false) fastmath<contract> : (i32, i1, i1) -> ()
// CHECK-NOT: omp.terminator
omp.terminator
// CHECK: ^[[BB2]]
^bb2: // pred: ^bb0
// CHECK: fir.store
fir.store %funcArg0 to %funcArg1 : !fir.ref<i32>
// CHECK-NOT: omp.terminator
omp.terminator
}
return
}
// -----
// CHECK-LABEL: func.func @map_info(
// CHECK-SAME: %[[ARG_0:.*]]: i32, %[[ARG_1:.*]]: !fir.ref<i32>
func.func @map_info(%funcArg0: i32, %funcArg1: !fir.ref<i32>) {
%c1 = arith.constant 1 : index
// CHECK-NOT: omp.map.bounds
%1 = omp.map.bounds lower_bound(%c1 : index) upper_bound(%c1 : index) extent(%c1 : index) stride(%c1 : index) start_idx(%c1 : index)
// CHECK-NOT: omp.map.info
%13 = omp.map.info var_ptr(%funcArg1 : !fir.ref<i32>, i32) map_clauses(to) capture(ByRef) bounds(%1) -> !fir.ref<i32>
// CHECK-NOT: omp.target
omp.target map_entries(%13 -> %arg3 : !fir.ref<i32>) {
%c1_i32 = arith.constant 1 : i32
// CHECK: fir.store %c1_i32 to %[[ARG_1]]
fir.store %c1_i32 to %arg3 : !fir.ref<i32>
// CHECK-NOT: omp.terminator
omp.terminator
}
// CHECK-NOT: omp.map.info
%18 = omp.map.info var_ptr(%funcArg1 : !fir.ref<i32>, i32) map_clauses(from) capture(ByRef) bounds(%1) -> !fir.ref<i32>
return
}