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 @@ -39,6 +39,9 @@ #include "mlir/Transforms/RegionUtils.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" +#include +#include +#include #include namespace fir { @@ -82,9 +85,12 @@ 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 simplifyReductionBody(fir::CallOp call, const fir::KindMapping &kindMap, GenReductionBodyTy genBodyFunc, fir::FirOpBuilder &builder, @@ -136,22 +142,30 @@ mlir::Value)>; using InitValGeneratorTy = llvm::function_ref; +using ContinueLoopGenTy = llvm::function_ref( + fir::FirOpBuilder &, mlir::Location, mlir::Value)>; /// Generate the reduction loop into \p funcOp. /// -/// \p elementType is the type of the elements in the input array, -/// which may be different to the return type. /// \p initVal is a function, called to get the initial value for /// the reduction value /// \p genBody is called to fill in the actual reduciton operation /// for example add for SUM, MAX for MAXVAL, etc. /// \p rank is the rank of the input argument. -static void genReductionLoop(fir::FirOpBuilder &builder, mlir::Type elementType, - mlir::func::FuncOp &funcOp, - InitValGeneratorTy initVal, - BodyOpGeneratorTy genBody, unsigned rank) { - auto loc = mlir::UnknownLoc::get(builder.getContext()); - builder.setInsertionPointToEnd(funcOp.addEntryBlock()); +/// \p elementType is the type of the elements in the input array, +/// which may be different to the return type. +/// \p loopCond is called to generate the condition to continue or +/// not for IterWhile loops +/// \p unorderedOrInitalLoopCond contains either a boolean of bool +/// mlir constant, and controls the inital value for while loops +/// or if DoLoop is ordered/unordered. + +template +static void +genReductionLoop(fir::FirOpBuilder &builder, mlir::func::FuncOp &funcOp, + InitValGeneratorTy initVal, ContinueLoopGenTy loopCond, + T unorderedOrInitialLoopCond, BodyOpGeneratorTy genBody, + unsigned rank, mlir::Type elementType, mlir::Location loc) { mlir::IndexType idxTy = builder.getIndexType(); @@ -186,8 +200,7 @@ mlir::Value loopCount = builder.create(loc, len, one); bounds.push_back(loopCount); } - - // Create a loop nest consisting of DoLoopOp operations. + // Create a loop nest consisting of OP operations. // Collect the loops' induction variables into indices array, // which will be used in the innermost loop to load the input // array's element. @@ -197,9 +210,9 @@ for (unsigned i = rank; 0 < i; --i) { mlir::Value step = one; mlir::Value loopCount = bounds[i - 1]; - auto loop = builder.create(loc, zeroIdx, loopCount, step, - /*unordered=*/false, - /*finalCountValue=*/false, init); + auto loop = builder.create(loc, zeroIdx, loopCount, step, + unorderedOrInitialLoopCond, + /*finalCountValue=*/false, init); init = loop.getRegionIterArgs()[0]; indices.push_back(loop.getInductionVar()); // Set insertion point to the loop body so that the next loop @@ -210,31 +223,38 @@ // 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] for IterWhileOp loops, just result at [0] for + // DoLoopOp loops. + llvm::SmallVector 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, reductionVal); + auto result = builder.create(loc, results); // Proceed to the outer loop. - auto loop = mlir::cast(result->getParentOp()); - reductionVal = loop.getResult(0); + 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, reductionVal); + builder.create(loc, results[resultIndex]); +} + +static llvm::SmallVector nopLoopCond(fir::FirOpBuilder &builder, + mlir::Location, + mlir::Value reductionVal) { + return {reductionVal}; } /// Generate function body of the simplified version of RTNAME(Sum) @@ -276,8 +296,12 @@ }; mlir::Type elementType = funcOp.getResultTypes()[0]; + mlir::Location loc = mlir::UnknownLoc::get(builder.getContext()); + builder.setInsertionPointToEnd(funcOp.addEntryBlock()); - genReductionLoop(builder, elementType, funcOp, zero, genBodyOp, rank); + genReductionLoop(builder, funcOp, zero, nopLoopCond, + false, genBodyOp, rank, elementType, + loc); } static void genRuntimeMaxvalBody(fir::FirOpBuilder &builder, @@ -307,8 +331,12 @@ }; mlir::Type elementType = funcOp.getResultTypes()[0]; + mlir::Location loc = mlir::UnknownLoc::get(builder.getContext()); + builder.setInsertionPointToEnd(funcOp.addEntryBlock()); - genReductionLoop(builder, elementType, funcOp, init, genBodyOp, rank); + genReductionLoop(builder, funcOp, init, nopLoopCond, + false, genBodyOp, rank, elementType, + loc); } static void genRuntimeCountBody(fir::FirOpBuilder &builder, @@ -335,8 +363,76 @@ }; mlir::Type elementType = builder.getI32Type(); + mlir::Location loc = mlir::UnknownLoc::get(builder.getContext()); + builder.setInsertionPointToEnd(funcOp.addEntryBlock()); - genReductionLoop(builder, elementType, funcOp, zero, genBodyOp, rank); + genReductionLoop(builder, funcOp, zero, nopLoopCond, + false, genBodyOp, rank, elementType, + loc); +} + +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(); + mlir::Location loc = mlir::UnknownLoc::get(builder.getContext()); + builder.setInsertionPointToEnd(funcOp.addEntryBlock()); + mlir::Value ok = builder.createBool(loc, true); + + genReductionLoop( + builder, funcOp, zero, continueCond, ok, genBodyOp, rank, elementType, + loc); +} + +static void genRuntimeAllBody(fir::FirOpBuilder &builder, + mlir::func::FuncOp &funcOp, unsigned rank) { + auto one = [](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(); + mlir::Location loc = mlir::UnknownLoc::get(builder.getContext()); + builder.setInsertionPointToEnd(funcOp.addEntryBlock()); + mlir::Value ok = builder.createBool(loc, true); + + genReductionLoop( + builder, funcOp, one, continueCond, ok, genBodyOp, rank, elementType, + loc); } /// Generate function type for the simplified version of RTNAME(DotProduct) @@ -615,7 +711,7 @@ simplifyReductionBody(call, kindMap, genBodyFunc, builder, funcName); } -void SimplifyIntrinsicsPass::simplifyLogicalReduction( +void SimplifyIntrinsicsPass::simplifyLogicalDim0Reduction( fir::CallOp call, const fir::KindMapping &kindMap, GenReductionBodyTy genBodyFunc) { @@ -623,8 +719,8 @@ 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 + // getDimCount returns a rank of 0 for assumed shape arrays, don't simplify in + // these cases. if (!(isZero(dim) && rank > 0)) return; @@ -639,6 +735,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]); + + // getDimCount returns a rank of 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 +881,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/Lower/array-derived.f90 b/flang/test/Lower/array-derived.f90 --- a/flang/test/Lower/array-derived.f90 +++ b/flang/test/Lower/array-derived.f90 @@ -29,7 +29,7 @@ ! CHECK: %[[slice0:.*]] = fir.slice %c1{{.*}}, %[[ext0]]#1, %c1{{.*}} path %[[fldn]] : (index, index, index, !fir.field) -> !fir.slice<1> ! CHECK-DAG: = fir.array_coor %[[arg1]] [%[[slice1]]] %[[index:.*]] : (!fir.box>>, !fir.slice<1>, index) -> !fir.ref ! CHECK-DAG: = fir.array_coor %[[arg0]] [%[[slice0]]] %[[index]] : (!fir.box>>, !fir.slice<1>, index) -> !fir.ref - ! CHECK: = fir.call @_FortranAAll( + ! CHECK: = fir.call @_FortranAAllx1_simplified( c1 = all(c%n == e%n) end function c1 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 @_QPtestAny_NoDimArg(%arg0: !fir.ref>> {fir.bindc_name = "a"}) -> !fir.logical<4> { + %c10 = arith.constant 10 : index + %0 = fir.alloca !fir.logical<4> {bindc_name = "testAny_NoDimArg", uniq_name = "_QFtestAny_NoDimArgEtestAny_NoDimArg"} + %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 @_QPtestAny_NoDimArg( +// 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: %[[INIT_COND:.*]] = arith.constant true +// 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: %[[RES:.*]]:2 = fir.iterate_while (%[[ITER:.*]] = %[[C_INDEX0]] to %[[EXTENT]] step %[[C_INDEX1]]) and (%[[OK:.*]] = %[[INIT_COND]]) 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 @_QPtestAny_DimArg(%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 = "testAny_DimArg", uniq_name = "_QFtestAny_DimArgEtestAny_DimArg"} + %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 @_QPtestAny_DimArg( +// 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 @_QPtestAny_UnknownDim(%arg0: !fir.box>> {fir.bindc_name = "a"}) -> !fir.logical<4> { + %0 = fir.alloca !fir.logical<4> {bindc_name = "testAny_UnknownDim", uniq_name = "_QFtestAny_UnknownDimEtestAny_UnknownDim"} + %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 @_QPtestAny_UnknownDim( +// 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 @_QPtestAll_NoDimArg(%arg0: !fir.ref>> {fir.bindc_name = "a"}) -> !fir.logical<4> { + %c10 = arith.constant 10 : index + %0 = fir.alloca !fir.logical<4> {bindc_name = "testAll_NoDimArg", uniq_name = "_QFtestAll_NoDimArgEtestAll_NoDimArg"} + %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 @_QPtestAll_NoDimArg( +// 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: %[[INIT_COND:.*]] = arith.constant true +// 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: %[[RES:.*]]:2 = fir.iterate_while (%[[ITER:.*]] = %[[C_INDEX0]] to %[[EXTENT]] step %[[C_INDEX1]]) and (%[[OK:.*]] = %[[INIT_COND]]) 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 @_QPtestAll_DimArg(%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 = "testAll_DimArg", uniq_name = "_QFtestAll_DimArgEtestAll_DimArg"} + %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 @_QPtestAll_DimArg( +// 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({{.*}})