diff --git a/flang/lib/Optimizer/Transforms/LoopVersioning.cpp b/flang/lib/Optimizer/Transforms/LoopVersioning.cpp index adc39861840ab..b534ec160ce21 100644 --- a/flang/lib/Optimizer/Transforms/LoopVersioning.cpp +++ b/flang/lib/Optimizer/Transforms/LoopVersioning.cpp @@ -145,11 +145,45 @@ struct ArgsUsageInLoop { }; } // namespace -static fir::SequenceType getAsSequenceType(mlir::Value *v) { - mlir::Type argTy = fir::unwrapPassByRefType(fir::unwrapRefType(v->getType())); +static fir::SequenceType getAsSequenceType(mlir::Value v) { + mlir::Type argTy = fir::unwrapPassByRefType(fir::unwrapRefType(v.getType())); return mlir::dyn_cast(argTy); } +/// Return the rank and the element size (in bytes) of the given +/// value \p v. If it is not an array or the element type is not +/// supported, then return <0, 0>. Only trivial data types +/// are currently supported. +/// When \p isArgument is true, \p v is assumed to be a function +/// argument. If \p v's type does not look like a type of an assumed +/// shape array, then the function returns <0, 0>. +/// When \p isArgument is false, array types with known innermost +/// dimension are allowed to proceed. +static std::pair +getRankAndElementSize(const fir::KindMapping &kindMap, + const mlir::DataLayout &dl, mlir::Value v, + bool isArgument = false) { + if (auto seqTy = getAsSequenceType(v)) { + unsigned rank = seqTy.getDimension(); + if (rank > 0 && + (!isArgument || + seqTy.getShape()[0] == fir::SequenceType::getUnknownExtent())) { + size_t typeSize = 0; + mlir::Type elementType = fir::unwrapSeqOrBoxedSeqType(v.getType()); + if (fir::isa_trivial(elementType)) { + auto [eleSize, eleAlign] = fir::getTypeSizeAndAlignmentOrCrash( + v.getLoc(), elementType, dl, kindMap); + typeSize = llvm::alignTo(eleSize, eleAlign); + } + if (typeSize) + return {rank, typeSize}; + } + } + + LLVM_DEBUG(llvm::dbgs() << "Unsupported rank/type: " << v << '\n'); + return {0, 0}; +} + /// if a value comes from a fir.declare, follow it to the original source, /// otherwise return the value static mlir::Value unwrapFirDeclare(mlir::Value val) { @@ -160,12 +194,48 @@ static mlir::Value unwrapFirDeclare(mlir::Value val) { return val; } +/// Return true, if \p rebox operation keeps the input array +/// continuous in the innermost dimension, if it is initially continuous +/// in the innermost dimension. +static bool reboxPreservesContinuity(fir::ReboxOp rebox) { + // If slicing is not involved, then the rebox does not affect + // the continuity of the array. + auto sliceArg = rebox.getSlice(); + if (!sliceArg) + return true; + + // A slice with step=1 in the innermost dimension preserves + // the continuity of the array in the innermost dimension. + if (auto sliceOp = + mlir::dyn_cast_or_null(sliceArg.getDefiningOp())) { + if (sliceOp.getFields().empty() && sliceOp.getSubstr().empty()) { + auto triples = sliceOp.getTriples(); + if (triples.size() > 2) + if (auto innermostStep = fir::getIntIfConstant(triples[2])) + if (*innermostStep == 1) + return true; + } + + LLVM_DEBUG(llvm::dbgs() + << "REBOX with slicing may produce non-contiguous array: " + << sliceOp << '\n' + << rebox << '\n'); + return false; + } + + LLVM_DEBUG(llvm::dbgs() << "REBOX with unknown slice" << sliceArg << '\n' + << rebox << '\n'); + return false; +} + /// if a value comes from a fir.rebox, follow the rebox to the original source, /// of the value, otherwise return the value static mlir::Value unwrapReboxOp(mlir::Value val) { - // don't support reboxes of reboxes - if (fir::ReboxOp rebox = val.getDefiningOp()) + while (fir::ReboxOp rebox = val.getDefiningOp()) { + if (!reboxPreservesContinuity(rebox)) + break; val = rebox.getBox(); + } return val; } @@ -257,25 +327,10 @@ void LoopVersioningPass::runOnOperation() { continue; } - if (auto seqTy = getAsSequenceType(&arg)) { - unsigned rank = seqTy.getDimension(); - if (rank > 0 && - seqTy.getShape()[0] == fir::SequenceType::getUnknownExtent()) { - size_t typeSize = 0; - mlir::Type elementType = fir::unwrapSeqOrBoxedSeqType(arg.getType()); - if (mlir::isa(elementType) || - mlir::isa(elementType) || - mlir::isa(elementType)) { - auto [eleSize, eleAlign] = fir::getTypeSizeAndAlignmentOrCrash( - arg.getLoc(), elementType, *dl, kindMap); - typeSize = llvm::alignTo(eleSize, eleAlign); - } - if (typeSize) - argsOfInterest.push_back({arg, typeSize, rank, {}}); - else - LLVM_DEBUG(llvm::dbgs() << "Type not supported\n"); - } - } + auto [rank, typeSize] = + getRankAndElementSize(kindMap, *dl, arg, /*isArgument=*/true); + if (rank != 0 && typeSize != 0) + argsOfInterest.push_back({arg, typeSize, rank, {}}); } if (argsOfInterest.empty()) { @@ -326,6 +381,13 @@ void LoopVersioningPass::runOnOperation() { if (arrayCoor.getSlice()) argsInLoop.cannotTransform.insert(a.arg); + // We need to compute the rank and element size + // based on the operand, not the original argument, + // because array slicing may affect it. + std::tie(a.rank, a.size) = getRankAndElementSize(kindMap, *dl, a.arg); + if (a.rank == 0 || a.size == 0) + argsInLoop.cannotTransform.insert(a.arg); + if (argsInLoop.cannotTransform.contains(a.arg)) { // Remove any previously recorded usage, if any. argsInLoop.usageInfo.erase(a.arg); @@ -416,8 +478,8 @@ void LoopVersioningPass::runOnOperation() { mlir::Location loc = builder.getUnknownLoc(); mlir::IndexType idxTy = builder.getIndexType(); - LLVM_DEBUG(llvm::dbgs() << "Module Before transformation:"); - LLVM_DEBUG(module->dump()); + LLVM_DEBUG(llvm::dbgs() << "Func Before transformation:\n"); + LLVM_DEBUG(func->dump()); LLVM_DEBUG(llvm::dbgs() << "loopsOfInterest: " << loopsOfInterest.size() << "\n"); @@ -551,8 +613,8 @@ void LoopVersioningPass::runOnOperation() { } } - LLVM_DEBUG(llvm::dbgs() << "After transform:\n"); - LLVM_DEBUG(module->dump()); + LLVM_DEBUG(llvm::dbgs() << "Func After transform:\n"); + LLVM_DEBUG(func->dump()); LLVM_DEBUG(llvm::dbgs() << "=== End " DEBUG_TYPE " ===\n"); } diff --git a/flang/test/Transforms/loop-versioning.fir b/flang/test/Transforms/loop-versioning.fir index 7528d14b3670d..2f7c439ed3f4e 100644 --- a/flang/test/Transforms/loop-versioning.fir +++ b/flang/test/Transforms/loop-versioning.fir @@ -113,8 +113,10 @@ func.func @sum1dfixed(%arg0: !fir.ref> {fir.bindc_name = "a"}, // CHECK-LABEL: func.func @sum1dfixed( // CHECK-SAME: %[[ARG0:.*]]: !fir.ref> {{.*}}) // CHECK: fir.do_loop {{.*}} +// CHECK-NOT: fir.do_loop // CHECK: %[[COORD:.*]] = fir.coordinate_of %[[ARG0]], {{.*}} // CHECK: %{{.*}} = fir.load %[[COORD]] +// CHECK-NOT: fir.do_loop // ----- @@ -1641,4 +1643,355 @@ func.func @_QPtest_complex10(%arg0: !fir.box>> {fir. // CHECK: } else { // CHECK: fir.do_loop +// Test that the loop is not versioned with non-contiguous slices: +//subroutine test_step2_slice(x, y) +// real :: x(:,:), y(:,:) +// do i=1,10 +// x(::2,i) = y(::2,i) + 1.0 +// end do +//end subroutine +func.func @_QPtest_step2_slice(%arg0: !fir.box> {fir.bindc_name = "x"}, %arg1: !fir.box> {fir.bindc_name = "y"}) { + %c10 = arith.constant 10 : index + %cst = arith.constant 1.000000e+00 : f32 + %c2 = arith.constant 2 : index + %c0 = arith.constant 0 : index + %c1 = arith.constant 1 : index + %0 = fir.dummy_scope : !fir.dscope + %1 = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFtest_step2_sliceEi"} + %2 = fir.declare %1 {uniq_name = "_QFtest_step2_sliceEi"} : (!fir.ref) -> !fir.ref + %3 = fir.declare %arg0 dummy_scope %0 {uniq_name = "_QFtest_step2_sliceEx"} : (!fir.box>, !fir.dscope) -> !fir.box> + %4 = fir.rebox %3 : (!fir.box>) -> !fir.box> + %5 = fir.declare %arg1 dummy_scope %0 {uniq_name = "_QFtest_step2_sliceEy"} : (!fir.box>, !fir.dscope) -> !fir.box> + %6 = fir.rebox %5 : (!fir.box>) -> !fir.box> + %7 = fir.convert %c1 : (index) -> i32 + %8:2 = fir.do_loop %arg2 = %c1 to %c10 step %c1 iter_args(%arg3 = %7) -> (index, i32) { + fir.store %arg3 to %2 : !fir.ref + %9:3 = fir.box_dims %6, %c0 : (!fir.box>, index) -> (index, index, index) + %10 = arith.addi %9#1, %c1 : index + %11 = arith.divsi %10, %c2 : index + %12 = arith.cmpi sgt, %11, %c0 : index + %13 = arith.select %12, %11, %c0 : index + %14 = fir.load %2 : !fir.ref + %15 = fir.convert %14 : (i32) -> i64 + %16 = fir.undefined index + %17 = fir.slice %c1, %9#1, %c2, %15, %16, %16 : (index, index, index, i64, index, index) -> !fir.slice<2> + %18 = fir.rebox %6 [%17] : (!fir.box>, !fir.slice<2>) -> !fir.box> + %19:3 = fir.box_dims %4, %c0 : (!fir.box>, index) -> (index, index, index) + %20 = fir.slice %c1, %19#1, %c2, %15, %16, %16 : (index, index, index, i64, index, index) -> !fir.slice<2> + %21 = fir.rebox %4 [%20] : (!fir.box>, !fir.slice<2>) -> !fir.box> + fir.do_loop %arg4 = %c1 to %13 step %c1 unordered { + %25 = fir.array_coor %18 %arg4 : (!fir.box>, index) -> !fir.ref + %26 = fir.load %25 : !fir.ref + %27 = arith.addf %26, %cst fastmath : f32 + %28 = fir.array_coor %21 %arg4 : (!fir.box>, index) -> !fir.ref + fir.store %27 to %28 : !fir.ref + } + %22 = arith.addi %arg2, %c1 overflow : index + %23 = fir.load %2 : !fir.ref + %24 = arith.addi %23, %7 overflow : i32 + fir.result %22, %24 : index, i32 + } + fir.store %8#1 to %2 : !fir.ref + return +} +// CHECK-LABEL: func.func @_QPtest_step2_slice( +// CHECK-NOT: fir.if + +// Test that the loop is versioned with most probably +// contiguous slices: +//subroutine test_step1_slice(x, y) +// real :: x(:,:), y(:,:) +// do i=1,10 +// x(:,i) = y(:,i) + 1.0 +// end do +//end subroutine +func.func @_QPtest_step1_slice(%arg0: !fir.box> {fir.bindc_name = "x"}, %arg1: !fir.box> {fir.bindc_name = "y"}) { + %c10 = arith.constant 10 : index + %cst = arith.constant 1.000000e+00 : f32 + %c0 = arith.constant 0 : index + %c1 = arith.constant 1 : index + %0 = fir.dummy_scope : !fir.dscope + %1 = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFtest_step1_sliceEi"} + %2 = fir.declare %1 {uniq_name = "_QFtest_step1_sliceEi"} : (!fir.ref) -> !fir.ref + %3 = fir.declare %arg0 dummy_scope %0 {uniq_name = "_QFtest_step1_sliceEx"} : (!fir.box>, !fir.dscope) -> !fir.box> + %4 = fir.rebox %3 : (!fir.box>) -> !fir.box> + %5 = fir.declare %arg1 dummy_scope %0 {uniq_name = "_QFtest_step1_sliceEy"} : (!fir.box>, !fir.dscope) -> !fir.box> + %6 = fir.rebox %5 : (!fir.box>) -> !fir.box> + %7 = fir.convert %c1 : (index) -> i32 + %8:2 = fir.do_loop %arg2 = %c1 to %c10 step %c1 iter_args(%arg3 = %7) -> (index, i32) { + fir.store %arg3 to %2 : !fir.ref + %9:3 = fir.box_dims %6, %c0 : (!fir.box>, index) -> (index, index, index) + %10 = arith.cmpi sgt, %9#1, %c0 : index + %11 = arith.select %10, %9#1, %c0 : index + %12 = fir.load %2 : !fir.ref + %13 = fir.convert %12 : (i32) -> i64 + %14 = fir.undefined index + %15 = fir.slice %c1, %9#1, %c1, %13, %14, %14 : (index, index, index, i64, index, index) -> !fir.slice<2> + %16 = fir.rebox %6 [%15] : (!fir.box>, !fir.slice<2>) -> !fir.box> + %17:3 = fir.box_dims %4, %c0 : (!fir.box>, index) -> (index, index, index) + %18 = fir.slice %c1, %17#1, %c1, %13, %14, %14 : (index, index, index, i64, index, index) -> !fir.slice<2> + %19 = fir.rebox %4 [%18] : (!fir.box>, !fir.slice<2>) -> !fir.box> + fir.do_loop %arg4 = %c1 to %11 step %c1 unordered { + %23 = fir.array_coor %16 %arg4 : (!fir.box>, index) -> !fir.ref + %24 = fir.load %23 : !fir.ref + %25 = arith.addf %24, %cst fastmath : f32 + %26 = fir.array_coor %19 %arg4 : (!fir.box>, index) -> !fir.ref + fir.store %25 to %26 : !fir.ref + } + %20 = arith.addi %arg2, %c1 overflow : index + %21 = fir.load %2 : !fir.ref + %22 = arith.addi %21, %7 overflow : i32 + fir.result %20, %22 : index, i32 + } + fir.store %8#1 to %2 : !fir.ref + return +} +// CHECK-LABEL: func.func @_QPtest_step1_slice( +// CHECK: fir.do_loop +// CHECK: fir.if +// CHECK: fir.do_loop +// CHECK: } else { +// CHECK: fir.do_loop + +// Test that the loop is versioned with logical arrays: +//subroutine test_logical_slice(x, y) +// logical :: x(:,:), y(:,:) +// do i=1,10 +// x(:,i) = y(:,i) .or. y(i,:) +// end do +//end subroutine +func.func @_QPtest_logical_slice(%arg0: !fir.box>> {fir.bindc_name = "x"}, %arg1: !fir.box>> {fir.bindc_name = "y"}) { + %c10 = arith.constant 10 : index + %c0 = arith.constant 0 : index + %c1 = arith.constant 1 : index + %0 = fir.dummy_scope : !fir.dscope + %1 = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFtest_logical_sliceEi"} + %2 = fir.declare %1 {uniq_name = "_QFtest_logical_sliceEi"} : (!fir.ref) -> !fir.ref + %3 = fir.declare %arg0 dummy_scope %0 {uniq_name = "_QFtest_logical_sliceEx"} : (!fir.box>>, !fir.dscope) -> !fir.box>> + %4 = fir.rebox %3 : (!fir.box>>) -> !fir.box>> + %5 = fir.declare %arg1 dummy_scope %0 {uniq_name = "_QFtest_logical_sliceEy"} : (!fir.box>>, !fir.dscope) -> !fir.box>> + %6 = fir.rebox %5 : (!fir.box>>) -> !fir.box>> + %7 = fir.convert %c1 : (index) -> i32 + %8:2 = fir.do_loop %arg2 = %c1 to %c10 step %c1 iter_args(%arg3 = %7) -> (index, i32) { + fir.store %arg3 to %2 : !fir.ref + %9:3 = fir.box_dims %6, %c0 : (!fir.box>>, index) -> (index, index, index) + %10 = arith.cmpi sgt, %9#1, %c0 : index + %11 = arith.select %10, %9#1, %c0 : index + %12 = fir.load %2 : !fir.ref + %13 = fir.convert %12 : (i32) -> i64 + %14 = fir.undefined index + %15 = fir.slice %c1, %9#1, %c1, %13, %14, %14 : (index, index, index, i64, index, index) -> !fir.slice<2> + %16 = fir.rebox %6 [%15] : (!fir.box>>, !fir.slice<2>) -> !fir.box>> + %17:3 = fir.box_dims %6, %c1 : (!fir.box>>, index) -> (index, index, index) + %18 = fir.slice %13, %14, %14, %c1, %17#1, %c1 : (i64, index, index, index, index, index) -> !fir.slice<2> + %19 = fir.rebox %6 [%18] : (!fir.box>>, !fir.slice<2>) -> !fir.box>> + %20:3 = fir.box_dims %4, %c0 : (!fir.box>>, index) -> (index, index, index) + %21 = fir.slice %c1, %20#1, %c1, %13, %14, %14 : (index, index, index, i64, index, index) -> !fir.slice<2> + %22 = fir.rebox %4 [%21] : (!fir.box>>, !fir.slice<2>) -> !fir.box>> + fir.do_loop %arg4 = %c1 to %11 step %c1 unordered { + %26 = fir.array_coor %16 %arg4 : (!fir.box>>, index) -> !fir.ref> + %27 = fir.array_coor %19 %arg4 : (!fir.box>>, index) -> !fir.ref> + %28 = fir.load %26 : !fir.ref> + %29 = fir.load %27 : !fir.ref> + %30 = fir.convert %28 : (!fir.logical<4>) -> i1 + %31 = fir.convert %29 : (!fir.logical<4>) -> i1 + %32 = arith.ori %30, %31 : i1 + %33 = fir.convert %32 : (i1) -> !fir.logical<4> + %34 = fir.array_coor %22 %arg4 : (!fir.box>>, index) -> !fir.ref> + fir.store %33 to %34 : !fir.ref> + } + %23 = arith.addi %arg2, %c1 overflow : index + %24 = fir.load %2 : !fir.ref + %25 = arith.addi %24, %7 overflow : i32 + fir.result %23, %25 : index, i32 + } + fir.store %8#1 to %2 : !fir.ref + return +} +// CHECK-LABEL: func.func @_QPtest_logical_slice( +// CHECK: fir.do_loop +// CHECK: fir.if +// CHECK: fir.do_loop +// CHECK: } else { +// CHECK: fir.do_loop + +// Test that the loop is versioned when a most probably +// contiguous slices have known shape: +//subroutine test_known_shape_slice(x, y) +// integer :: x(:,:), y(:,:) +// do i=1,10 +// x(1:10,i) = y(1:10,i) + 1 +// end do +//end subroutine +func.func @_QPtest_known_shape_slice(%arg0: !fir.box> {fir.bindc_name = "x"}, %arg1: !fir.box> {fir.bindc_name = "y"}) { + %c10 = arith.constant 10 : index + %c1 = arith.constant 1 : index + %c1_i32 = arith.constant 1 : i32 + %0 = fir.dummy_scope : !fir.dscope + %1 = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFtest_known_shape_sliceEi"} + %2 = fir.declare %1 {uniq_name = "_QFtest_known_shape_sliceEi"} : (!fir.ref) -> !fir.ref + %3 = fir.declare %arg0 dummy_scope %0 {uniq_name = "_QFtest_known_shape_sliceEx"} : (!fir.box>, !fir.dscope) -> !fir.box> + %4 = fir.rebox %3 : (!fir.box>) -> !fir.box> + %5 = fir.declare %arg1 dummy_scope %0 {uniq_name = "_QFtest_known_shape_sliceEy"} : (!fir.box>, !fir.dscope) -> !fir.box> + %6 = fir.rebox %5 : (!fir.box>) -> !fir.box> + %7 = fir.convert %c1 : (index) -> i32 + %8:2 = fir.do_loop %arg2 = %c1 to %c10 step %c1 iter_args(%arg3 = %7) -> (index, i32) { + fir.store %arg3 to %2 : !fir.ref + %9 = fir.load %2 : !fir.ref + %10 = fir.convert %9 : (i32) -> i64 + %11 = fir.undefined index + %12 = fir.slice %c1, %c10, %c1, %10, %11, %11 : (index, index, index, i64, index, index) -> !fir.slice<2> + %13 = fir.rebox %6 [%12] : (!fir.box>, !fir.slice<2>) -> !fir.box> + %14 = fir.rebox %4 [%12] : (!fir.box>, !fir.slice<2>) -> !fir.box> + fir.do_loop %arg4 = %c1 to %c10 step %c1 unordered { + %18 = fir.array_coor %13 %arg4 : (!fir.box>, index) -> !fir.ref + %19 = fir.load %18 : !fir.ref + %20 = arith.addi %19, %c1_i32 : i32 + %21 = fir.array_coor %14 %arg4 : (!fir.box>, index) -> !fir.ref + fir.store %20 to %21 : !fir.ref + } + %15 = arith.addi %arg2, %c1 overflow : index + %16 = fir.load %2 : !fir.ref + %17 = arith.addi %16, %7 overflow : i32 + fir.result %15, %17 : index, i32 + } + fir.store %8#1 to %2 : !fir.ref + return +} +// CHECK-LABEL: func.func @_QPtest_known_shape_slice( +// CHECK: fir.do_loop +// CHECK: fir.if +// CHECK: fir.do_loop +// CHECK: } else { +// CHECK: fir.do_loop + +// Test that the loop is not versioned for most probably +// not-contiguous slices: +//subroutine test_maybe_noncontig_slice(x, y) +// real :: x(:,:), y(:,:) +// do i=1,10 +// x(i,:) = y(i,:) + 1.0 +// end do +//end subroutine +func.func @_QPtest_maybe_noncontig_slice(%arg0: !fir.box> {fir.bindc_name = "x"}, %arg1: !fir.box> {fir.bindc_name = "y"}) { + %c10 = arith.constant 10 : index + %cst = arith.constant 1.000000e+00 : f32 + %c0 = arith.constant 0 : index + %c1 = arith.constant 1 : index + %0 = fir.dummy_scope : !fir.dscope + %1 = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFtest_maybe_noncontig_sliceEi"} + %2 = fir.declare %1 {uniq_name = "_QFtest_maybe_noncontig_sliceEi"} : (!fir.ref) -> !fir.ref + %3 = fir.declare %arg0 dummy_scope %0 {uniq_name = "_QFtest_maybe_noncontig_sliceEx"} : (!fir.box>, !fir.dscope) -> !fir.box> + %4 = fir.rebox %3 : (!fir.box>) -> !fir.box> + %5 = fir.declare %arg1 dummy_scope %0 {uniq_name = "_QFtest_maybe_noncontig_sliceEy"} : (!fir.box>, !fir.dscope) -> !fir.box> + %6 = fir.rebox %5 : (!fir.box>) -> !fir.box> + %7 = fir.convert %c1 : (index) -> i32 + %8:2 = fir.do_loop %arg2 = %c1 to %c10 step %c1 iter_args(%arg3 = %7) -> (index, i32) { + fir.store %arg3 to %2 : !fir.ref + %9 = fir.load %2 : !fir.ref + %10 = fir.convert %9 : (i32) -> i64 + %11:3 = fir.box_dims %6, %c1 : (!fir.box>, index) -> (index, index, index) + %12 = arith.cmpi sgt, %11#1, %c0 : index + %13 = arith.select %12, %11#1, %c0 : index + %14 = fir.undefined index + %15 = fir.slice %10, %14, %14, %c1, %11#1, %c1 : (i64, index, index, index, index, index) -> !fir.slice<2> + %16 = fir.rebox %6 [%15] : (!fir.box>, !fir.slice<2>) -> !fir.box> + %17:3 = fir.box_dims %4, %c1 : (!fir.box>, index) -> (index, index, index) + %18 = fir.slice %10, %14, %14, %c1, %17#1, %c1 : (i64, index, index, index, index, index) -> !fir.slice<2> + %19 = fir.rebox %4 [%18] : (!fir.box>, !fir.slice<2>) -> !fir.box> + fir.do_loop %arg4 = %c1 to %13 step %c1 unordered { + %23 = fir.array_coor %16 %arg4 : (!fir.box>, index) -> !fir.ref + %24 = fir.load %23 : !fir.ref + %25 = arith.addf %24, %cst fastmath : f32 + %26 = fir.array_coor %19 %arg4 : (!fir.box>, index) -> !fir.ref + fir.store %25 to %26 : !fir.ref + } + %20 = arith.addi %arg2, %c1 overflow : index + %21 = fir.load %2 : !fir.ref + %22 = arith.addi %21, %7 overflow : i32 + fir.result %20, %22 : index, i32 + } + fir.store %8#1 to %2 : !fir.ref + return +} +// CHECK-LABEL: func.func @_QPtest_maybe_noncontig_slice( +// CHECK-NOT: fir.if + +// Regression test for facerec's GraphSimFct: +//real function test_graphsimfct(a1, a2) +// integer :: i +// real, intent(in) :: a1(:,:,:) +// real, intent(in) :: a2(:,:,:,:) +// graphsimfct = 0.0 +// do i=1,10 +// test_graphsimfct = test_graphsimfct + SUM(a1(:,:,i) * a2(:,:,i,i)) +// end do +//end function +func.func @_QPtest_graphsimfct(%arg0: !fir.box> {fir.bindc_name = "a1"}, %arg1: !fir.box> {fir.bindc_name = "a2"}) -> f32 { + %c10 = arith.constant 10 : index + %c0 = arith.constant 0 : index + %c1 = arith.constant 1 : index + %cst = arith.constant 0.000000e+00 : f32 + %0 = fir.dummy_scope : !fir.dscope + %1 = fir.declare %arg0 dummy_scope %0 {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest_graphsimfctEa1"} : (!fir.box>, !fir.dscope) -> !fir.box> + %2 = fir.rebox %1 : (!fir.box>) -> !fir.box> + %3 = fir.declare %arg1 dummy_scope %0 {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest_graphsimfctEa2"} : (!fir.box>, !fir.dscope) -> !fir.box> + %4 = fir.rebox %3 : (!fir.box>) -> !fir.box> + %5 = fir.alloca f32 {bindc_name = "graphsimfct", uniq_name = "_QFtest_graphsimfctEgraphsimfct"} + %6 = fir.declare %5 {uniq_name = "_QFtest_graphsimfctEgraphsimfct"} : (!fir.ref) -> !fir.ref + %7 = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFtest_graphsimfctEi"} + %8 = fir.declare %7 {uniq_name = "_QFtest_graphsimfctEi"} : (!fir.ref) -> !fir.ref + %9 = fir.alloca f32 {bindc_name = "test_graphsimfct", uniq_name = "_QFtest_graphsimfctEtest_graphsimfct"} + %10 = fir.declare %9 {uniq_name = "_QFtest_graphsimfctEtest_graphsimfct"} : (!fir.ref) -> !fir.ref + fir.store %cst to %6 : !fir.ref + %11 = fir.convert %c1 : (index) -> i32 + %12:2 = fir.do_loop %arg2 = %c1 to %c10 step %c1 iter_args(%arg3 = %11) -> (index, i32) { + fir.store %arg3 to %8 : !fir.ref + %14 = fir.load %10 : !fir.ref + %15:3 = fir.box_dims %2, %c0 : (!fir.box>, index) -> (index, index, index) + %16:3 = fir.box_dims %2, %c1 : (!fir.box>, index) -> (index, index, index) + %17 = arith.cmpi sgt, %15#1, %c0 : index + %18 = arith.select %17, %15#1, %c0 : index + %19 = arith.cmpi sgt, %16#1, %c0 : index + %20 = arith.select %19, %16#1, %c0 : index + %21 = fir.load %8 : !fir.ref + %22 = fir.convert %21 : (i32) -> i64 + %23 = fir.undefined index + %24 = fir.slice %c1, %15#1, %c1, %c1, %16#1, %c1, %22, %23, %23 : (index, index, index, index, index, index, i64, index, index) -> !fir.slice<3> + %25 = fir.rebox %2 [%24] : (!fir.box>, !fir.slice<3>) -> !fir.box> + %26:3 = fir.box_dims %4, %c0 : (!fir.box>, index) -> (index, index, index) + %27:3 = fir.box_dims %4, %c1 : (!fir.box>, index) -> (index, index, index) + %28 = fir.slice %c1, %26#1, %c1, %c1, %27#1, %c1, %22, %23, %23, %22, %23, %23 : (index, index, index, index, index, index, i64, index, index, i64, index, index) -> !fir.slice<4> + %29 = fir.rebox %4 [%28] : (!fir.box>, !fir.slice<4>) -> !fir.box> + %30 = fir.do_loop %arg4 = %c1 to %20 step %c1 unordered iter_args(%arg5 = %cst) -> (f32) { + %35 = fir.do_loop %arg6 = %c1 to %18 step %c1 unordered iter_args(%arg7 = %arg5) -> (f32) { + %36 = fir.array_coor %25 %arg6, %arg4 : (!fir.box>, index, index) -> !fir.ref + %37 = fir.array_coor %29 %arg6, %arg4 : (!fir.box>, index, index) -> !fir.ref + %38 = fir.load %36 : !fir.ref + %39 = fir.load %37 : !fir.ref + %40 = arith.mulf %38, %39 fastmath : f32 + %41 = arith.addf %arg7, %40 fastmath : f32 + fir.result %41 : f32 + } + fir.result %35 : f32 + } + %31 = arith.addf %14, %30 fastmath : f32 + fir.store %31 to %10 : !fir.ref + %32 = arith.addi %arg2, %c1 overflow : index + %33 = fir.load %8 : !fir.ref + %34 = arith.addi %33, %11 overflow : i32 + fir.result %32, %34 : index, i32 + } + fir.store %12#1 to %8 : !fir.ref + %13 = fir.load %10 : !fir.ref + return %13 : f32 +} +// CHECK-LABEL: func.func @_QPtest_graphsimfct( +// CHECK: fir.do_loop +// CHECK: fir.do_loop +// CHECK: fir.if +// CHECK: fir.do_loop +// CHECK: } else { +// CHECK: fir.do_loop + } // End module