diff --git a/flang/lib/Optimizer/Transforms/SimplifyIntrinsics.cpp b/flang/lib/Optimizer/Transforms/SimplifyIntrinsics.cpp --- a/flang/lib/Optimizer/Transforms/SimplifyIntrinsics.cpp +++ b/flang/lib/Optimizer/Transforms/SimplifyIntrinsics.cpp @@ -82,9 +82,14 @@ void simplifyIntOrFloatReduction(fir::CallOp call, const fir::KindMapping &kindMap, GenReductionBodyTy genBodyFunc); - void simplifyLogicalReduction(fir::CallOp call, - const fir::KindMapping &kindMap, - GenReductionBodyTy genBodyFunc); + void simplifyLogicalDim0Reduction(fir::CallOp call, + const fir::KindMapping &kindMap, + GenReductionBodyTy genBodyFunc); + void simplifyLogicalDim1Reduction(fir::CallOp call, + const fir::KindMapping &kindMap, + GenReductionBodyTy genBodyFunc); + void simplifyAnyReduction(fir::CallOp call, const fir::KindMapping &kindMap, + GenReductionBodyTy genBodyFunc); void simplifyReductionBody(fir::CallOp call, const fir::KindMapping &kindMap, GenReductionBodyTy genBodyFunc, fir::FirOpBuilder &builder, @@ -237,6 +242,103 @@ builder.create(loc, reductionVal); } +using ContinueLoopGenTy = llvm::function_ref( + fir::FirOpBuilder &, mlir::Location, mlir::Value)>; + +static void genEarlyExitLoop(fir::FirOpBuilder &builder, mlir::Type elementType, + mlir::func::FuncOp &funcOp, + InitValGeneratorTy initVal, + ContinueLoopGenTy loopCond, + BodyOpGeneratorTy genBody, unsigned rank) { + auto loc = mlir::UnknownLoc::get(builder.getContext()); + builder.setInsertionPointToEnd(funcOp.addEntryBlock()); + + mlir::IndexType idxTy = builder.getIndexType(); + + mlir::Block::BlockArgListType args = funcOp.front().getArguments(); + mlir::Value arg = args[0]; + + mlir::Value zeroIdx = builder.createIntegerConstant(loc, idxTy, 0); + + fir::SequenceType::Shape flatShape(rank, + fir::SequenceType::getUnknownExtent()); + mlir::Type arrTy = fir::SequenceType::get(flatShape, elementType); + mlir::Type boxArrTy = fir::BoxType::get(arrTy); + mlir::Value array = builder.create(loc, boxArrTy, arg); + mlir::Type resultType = funcOp.getResultTypes()[0]; + mlir::Value init = initVal(builder, loc, resultType); + + llvm::SmallVector bounds; + + assert(rank > 0 && "rank cannot be zero"); + mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1); + + // Compute all the upper bounds before the loop nest. + // It is not strictly necessary for performance, since the loop nest + // does not have any store operations and any LICM optimization + // should be able to optimize the redundancy. + for (unsigned i = 0; i < rank; ++i) { + mlir::Value dimIdx = builder.createIntegerConstant(loc, idxTy, i); + auto dims = + builder.create(loc, idxTy, idxTy, idxTy, array, dimIdx); + mlir::Value len = dims.getResult(1); + // We use C indexing here, so len-1 as loopcount + mlir::Value loopCount = builder.create(loc, len, one); + bounds.push_back(loopCount); + } + + // Create a loop nest consisting of IterWhileOp operations. + // Collect the loops' induction variables into indices array, + // which will be used in the innermost loop to load the input + // array's element. + // The loops are generated such that the innermost loop processes + // the 0 dimension. + llvm::SmallVector indices; + for (unsigned i = rank; 0 < i; --i) { + mlir::Value step = one; + mlir::Value loopCount = bounds[i - 1]; + auto ok = builder.createBool(loc, true); + auto loop = builder.create( + loc, zeroIdx, loopCount, step, ok, /*finalCountValue=*/false, init); + init = loop.getRegionIterArgs()[0]; + indices.push_back(loop.getInductionVar()); + // Set insertion point to the loop body so that the next loop + // is inserted inside the current one. + builder.setInsertionPointToStart(loop.getBody()); + } + + // Reverse the indices such that they are ordered as: + // + std::reverse(indices.begin(), indices.end()); + + // We are in the innermost loop: generate the reduction body. + mlir::Type eleRefTy = builder.getRefType(elementType); + mlir::Value addr = + builder.create(loc, eleRefTy, array, indices); + mlir::Value elem = builder.create(loc, addr); + + mlir::Value reductionVal = genBody(builder, loc, elementType, elem, init); + // Generate vector with condition to continue while loop at [0] and result + // from current loop at [1] + auto results = loopCond(builder, loc, reductionVal); + + // Unwind the loop nest and insert ResultOp on each level + // to return the updated value of the reduction to the enclosing + // loops. + for (unsigned i = 0; i < rank; ++i) { + auto result = builder.create(loc, results); + // Proceed to the outer loop. + auto loop = mlir::cast(result->getParentOp()); + results = loop.getResults(); + // Set insertion point after the loop operation that we have + // just processed. + builder.setInsertionPointAfter(loop.getOperation()); + } + // End of loop nest. The insertion point is after the outermost loop. + // Return the reduction value from the function. + builder.create(loc, results[1]); +} + /// Generate function body of the simplified version of RTNAME(Sum) /// with signature provided by \p funcOp. The caller is responsible /// for saving/restoring the original insertion point of \p builder. @@ -339,6 +441,62 @@ genReductionLoop(builder, elementType, funcOp, zero, genBodyOp, rank); } +static void genRuntimeAnyBody(fir::FirOpBuilder &builder, + mlir::func::FuncOp &funcOp, unsigned rank) { + auto zero = [](fir::FirOpBuilder builder, mlir::Location loc, + mlir::Type elementType) { + return builder.createIntegerConstant(loc, elementType, 0); + }; + + auto genBodyOp = [](fir::FirOpBuilder builder, mlir::Location loc, + mlir::Type elementType, mlir::Value elem1, + mlir::Value elem2) -> mlir::Value { + auto zero32 = builder.createIntegerConstant(loc, builder.getI32Type(), 0); + return builder.create( + loc, mlir::arith::CmpIPredicate::ne, elem1, zero32); + }; + + auto continueCond = [](fir::FirOpBuilder builder, mlir::Location loc, + mlir::Value reductionVal) { + auto one1 = builder.createIntegerConstant(loc, builder.getI1Type(), 1); + auto eor = builder.create(loc, reductionVal, one1); + llvm::SmallVector results = {eor, reductionVal}; + return results; + }; + + mlir::Type elementType = builder.getI32Type(); + + genEarlyExitLoop(builder, elementType, funcOp, zero, continueCond, genBodyOp, + rank); +} + +static void genRuntimeAllBody(fir::FirOpBuilder &builder, + mlir::func::FuncOp &funcOp, unsigned rank) { + auto zero = [](fir::FirOpBuilder builder, mlir::Location loc, + mlir::Type elementType) { + return builder.createIntegerConstant(loc, elementType, 1); + }; + + auto genBodyOp = [](fir::FirOpBuilder builder, mlir::Location loc, + mlir::Type elementType, mlir::Value elem1, + mlir::Value elem2) -> mlir::Value { + auto one32 = builder.createIntegerConstant(loc, builder.getI32Type(), 1); + return builder.create( + loc, mlir::arith::CmpIPredicate::eq, elem1, one32); + }; + + auto continueCond = [](fir::FirOpBuilder builder, mlir::Location loc, + mlir::Value reductionVal) { + llvm::SmallVector results = {reductionVal, reductionVal}; + return results; + }; + + mlir::Type elementType = builder.getI32Type(); + + genEarlyExitLoop(builder, elementType, funcOp, zero, continueCond, genBodyOp, + rank); +} + /// Generate function type for the simplified version of RTNAME(DotProduct) /// operating on the given \p elementType. static mlir::FunctionType genRuntimeDotType(fir::FirOpBuilder &builder, @@ -615,7 +773,7 @@ simplifyReductionBody(call, kindMap, genBodyFunc, builder, funcName); } -void SimplifyIntrinsicsPass::simplifyLogicalReduction( +void SimplifyIntrinsicsPass::simplifyLogicalDim0Reduction( fir::CallOp call, const fir::KindMapping &kindMap, GenReductionBodyTy genBodyFunc) { @@ -623,8 +781,7 @@ const mlir::Value &dim = args[3]; unsigned rank = getDimCount(args[0]); - // Rank is set to 0 for assumed shape arrays, don't simplify - // in these cases + // Rank is set to 0 for assumed shape arrays, don't simplify in these cases. if (!(isZero(dim) && rank > 0)) return; @@ -639,6 +796,30 @@ simplifyReductionBody(call, kindMap, genBodyFunc, builder, funcName); } +void SimplifyIntrinsicsPass::simplifyLogicalDim1Reduction( + fir::CallOp call, const fir::KindMapping &kindMap, + GenReductionBodyTy genBodyFunc) { + + mlir::Operation::operand_range args = call.getArgs(); + mlir::SymbolRefAttr callee = call.getCalleeAttr(); + mlir::StringRef funcNameBase = callee.getLeafReference().getValue(); + unsigned rank = getDimCount(args[0]); + + // Rank is set to 0 for assumed shape arrays, don't simplify in these cases. + // We check for Dim at the end as some logical functions (Any, All) set dim to + // 1 instead of 0 when the argument is not present. + if (funcNameBase.ends_with("Dim") || !(rank > 0)) + return; + + fir::FirOpBuilder builder{getSimplificationBuilder(call, kindMap)}; + std::string funcName = + (mlir::Twine{callee.getLeafReference().getValue(), "x"} + + mlir::Twine{rank}) + .str(); + + simplifyReductionBody(call, kindMap, genBodyFunc, builder, funcName); +} + void SimplifyIntrinsicsPass::simplifyReductionBody( fir::CallOp call, const fir::KindMapping &kindMap, GenReductionBodyTy genBodyFunc, fir::FirOpBuilder &builder, @@ -761,7 +942,15 @@ return; } if (funcName.startswith(RTNAME_STRING(Count))) { - simplifyLogicalReduction(call, kindMap, genRuntimeCountBody); + simplifyLogicalDim0Reduction(call, kindMap, genRuntimeCountBody); + return; + } + if (funcName.startswith(RTNAME_STRING(Any))) { + simplifyLogicalDim1Reduction(call, kindMap, genRuntimeAnyBody); + return; + } + if (funcName.startswith(RTNAME_STRING(All))) { + simplifyLogicalDim1Reduction(call, kindMap, genRuntimeAllBody); return; } } diff --git a/flang/test/Transforms/simplifyintrinsics.fir b/flang/test/Transforms/simplifyintrinsics.fir --- a/flang/test/Transforms/simplifyintrinsics.fir +++ b/flang/test/Transforms/simplifyintrinsics.fir @@ -1239,3 +1239,236 @@ // CHECK-NOT fir.call @_FortranACount_simplified({{.*}}) // CHECK: %[[RES:.*]] = fir.call @_FortranACount({{.*}}) fastmath : (!fir.box, !fir.ref, i32, i32) -> i64 // CHECK-NOT fir.call @_FortranACount_simplified({{.*}}) + +// ----- +// Ensure Any is simplified in correct usage + +func.func @_QPdimless(%arg0: !fir.ref>> {fir.bindc_name = "a"}) -> !fir.logical<4> { + %c10 = arith.constant 10 : index + %0 = fir.alloca !fir.logical<4> {bindc_name = "dimless", uniq_name = "_QFdimlessEdimless"} + %1 = fir.shape %c10 : (index) -> !fir.shape<1> + %2 = fir.embox %arg0(%1) : (!fir.ref>>, !fir.shape<1>) -> !fir.box>> + %c1 = arith.constant 1 : index + %3 = fir.address_of(@_QQcl.04ab56883945fd2c21a3b6d132f0bb37) : !fir.ref> + %c3_i32 = arith.constant 3 : i32 + %4 = fir.convert %2 : (!fir.box>>) -> !fir.box + %5 = fir.convert %3 : (!fir.ref>) -> !fir.ref + %6 = fir.convert %c1 : (index) -> i32 + %7 = fir.call @_FortranAAny(%4, %5, %c3_i32, %6) fastmath : (!fir.box, !fir.ref, i32, i32) -> i1 + %8 = fir.convert %7 : (i1) -> !fir.logical<4> + fir.store %8 to %0 : !fir.ref> + %9 = fir.load %0 : !fir.ref> + return %9 : !fir.logical<4> +} +func.func private @_FortranAAny(!fir.box, !fir.ref, i32, i32) -> i1 attributes {fir.runtime} + +// CHECK-LABEL: func.func @_QPdimless( +// CHECK-SAME: %[[ARR:.*]]: !fir.ref>> {fir.bindc_name = "a"}) -> !fir.logical<4> { +// CHECK: %[[SIZE:.*]] = arith.constant 10 : index +// CHECK: %[[SHAPE:.*]] = fir.shape %[[SIZE]] : (index) -> !fir.shape<1> +// CHECK: %[[A_BOX_LOGICAL:.*]] = fir.embox %[[ARR]](%[[SHAPE]]) : (!fir.ref>>, !fir.shape<1>) -> !fir.box>> +// CHECK: %[[A_BOX_NONE:.*]] = fir.convert %[[A_BOX_LOGICAL]] : (!fir.box>>) -> !fir.box +// CHECK: %[[RES:.*]] = fir.call @_FortranAAnyx1_simplified(%[[A_BOX_NONE]]) fastmath : (!fir.box) -> i1 +// CHECK: } + +// CHECK-LABEL: func.func private @_FortranAAnyx1_simplified( +// CHECK-SAME: %[[ARR:.*]]: !fir.box) -> i1 attributes {llvm.linkage = #llvm.linkage} { +// CHECK: %[[C_INDEX0:.*]] = arith.constant 0 : index +// CHECK: %[[A_BOX_I32:.*]] = fir.convert %[[ARR]] : (!fir.box) -> !fir.box> +// CHECK: %[[FALSE:.*]] = arith.constant false +// CHECK: %[[C_INDEX1:.*]] = arith.constant 1 : index +// CHECK: %[[DIM_IDX0:.*]] = arith.constant 0 : index +// CHECK: %[[DIMS:.*]]:3 = fir.box_dims %[[A_BOX_I32]], %[[DIM_IDX0]] : (!fir.box>, index) -> (index, index, index) +// CHECK: %[[EXTENT:.*]] = arith.subi %[[DIMS]]#1, %[[C_INDEX1]] : index +// CHECK: %[[TRUE:.*]] = arith.constant true +// CHECK: %[[RES:.*]]:2 = fir.iterate_while (%[[ITER:.*]] = %[[C_INDEX0]] to %[[EXTENT]] step %[[C_INDEX1]]) and (%[[OK:.*]] = %[[TRUE]]) iter_args(%[[INIT:.*]] = %[[FALSE]]) -> (i1) { +// CHECK: %[[ITEM:.*]] = fir.coordinate_of %[[A_BOX_I32]], %[[ITER]] : (!fir.box>, index) -> !fir.ref +// CHECK: %[[ITEM_VAL:.*]] = fir.load %[[ITEM]] : !fir.ref +// CHECK: %[[I32_0:.*]] = arith.constant 0 : i32 +// CHECK: %[[CMP:.*]] = arith.cmpi ne, %[[ITEM_VAL]], %[[I32_0]] : i32 +// CHECK: %[[I1_1:.*]] = arith.constant true +// CHECK: %[[CONTINUE:.*]] = arith.xori %[[CMP]], %[[I1_1]] : i1 +// CHECK: fir.result %[[CONTINUE]], %[[CMP]] : i1, i1 +// CHECK: } +// CHECK: return %[[RES:.*]]#1 : i1 +// CHECK: } + +// ----- +// Ensure Any is not simplified when call ends in 'Dim' + +func.func @_QPdimless(%arg0: !fir.ref>> {fir.bindc_name = "a"}) -> !fir.array<10x!fir.logical<4>> { + %0 = fir.alloca !fir.box>>> + %c10 = arith.constant 10 : index + %c10_0 = arith.constant 10 : index + %c10_1 = arith.constant 10 : index + %1 = fir.alloca !fir.array<10x!fir.logical<4>> {bindc_name = "dimless", uniq_name = "_QFdimlessEdimless"} + %2 = fir.shape %c10_1 : (index) -> !fir.shape<1> + %3 = fir.array_load %1(%2) : (!fir.ref>>, !fir.shape<1>) -> !fir.array<10x!fir.logical<4>> + %c2_i32 = arith.constant 2 : i32 + %4 = fir.shape %c10, %c10_0 : (index, index) -> !fir.shape<2> + %5 = fir.embox %arg0(%4) : (!fir.ref>>, !fir.shape<2>) -> !fir.box>> + %6 = fir.zero_bits !fir.heap>> + %c0 = arith.constant 0 : index + %7 = fir.shape %c0 : (index) -> !fir.shape<1> + %8 = fir.embox %6(%7) : (!fir.heap>>, !fir.shape<1>) -> !fir.box>>> + fir.store %8 to %0 : !fir.ref>>>> + %9 = fir.address_of(@_QQcl.04ab56883945fd2c21a3b6d132f0bb37) : !fir.ref> + %c3_i32 = arith.constant 3 : i32 + %10 = fir.convert %0 : (!fir.ref>>>>) -> !fir.ref> + %11 = fir.convert %5 : (!fir.box>>) -> !fir.box + %12 = fir.convert %9 : (!fir.ref>) -> !fir.ref + %13 = fir.call @_FortranAAnyDim(%10, %11, %c2_i32, %12, %c3_i32) fastmath : (!fir.ref>, !fir.box, i32, !fir.ref, i32) -> none + %14 = fir.load %0 : !fir.ref>>>> + %c0_2 = arith.constant 0 : index + %15:3 = fir.box_dims %14, %c0_2 : (!fir.box>>>, index) -> (index, index, index) + %16 = fir.box_addr %14 : (!fir.box>>>) -> !fir.heap>> + %17 = fir.shape_shift %15#0, %15#1 : (index, index) -> !fir.shapeshift<1> + %18 = fir.array_load %16(%17) : (!fir.heap>>, !fir.shapeshift<1>) -> !fir.array> + %c1 = arith.constant 1 : index + %c0_3 = arith.constant 0 : index + %19 = arith.subi %c10_1, %c1 : index + %20 = fir.do_loop %arg1 = %c0_3 to %19 step %c1 unordered iter_args(%arg2 = %3) -> (!fir.array<10x!fir.logical<4>>) { + %22 = fir.array_fetch %18, %arg1 : (!fir.array>, index) -> !fir.logical<4> + %23 = fir.array_update %arg2, %22, %arg1 : (!fir.array<10x!fir.logical<4>>, !fir.logical<4>, index) -> !fir.array<10x!fir.logical<4>> + fir.result %23 : !fir.array<10x!fir.logical<4>> + } + fir.array_merge_store %3, %20 to %1 : !fir.array<10x!fir.logical<4>>, !fir.array<10x!fir.logical<4>>, !fir.ref>> + fir.freemem %16 : !fir.heap>> + %21 = fir.load %1 : !fir.ref>> + return %21 : !fir.array<10x!fir.logical<4>> +} +func.func private @_FortranAAnyDim(!fir.ref>, !fir.box, i32, !fir.ref, i32) -> none attributes {fir.runtime} + +// CHECK-LABEL: func.func @_QPdimless( +// CHECK-SAME: %[[ARR:.*]]: !fir.ref>> {fir.bindc_name = "a"}) -> !fir.array<10x!fir.logical<4>> { +// CHECK-NOT fir.call @_FortranAAnyDim_simplified({{.*}}) +// CHECK: fir.call @_FortranAAnyDim({{.*}}) fastmath : (!fir.ref>, !fir.box, i32, !fir.ref, i32) -> none +// CHECK-NOT fir.call @_FortranAAnyDim_simplified({{.*}}) + +// ----- +// Ensure Any is not simplified for unknown dimension arrays + +func.func @_QPdimless(%arg0: !fir.box>> {fir.bindc_name = "a"}) -> !fir.logical<4> { + %0 = fir.alloca !fir.logical<4> {bindc_name = "dimless", uniq_name = "_QFdimlessEdimless"} + %c1 = arith.constant 1 : index + %1 = fir.address_of(@_QQcl.04ab56883945fd2c21a3b6d132f0bb37) : !fir.ref> + %c3_i32 = arith.constant 3 : i32 + %2 = fir.convert %arg0 : (!fir.box>>) -> !fir.box + %3 = fir.convert %1 : (!fir.ref>) -> !fir.ref + %4 = fir.convert %c1 : (index) -> i32 + %5 = fir.call @_FortranAAny(%2, %3, %c3_i32, %4) fastmath : (!fir.box, !fir.ref, i32, i32) -> i1 + %6 = fir.convert %5 : (i1) -> !fir.logical<4> + fir.store %6 to %0 : !fir.ref> + %7 = fir.load %0 : !fir.ref> + return %7 : !fir.logical<4> +} +func.func private @_FortranAAny(!fir.box, !fir.ref, i32, i32) -> i1 attributes {fir.runtime} + +// CHECK-LABEL: func.func @_QPdimless( +// CHECK-SAME: %[[VAL_0:.*]]: !fir.box>> {fir.bindc_name = "a"}) -> !fir.logical<4> { +// CHECK-NOT fir.call @_FortranAAny_simplified({{.*}}) +// CHECK: fir.call @_FortranAAny({{.*}}) fastmath : (!fir.box, !fir.ref, i32, i32) -> i1 +// CHECK-NOT fir.call @_FortranAAny_simplified({{.*}}) + +// ----- +// Ensure All is simplified in correct usage + +func.func @_QPdimless(%arg0: !fir.ref>> {fir.bindc_name = "a"}) -> !fir.logical<4> { + %c10 = arith.constant 10 : index + %0 = fir.alloca !fir.logical<4> {bindc_name = "dimless", uniq_name = "_QFdimlessEdimless"} + %1 = fir.shape %c10 : (index) -> !fir.shape<1> + %2 = fir.embox %arg0(%1) : (!fir.ref>>, !fir.shape<1>) -> !fir.box>> + %c1 = arith.constant 1 : index + %3 = fir.address_of(@_QQcl.04ab56883945fd2c21a3b6d132f0bb37) : !fir.ref> + %c3_i32 = arith.constant 3 : i32 + %4 = fir.convert %2 : (!fir.box>>) -> !fir.box + %5 = fir.convert %3 : (!fir.ref>) -> !fir.ref + %6 = fir.convert %c1 : (index) -> i32 + %7 = fir.call @_FortranAAll(%4, %5, %c3_i32, %6) fastmath : (!fir.box, !fir.ref, i32, i32) -> i1 + %8 = fir.convert %7 : (i1) -> !fir.logical<4> + fir.store %8 to %0 : !fir.ref> + %9 = fir.load %0 : !fir.ref> + return %9 : !fir.logical<4> +} +func.func private @_FortranAAll(!fir.box, !fir.ref, i32, i32) -> i1 attributes {fir.runtime} + +// CHECK-LABEL: func.func @_QPdimless( +// CHECK-SAME: %[[ARR:.*]]: !fir.ref>> {fir.bindc_name = "a"}) -> !fir.logical<4> { +// CHECK: %[[SIZE:.*]] = arith.constant 10 : index +// CHECK: %[[SHAPE:.*]] = fir.shape %[[SIZE]] : (index) -> !fir.shape<1> +// CHECK: %[[A_BOX_LOGICAL:.*]] = fir.embox %[[ARR]](%[[SHAPE]]) : (!fir.ref>>, !fir.shape<1>) -> !fir.box>> +// CHECK: %[[A_BOX_NONE:.*]] = fir.convert %[[A_BOX_LOGICAL]] : (!fir.box>>) -> !fir.box +// CHECK: %[[RES:.*]] = fir.call @_FortranAAllx1_simplified(%[[A_BOX_NONE]]) fastmath : (!fir.box) -> i1 +// CHECK: } + +// CHECK-LABEL: func.func private @_FortranAAllx1_simplified( +// CHECK-SAME: %[[ARR:.*]]: !fir.box) -> i1 attributes {llvm.linkage = #llvm.linkage} { +// CHECK: %[[C_INDEX0:.*]] = arith.constant 0 : index +// CHECK: %[[A_BOX_I32:.*]] = fir.convert %[[ARR]] : (!fir.box) -> !fir.box> +// CHECK: %[[TRUE:.*]] = arith.constant true +// CHECK: %[[C_INDEX1:.*]] = arith.constant 1 : index +// CHECK: %[[DIM_INDEX0:.*]] = arith.constant 0 : index +// CHECK: %[[DIMS:.*]]:3 = fir.box_dims %[[A_BOX_I32]], %[[DIM_INDEX0]] : (!fir.box>, index) -> (index, index, index) +// CHECK: %[[EXTENT:.*]] = arith.subi %[[DIMS]]#1, %[[C_INDEX1]] : index +// CHECK: %[[TRUE2:.*]] = arith.constant true +// CHECK: %[[RES:.*]]:2 = fir.iterate_while (%[[ITER:.*]] = %[[C_INDEX0]] to %[[EXTENT]] step %[[C_INDEX1]]) and (%[[OK:.*]] = %[[TRUE2]]) iter_args(%[[INIT:.*]] = %[[TRUE]]) -> (i1) { +// CHECK: %[[ITEM:.*]] = fir.coordinate_of %[[A_BOX_I32]], %[[ITER]] : (!fir.box>, index) -> !fir.ref +// CHECK: %[[ITEM_VAL:.*]] = fir.load %[[ITEM]] : !fir.ref +// CHECK: %[[I32_1:.*]] = arith.constant 1 : i32 +// CHECK: %[[CMP_AND_CONTINUE:.*]] = arith.cmpi eq, %[[ITEM_VAL]], %[[I32_1]] : i32 +// CHECK: fir.result %[[CMP_AND_CONTINUE]], %[[CMP_AND_CONTINUE]] : i1, i1 +// CHECK: } +// CHECK: return %[[RES:.*]]#1 : i1 +// CHECK: } + +// ----- +// Ensure All is not simplified when call ends in 'Dim' + +func.func @_QPdimless(%arg0: !fir.ref>> {fir.bindc_name = "a"}) -> !fir.array<10x!fir.logical<4>> { + %0 = fir.alloca !fir.box>>> + %c10 = arith.constant 10 : index + %c10_0 = arith.constant 10 : index + %c10_1 = arith.constant 10 : index + %1 = fir.alloca !fir.array<10x!fir.logical<4>> {bindc_name = "dimless", uniq_name = "_QFdimlessEdimless"} + %2 = fir.shape %c10_1 : (index) -> !fir.shape<1> + %3 = fir.array_load %1(%2) : (!fir.ref>>, !fir.shape<1>) -> !fir.array<10x!fir.logical<4>> + %c1_i32 = arith.constant 1 : i32 + %4 = fir.shape %c10, %c10_0 : (index, index) -> !fir.shape<2> + %5 = fir.embox %arg0(%4) : (!fir.ref>>, !fir.shape<2>) -> !fir.box>> + %6 = fir.zero_bits !fir.heap>> + %c0 = arith.constant 0 : index + %7 = fir.shape %c0 : (index) -> !fir.shape<1> + %8 = fir.embox %6(%7) : (!fir.heap>>, !fir.shape<1>) -> !fir.box>>> + fir.store %8 to %0 : !fir.ref>>>> + %9 = fir.address_of(@_QQcl.04ab56883945fd2c21a3b6d132f0bb37) : !fir.ref> + %c3_i32 = arith.constant 3 : i32 + %10 = fir.convert %0 : (!fir.ref>>>>) -> !fir.ref> + %11 = fir.convert %5 : (!fir.box>>) -> !fir.box + %12 = fir.convert %9 : (!fir.ref>) -> !fir.ref + %13 = fir.call @_FortranAAllDim(%10, %11, %c1_i32, %12, %c3_i32) fastmath : (!fir.ref>, !fir.box, i32, !fir.ref, i32) -> none + %14 = fir.load %0 : !fir.ref>>>> + %c0_2 = arith.constant 0 : index + %15:3 = fir.box_dims %14, %c0_2 : (!fir.box>>>, index) -> (index, index, index) + %16 = fir.box_addr %14 : (!fir.box>>>) -> !fir.heap>> + %17 = fir.shape_shift %15#0, %15#1 : (index, index) -> !fir.shapeshift<1> + %18 = fir.array_load %16(%17) : (!fir.heap>>, !fir.shapeshift<1>) -> !fir.array> + %c1 = arith.constant 1 : index + %c0_3 = arith.constant 0 : index + %19 = arith.subi %c10_1, %c1 : index + %20 = fir.do_loop %arg1 = %c0_3 to %19 step %c1 unordered iter_args(%arg2 = %3) -> (!fir.array<10x!fir.logical<4>>) { + %22 = fir.array_fetch %18, %arg1 : (!fir.array>, index) -> !fir.logical<4> + %23 = fir.array_update %arg2, %22, %arg1 : (!fir.array<10x!fir.logical<4>>, !fir.logical<4>, index) -> !fir.array<10x!fir.logical<4>> + fir.result %23 : !fir.array<10x!fir.logical<4>> + } + fir.array_merge_store %3, %20 to %1 : !fir.array<10x!fir.logical<4>>, !fir.array<10x!fir.logical<4>>, !fir.ref>> + fir.freemem %16 : !fir.heap>> + %21 = fir.load %1 : !fir.ref>> + return %21 : !fir.array<10x!fir.logical<4>> +} +func.func private @_FortranAAllDim(!fir.ref>, !fir.box, i32, !fir.ref, i32) -> none attributes {fir.runtime} + +// CHECK-LABEL: func.func @_QPdimless( +// CHECK-SAME: %[[ARR:.*]]: !fir.ref>> {fir.bindc_name = "a"}) -> !fir.array<10x!fir.logical<4>> { +// CHECK-NOT fir.call @_FortranAAllDim_simplified({{.*}}) +// CHECK: fir.call @_FortranAAllDim({{.*}}) fastmath : (!fir.ref>, !fir.box, i32, !fir.ref, i32) -> none +// CHECK-NOT fir.call @_FortranAAllDim_simplified({{.*}})