diff --git a/flang/lib/Lower/HlfirIntrinsics.cpp b/flang/lib/Lower/HlfirIntrinsics.cpp --- a/flang/lib/Lower/HlfirIntrinsics.cpp +++ b/flang/lib/Lower/HlfirIntrinsics.cpp @@ -12,9 +12,12 @@ #include "flang/Lower/HlfirIntrinsics.h" +#include "flang/Optimizer/Builder/BoxValue.h" #include "flang/Optimizer/Builder/FIRBuilder.h" #include "flang/Optimizer/Builder/HLFIRTools.h" #include "flang/Optimizer/Builder/IntrinsicCall.h" +#include "flang/Optimizer/Builder/MutableBox.h" +#include "flang/Optimizer/Builder/Todo.h" #include "flang/Optimizer/Dialect/FIRType.h" #include "flang/Optimizer/HLFIR/HLFIRDialect.h" #include "flang/Optimizer/HLFIR/HLFIROps.h" @@ -37,12 +40,15 @@ const fir::IntrinsicArgumentLoweringRules *argLowering, mlir::Type stmtResultType) { mlir::Value res = lowerImpl(loweredActuals, argLowering, stmtResultType); + for (const hlfir::CleanupFunction &fn : cleanupFns) + fn(); return {hlfir::EntityWithAttributes{res}}; } protected: fir::FirOpBuilder &builder; mlir::Location loc; + llvm::SmallVector cleanupFns; virtual mlir::Value lowerImpl(const Fortran::lower::PreparedActualArguments &loweredActuals, @@ -59,6 +65,14 @@ inline OP createOp(BUILD_ARGS... args) { return builder.create(loc, args...); } + + mlir::Value loadBoxAddress( + const std::optional &arg); + + void addCleanup(std::optional cleanup) { + if (cleanup) + cleanupFns.emplace_back(std::move(*cleanup)); + } }; template @@ -131,6 +145,39 @@ } // namespace +mlir::Value HlfirTransformationalIntrinsic::loadBoxAddress( + const std::optional &arg) { + if (!arg) + return mlir::Value{}; + + hlfir::Entity actual = arg->getOriginalActual(); + + if (!arg->handleDynamicOptional()) { + if (actual.isMutableBox()) { + // this is a box address type but is not dynamically optional. Just load + // the box, assuming it is well formed (!fir.ref> -> + // !fir.box<...>) + return builder.create(loc, actual.getBase()); + } + return actual; + } + + auto [exv, cleanup] = hlfir::translateToExtendedValue(loc, builder, actual); + addCleanup(cleanup); + + mlir::Value isPresent = arg->getIsPresent(); + // createBox will not do create any invalid memory dereferences if exv is + // absent. The created fir.box will not be usable, but the SelectOp below + // ensures it won't be. + mlir::Value box = builder.createBox(loc, exv); + mlir::Type boxType = box.getType(); + auto absent = builder.create(loc, boxType); + auto boxOrAbsent = builder.create( + loc, boxType, isPresent, box, absent); + + return boxOrAbsent; +} + llvm::SmallVector HlfirTransformationalIntrinsic::getOperandVector( const Fortran::lower::PreparedActualArguments &loweredActuals, const fir::IntrinsicArgumentLoweringRules *argLowering) { @@ -152,9 +199,14 @@ } else { fir::ArgLoweringRule argRules = fir::lowerIntrinsicArgumentAs(*argLowering, i); - if (!argRules.handleDynamicOptional && - argRules.lowerAs != fir::LowerIntrinsicArgAs::Inquired) + if (argRules.lowerAs == fir::LowerIntrinsicArgAs::Box) + valArg = loadBoxAddress(arg); + else if (!argRules.handleDynamicOptional && + argRules.lowerAs != fir::LowerIntrinsicArgAs::Inquired) valArg = hlfir::derefPointersAndAllocatables(loc, builder, actual); + else if (argRules.handleDynamicOptional) + TODO(loc, "hlfir transformational intrinsic dynamically optional " + "argument without box lowering"); else valArg = actual.getBase(); } @@ -195,7 +247,8 @@ OP op; if constexpr (HAS_MASK) - op = createOp(resultTy, array, dim, /*mask=*/operands[2]); + op = createOp(resultTy, array, dim, + /*mask=*/operands[2]); else op = createOp(resultTy, array, dim); return op; diff --git a/flang/test/Lower/HLFIR/all.f90 b/flang/test/Lower/HLFIR/all.f90 --- a/flang/test/Lower/HLFIR/all.f90 +++ b/flang/test/Lower/HLFIR/all.f90 @@ -78,3 +78,19 @@ ! CHECK-NEXT: hlfir.destroy %[[EXPR]] : !hlfir.expr> ! CHECK-NEXT: return ! CHECK-NEXT: } + +subroutine all5(a, s) + logical, allocatable :: a(:) + logical :: s + s = ALL(a) +end subroutine +! CHECK-LABEL: func.func @_QPall5( +! CHECK: %[[ARG0:.*]]: !fir.ref>>>> +! CHECK: %[[ARG1:.*]]: !fir.ref> +! CHECK-DAG: %[[MASK:.*]]:2 = hlfir.declare %[[ARG0]] +! CHECK-DAG: %[[OUT:.*]]:2 = hlfir.declare %[[ARG1]] +! CHECK-NEXT: %[[MASK_LOADED:.*]] = fir.load %[[MASK]]#0 +! CHECK-NEXT: %[[EXPR:.*]] = hlfir.all %[[MASK_LOADED]] : (!fir.box>>>) -> !fir.logical<4> +! CHECK-NEXT: hlfir.assign %[[EXPR]] to %[[OUT]]#0 : !fir.logical<4>, !fir.ref> +! CHECK-NEXT: return +! CHECK-NEXT: } diff --git a/flang/test/Lower/HLFIR/any.f90 b/flang/test/Lower/HLFIR/any.f90 --- a/flang/test/Lower/HLFIR/any.f90 +++ b/flang/test/Lower/HLFIR/any.f90 @@ -77,3 +77,19 @@ ! CHECK-NEXT: hlfir.destroy %[[EXPR]] : !hlfir.expr> ! CHECK-NEXT: return ! CHECK-NEXT: } + +subroutine any5(a, s) + logical, allocatable :: a(:) + logical :: s + s = ANY(a) +end subroutine +! CHECK-LABEL: func.func @_QPany5( +! CHECK: %[[ARG0:.*]]: !fir.ref>>>> +! CHECK: %[[ARG1:.*]]: !fir.ref> +! CHECK-DAG: %[[MASK:.*]]:2 = hlfir.declare %[[ARG0]] +! CHECK-DAG: %[[OUT:.*]]:2 = hlfir.declare %[[ARG1]] +! CHECK-NEXT: %[[MASK_LOADED:.*]] = fir.load %[[MASK]]#0 +! CHECK-NEXT: %[[EXPR:.*]] = hlfir.any %[[MASK_LOADED]] : (!fir.box>>>) -> !fir.logical<4> +! CHECK-NEXT: hlfir.assign %[[EXPR]] to %[[OUT]]#0 : !fir.logical<4>, !fir.ref> +! CHECK-NEXT: return +! CHECK-NEXT: } diff --git a/flang/test/Lower/HLFIR/count.f90 b/flang/test/Lower/HLFIR/count.f90 --- a/flang/test/Lower/HLFIR/count.f90 +++ b/flang/test/Lower/HLFIR/count.f90 @@ -80,3 +80,19 @@ ! CHECK-NEXT: hlfir.destroy %[[EXPR]] : !hlfir.expr ! CHECK-NEXT: return ! CHECK-NEXT: } + +subroutine count5(a, s) + logical, allocatable :: a(:) + integer :: s + s = COUNT(a) +end subroutine +! CHECK-LABEL: func.func @_QPcount5( +! CHECK: %[[ARG0:.*]]: !fir.ref>>>> +! CHECK: %[[ARG1:.*]]: !fir.ref +! CHECK-DAG: %[[MASK:.*]]:2 = hlfir.declare %[[ARG0]] +! CHECK-DAG: %[[OUT:.*]]:2 = hlfir.declare %[[ARG1]] +! CHECK-NEXT: %[[MASK_LOADED:.*]] = fir.load %[[MASK]]#0 +! CHECK-NEXT: %[[EXPR:.*]] = hlfir.count %[[MASK_LOADED]] : (!fir.box>>>) -> i32 +! CHECK-NEXT: hlfir.assign %[[EXPR]] to %[[OUT]]#0 : i32, !fir.ref +! CHECK-NEXT: return +! CHECK-NEXT: } diff --git a/flang/test/Lower/HLFIR/dot_product.f90 b/flang/test/Lower/HLFIR/dot_product.f90 --- a/flang/test/Lower/HLFIR/dot_product.f90 +++ b/flang/test/Lower/HLFIR/dot_product.f90 @@ -51,3 +51,22 @@ ! CHECK-NEXT: hlfir.assign %[[EXPR]] to %[[RES_VAR]]#0 : i32, !fir.ref ! CHECK-NEXT: return ! CHECK-NEXT: } + +subroutine dot_product4(lhs, rhs, res) + integer, allocatable :: lhs(:), rhs(:) + integer :: res + res = dot_product(lhs, rhs) +endsubroutine +! CHECK-LABEL: func.func @_QPdot_product4 +! CHECK: %[[LHS:.*]]: !fir.ref>>> {fir.bindc_name = "lhs"} +! CHECK: %[[RHS:.*]]: !fir.ref>>> {fir.bindc_name = "rhs"} +! CHECK: %[[RES:.*]]: !fir.ref {fir.bindc_name = "res"} +! CHECK-DAG: %[[LHS_VAR:.*]]:2 = hlfir.declare %[[LHS]] +! CHECK-DAG: %[[RHS_VAR:.*]]:2 = hlfir.declare %[[RHS]] +! CHECK-DAG: %[[RES_VAR:.*]]:2 = hlfir.declare %[[RES]] +! CHECK-NEXT: %[[LHS_LD:.*]] = fir.load %[[LHS_VAR]]#0 +! CHECK-NEXT: %[[RHS_LD:.*]] = fir.load %[[RHS_VAR]]#0 +! CHECK-NEXT: %[[PROD:.*]] = hlfir.dot_product %[[LHS_LD]] %[[RHS_LD]] {fastmath = #arith.fastmath} : (!fir.box>>, !fir.box>>) -> i32 +! CHECK-NEXT: hlfir.assign %[[PROD]] to %[[RES_VAR]]#0 : i32, !fir.ref +! CHECK-NEXT: return +! CHECK-NEXT: } diff --git a/flang/test/Lower/HLFIR/matmul.f90 b/flang/test/Lower/HLFIR/matmul.f90 --- a/flang/test/Lower/HLFIR/matmul.f90 +++ b/flang/test/Lower/HLFIR/matmul.f90 @@ -55,3 +55,22 @@ ! The shapes in these types are what is being tested: ! CHECK-NEXT: %[[MATMUL:.*]] = hlfir.matmul %[[A_BOX]] %[[ELEMENTAL]] {{.*}} : (!fir.box>>, !hlfir.expr) -> !hlfir.expr + +subroutine matmul3(lhs, rhs, res) + integer, allocatable :: lhs(:,:), rhs(:,:), res(:,:) + res = MATMUL(lhs, rhs) +endsubroutine +! CHECK-LABEL: func.func @_QPmatmul3 +! CHECK: %[[LHS:.*]]: !fir.ref>>> {fir.bindc_name = "lhs"} +! CHECK: %[[RHS:.*]]: !fir.ref>>> {fir.bindc_name = "rhs"} +! CHECK: %[[RES:.*]]: !fir.ref>>> {fir.bindc_name = "res"} +! CHECK-DAG: %[[LHS_VAR:.*]]:2 = hlfir.declare %[[LHS]] +! CHECK-DAG: %[[RHS_VAR:.*]]:2 = hlfir.declare %[[RHS]] +! CHECK-DAG: %[[RES_VAR:.*]]:2 = hlfir.declare %[[RES]] +! CHECK-NEXT: %[[LHS_LD:.*]] = fir.load %[[LHS_VAR]]#0 +! CHECK-NEXT: %[[RHS_LD:.*]] = fir.load %[[RHS_VAR]]#0 +! CHECK-NEXT: %[[EXPR:.*]] = hlfir.matmul %[[LHS_LD]] %[[RHS_LD]] {fastmath = #arith.fastmath} : (!fir.box>>, !fir.box>>) -> !hlfir.expr +! CHECK-NEXT: hlfir.assign %[[EXPR]] to %[[RES_VAR]]#0 realloc : !hlfir.expr, !fir.ref>>> +! CHECK-NEXT: hlfir.destroy %[[EXPR]] +! CHECK-NEXT: return +! CHECK-NEXT: } diff --git a/flang/test/Lower/HLFIR/product.f90 b/flang/test/Lower/HLFIR/product.f90 --- a/flang/test/Lower/HLFIR/product.f90 +++ b/flang/test/Lower/HLFIR/product.f90 @@ -105,3 +105,70 @@ ! CHECK-NEXT: hlfir.destroy %[[EXPR]] ! CHECK-NEXT: return ! CHECK-NEXT: } + +subroutine testDynamicallyOptionalMask(array, mask, res) + integer :: array(:), res + logical, allocatable :: mask(:) + res = PRODUCT(array, mask=mask) +end subroutine +! CHECK-LABEL: func.func @_QPtestdynamicallyoptionalmask( +! CHECK-SAME: %[[ARG0:.*]]: !fir.box> +! CHECK-SAME: %[[ARG1:.*]]: !fir.ref>>>> +! CHECK-SAME: %[[ARG2:.*]]: !fir.ref +! CHECK-DAG: %[[ARRAY:.*]]:2 = hlfir.declare %[[ARG0]] +! CHECK-DAG: %[[MASK:.*]]:2 = hlfir.declare %[[ARG1]] +! CHECK-DAG: %[[RES:.*]]:2 = hlfir.declare %[[ARG2]] +! CHECK-NEXT: %[[MASK_LOAD:.*]] = fir.load %[[MASK]]#1 +! CHECK-NEXT: %[[MASK_ADDR:.*]] = fir.box_addr %[[MASK_LOAD]] +! CHECK-NEXT: %[[MASK_ADDR_INT:.*]] = fir.convert %[[MASK_ADDR]] +! CHECK-NEXT: %[[C0:.*]] = arith.constant 0 : i64 +! CHECK-NEXT: %[[CMP:.*]] = arith.cmpi ne, %[[MASK_ADDR_INT]], %[[C0]] : i64 +! CHECK-NEXT: %[[MASK_LOAD2:.*]] = fir.load %[[MASK]]#1 +! CHECK-NEXT: %[[ABSENT:.*]] = fir.absent !fir.box>>> +! CHECK-NEXT: %[[SELECT:.*]] = arith.select %[[CMP]], %[[MASK_LOAD2]], %[[ABSENT]] +! CHECK-NEXT: %[[PRODUCT:.*]] = hlfir.product %[[ARRAY]]#0 mask %[[SELECT]] +! CHECK-NEXT: hlfir.assign %[[PRODUCT]] to %[[RES]]#0 +! CHECK-NEXT: return +! CHECK-NEXT: } + +subroutine testAllocatableArray(array, mask, res) + integer, allocatable :: array(:) + integer :: res + logical :: mask(:) + res = PRODUCT(array, mask=mask) +end subroutine +! CHECK-LABEL: func.func @_QPtestallocatablearray( +! CHECK-SAME: %[[ARG0:.*]]: !fir.ref>>> +! CHECK-SAME: %[[ARG1:.*]]: !fir.box>> +! CHECK-SAME: %[[ARG2:.*]]: !fir.ref +! CHECK-DAG: %[[ARRAY:.*]]:2 = hlfir.declare %[[ARG0]] +! CHECK-DAG: %[[MASK:.*]]:2 = hlfir.declare %[[ARG1]] +! CHECK-DAG: %[[RES:.*]]:2 = hlfir.declare %[[ARG2]] +! CHECK-NEXT: %[[LOADED_ARRAY:.*]] = fir.load %[[ARRAY]]#0 +! CHECK-NEXT: %[[PRODUCT:.*]] = hlfir.product %[[LOADED_ARRAY]] mask %[[MASK]]#0 +! CHECK-NEXT: hlfir.assign %[[PRODUCT]] to %[[RES]]#0 +! CHECK-NEXT: return +! CHECK-NEXT: } + +function testOptionalScalar(array, mask) + integer :: array(:) + logical, optional :: mask + integer :: testOptionalScalar + testOptionalScalar = product(array, mask) +end function +! CHECK-LABEL: func.func @_QPtestoptionalscalar( +! CHECK-SAME: %[[ARRAY_ARG:.*]]: !fir.box> {fir.bindc_name = "array"}, +! CHECK-SAME: %[[MASK_ARG:.*]]: !fir.ref> {fir.bindc_name = "mask", fir.optional}) -> i32 +! CHECK: %[[ARRAY_VAR:.*]]:2 = hlfir.declare %[[ARRAY_ARG]] +! CHECK: %[[MASK_VAR:.*]]:2 = hlfir.declare %[[MASK_ARG]] +! CHECK: %[[RET_ALLOC:.*]] = fir.alloca i32 {bindc_name = "testoptionalscalar", uniq_name = "_QFtestoptionalscalarEtestoptionalscalar"} +! CHECK: %[[RET_VAR:.*]]:2 = hlfir.declare %[[RET_ALLOC]] +! CHECK: %[[MASK_IS_PRESENT:.*]] = fir.is_present %[[MASK_VAR]]#0 : (!fir.ref>) -> i1 +! CHECK: %[[MASK_BOX:.*]] = fir.embox %[[MASK_VAR]]#1 +! CHECK: %[[ABSENT:.*]] = fir.absent !fir.box> +! CHECK: %[[MASK_SELECT:.*]] = arith.select %[[MASK_IS_PRESENT]], %[[MASK_BOX]], %[[ABSENT]] +! CHECK: %[[RES:.*]] = hlfir.product %[[ARRAY_VAR]]#0 mask %[[MASK_SELECT]] {{.*}}: (!fir.box>, !fir.box>) -> i32 +! CHECK: hlfir.assign %[[RES]] to %[[RET_VAR]]#0 +! CHECK: %[[RET:.*]] = fir.load %[[RET_VAR]]#1 : !fir.ref +! CHECK: return %[[RET]] : i32 +! CHECK: } \ No newline at end of file diff --git a/flang/test/Lower/HLFIR/sum.f90 b/flang/test/Lower/HLFIR/sum.f90 --- a/flang/test/Lower/HLFIR/sum.f90 +++ b/flang/test/Lower/HLFIR/sum.f90 @@ -106,3 +106,72 @@ ! CHECK-NEXT: hlfir.destroy %[[EXPR]] ! CHECK-NEXT: return ! CHECK-NEXT: } + +subroutine testDynamicallyOptionalMask(array, mask, res) + integer :: array(:), res + logical, allocatable :: mask(:) + res = SUM(array, mask=mask) +end subroutine +! CHECK-LABEL: func.func @_QPtestdynamicallyoptionalmask( +! CHECK-SAME: %[[ARG0:.*]]: !fir.box> +! CHECK-SAME: %[[ARG1:.*]]: !fir.ref>>>> +! CHECK-SAME: %[[ARG2:.*]]: !fir.ref +! CHECK-DAG: %[[ARRAY:.*]]:2 = hlfir.declare %[[ARG0]] +! CHECK-DAG: %[[MASK:.*]]:2 = hlfir.declare %[[ARG1]] +! CHECK-DAG: %[[RES:.*]]:2 = hlfir.declare %[[ARG2]] +! CHECK-NEXT: %[[MASK_LOAD:.*]] = fir.load %[[MASK]]#1 +! CHECK-NEXT: %[[MASK_ADDR:.*]] = fir.box_addr %[[MASK_LOAD]] +! CHECK-NEXT: %[[MASK_ADDR_INT:.*]] = fir.convert %[[MASK_ADDR]] +! CHECK-NEXT: %[[C0:.*]] = arith.constant 0 : i64 +! CHECK-NEXT: %[[CMP:.*]] = arith.cmpi ne, %[[MASK_ADDR_INT]], %[[C0]] : i64 +! it is a shame there is a second load here. The first is generated for +! PreparedActualArgument::isPresent, the second is for optional handling +! CHECK-NEXT: %[[MASK_LOAD2:.*]] = fir.load %[[MASK]]#1 +! CHECK-NEXT: %[[ABSENT:.*]] = fir.absent !fir.box>>> +! CHECK-NEXT: %[[SELECT:.*]] = arith.select %[[CMP]], %[[MASK_LOAD2]], %[[ABSENT]] +! CHECK-NEXT: %[[SUM:.*]] = hlfir.sum %[[ARRAY]]#0 mask %[[SELECT]] +! CHECK-NEXT: hlfir.assign %[[SUM]] to %[[RES]]#0 +! CHECK-NEXT: return +! CHECK-NEXT: } + +subroutine testAllocatableArray(array, mask, res) + integer, allocatable :: array(:) + integer :: res + logical :: mask(:) + res = SUM(array, mask=mask) +end subroutine +! CHECK-LABEL: func.func @_QPtestallocatablearray( +! CHECK-SAME: %[[ARG0:.*]]: !fir.ref>>> +! CHECK-SAME: %[[ARG1:.*]]: !fir.box>> +! CHECK-SAME: %[[ARG2:.*]]: !fir.ref +! CHECK-DAG: %[[ARRAY:.*]]:2 = hlfir.declare %[[ARG0]] +! CHECK-DAG: %[[MASK:.*]]:2 = hlfir.declare %[[ARG1]] +! CHECK-DAG: %[[RES:.*]]:2 = hlfir.declare %[[ARG2]] +! CHECK-NEXT: %[[LOADED_ARRAY:.*]] = fir.load %[[ARRAY]]#0 +! CHECK-NEXT: %[[SUM:.*]] = hlfir.sum %[[LOADED_ARRAY]] mask %[[MASK]]#0 +! CHECK-NEXT: hlfir.assign %[[SUM]] to %[[RES]]#0 +! CHECK-NEXT: return +! CHECK-NEXT: } + +function testOptionalScalar(array, mask) + integer :: array(:) + logical, optional :: mask + integer :: testOptionalScalar + testOptionalScalar = sum(array, mask) +end function +! CHECK-LABEL: func.func @_QPtestoptionalscalar( +! CHECK-SAME: %[[ARRAY_ARG:.*]]: !fir.box> {fir.bindc_name = "array"}, +! CHECK-SAME: %[[MASK_ARG:.*]]: !fir.ref> {fir.bindc_name = "mask", fir.optional}) -> i32 +! CHECK: %[[ARRAY_VAR:.*]]:2 = hlfir.declare %[[ARRAY_ARG]] +! CHECK: %[[MASK_VAR:.*]]:2 = hlfir.declare %[[MASK_ARG]] +! CHECK: %[[RET_ALLOC:.*]] = fir.alloca i32 {bindc_name = "testoptionalscalar", uniq_name = "_QFtestoptionalscalarEtestoptionalscalar"} +! CHECK: %[[RET_VAR:.*]]:2 = hlfir.declare %[[RET_ALLOC]] +! CHECK: %[[MASK_IS_PRESENT:.*]] = fir.is_present %[[MASK_VAR]]#0 : (!fir.ref>) -> i1 +! CHECK: %[[MASK_BOX:.*]] = fir.embox %[[MASK_VAR]]#1 +! CHECK: %[[ABSENT:.*]] = fir.absent !fir.box> +! CHECK: %[[MASK_SELECT:.*]] = arith.select %[[MASK_IS_PRESENT]], %[[MASK_BOX]], %[[ABSENT]] +! CHECK: %[[RES:.*]] = hlfir.sum %[[ARRAY_VAR]]#0 mask %[[MASK_SELECT]] {{.*}}: (!fir.box>, !fir.box>) -> i32 +! CHECK: hlfir.assign %[[RES]] to %[[RET_VAR]]#0 +! CHECK: %[[RET:.*]] = fir.load %[[RET_VAR]]#1 : !fir.ref +! CHECK: return %[[RET]] : i32 +! CHECK: } \ No newline at end of file diff --git a/flang/test/Lower/HLFIR/transpose.f90 b/flang/test/Lower/HLFIR/transpose.f90 --- a/flang/test/Lower/HLFIR/transpose.f90 +++ b/flang/test/Lower/HLFIR/transpose.f90 @@ -28,3 +28,20 @@ out = transpose(reshape(a, (/N, M/))) end subroutine ! CHECK-LABEL: func.func @_QPtranspose2( + +subroutine transpose3(m, res) + integer, allocatable :: m(:,:) + integer :: res(2, 1) + res = TRANSPOSE(m) +endsubroutine +! CHECK-LABEL: func.func @_QPtranspose3 +! CHECK: %[[M_ARG:.*]]: !fir.ref>>> +! CHECK: %[[RES_ARG:.*]]: !fir.ref> +! CHECK-DAG: %[[ARG:.*]]:2 = hlfir.declare %[[M_ARG]] +! CHECK-DAG: %[[RES:.*]]:2 = hlfir.declare %[[RES_ARG]](%[[RES_SHAPE:.*]]) {[[NAME2:.*]]} : (!fir.ref>, !fir.shape<2>) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[ARG_LOADED:.*]] = fir.load %[[ARG]]#0 +! CHECK: %[[EXPR:.*]] = hlfir.transpose %[[ARG_LOADED]] : (!fir.box>>) -> !hlfir.expr +! CHECK-NEXT: hlfir.assign %[[EXPR]] to %[[RES]]#0 +! CHECK-NEXT: hlfir.destroy %[[EXPR]] +! CHECK-NEXT: return +! CHECK-NEXT: }