[flang-commits] [flang] be4518f - [flang][hlfir] support optional args for intrinsic ops

Tom Eccles via flang-commits flang-commits at lists.llvm.org
Tue Jul 4 02:35:30 PDT 2023


Author: Tom Eccles
Date: 2023-07-04T09:34:43Z
New Revision: be4518f230092b81f2690e860d028df4573d1148

URL: https://github.com/llvm/llvm-project/commit/be4518f230092b81f2690e860d028df4573d1148
DIFF: https://github.com/llvm/llvm-project/commit/be4518f230092b81f2690e860d028df4573d1148.diff

LOG: [flang][hlfir] support optional args for intrinsic ops

This also adds support for allocatable non-optional arguments.

Of the transformational intrinsics which currently have their own hlfir
operations, all of the dynamically optional arguments are lowered as
boxes, so that is all that is implemented for now.

One alternative approach would have been to deal with the dynamically
optional arguments when lowering to FIR runtime calls. I decided not to
do this so that any passes working on the intrinsic operations would not
have to know about and handle the dynamically optional arguments.

Depends on D154235

Differential Revision: https://reviews.llvm.org/D154236

Added: 
    

Modified: 
    flang/lib/Lower/HlfirIntrinsics.cpp
    flang/test/Lower/HLFIR/all.f90
    flang/test/Lower/HLFIR/any.f90
    flang/test/Lower/HLFIR/count.f90
    flang/test/Lower/HLFIR/dot_product.f90
    flang/test/Lower/HLFIR/matmul.f90
    flang/test/Lower/HLFIR/product.f90
    flang/test/Lower/HLFIR/sum.f90
    flang/test/Lower/HLFIR/transpose.f90

Removed: 
    


################################################################################
diff  --git a/flang/lib/Lower/HlfirIntrinsics.cpp b/flang/lib/Lower/HlfirIntrinsics.cpp
index 89ca1c4114d2e7..e55cb0f82934a8 100644
--- 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 @@ class HlfirTransformationalIntrinsic {
         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<hlfir::CleanupFunction, 3> cleanupFns;
 
   virtual mlir::Value
   lowerImpl(const Fortran::lower::PreparedActualArguments &loweredActuals,
@@ -59,6 +65,14 @@ class HlfirTransformationalIntrinsic {
   inline OP createOp(BUILD_ARGS... args) {
     return builder.create<OP>(loc, args...);
   }
+
+  mlir::Value loadBoxAddress(
+      const std::optional<Fortran::lower::PreparedActualArgument> &arg);
+
+  void addCleanup(std::optional<hlfir::CleanupFunction> cleanup) {
+    if (cleanup)
+      cleanupFns.emplace_back(std::move(*cleanup));
+  }
 };
 
 template <typename OP, bool HAS_MASK>
@@ -131,6 +145,39 @@ class HlfirCharExtremumLowering : public HlfirTransformationalIntrinsic {
 
 } // namespace
 
+mlir::Value HlfirTransformationalIntrinsic::loadBoxAddress(
+    const std::optional<Fortran::lower::PreparedActualArgument> &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<...>> ->
+      // !fir.box<...>)
+      return builder.create<fir::LoadOp>(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<fir::AbsentOp>(loc, boxType);
+  auto boxOrAbsent = builder.create<mlir::arith::SelectOp>(
+      loc, boxType, isPresent, box, absent);
+
+  return boxOrAbsent;
+}
+
 llvm::SmallVector<mlir::Value> HlfirTransformationalIntrinsic::getOperandVector(
     const Fortran::lower::PreparedActualArguments &loweredActuals,
     const fir::IntrinsicArgumentLoweringRules *argLowering) {
@@ -152,9 +199,14 @@ llvm::SmallVector<mlir::Value> HlfirTransformationalIntrinsic::getOperandVector(
     } 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 @@ mlir::Value HlfirReductionIntrinsic<OP, HAS_MASK>::lowerImpl(
 
   OP op;
   if constexpr (HAS_MASK)
-    op = createOp<OP>(resultTy, array, dim, /*mask=*/operands[2]);
+    op = createOp<OP>(resultTy, array, dim,
+                      /*mask=*/operands[2]);
   else
     op = createOp<OP>(resultTy, array, dim);
   return op;

diff  --git a/flang/test/Lower/HLFIR/all.f90 b/flang/test/Lower/HLFIR/all.f90
index 253a742cf16f93..7d24a5c6d43081 100644
--- a/flang/test/Lower/HLFIR/all.f90
+++ b/flang/test/Lower/HLFIR/all.f90
@@ -78,3 +78,19 @@ subroutine all4(a, s, d)
 ! CHECK-NEXT:    hlfir.destroy %[[EXPR]] : !hlfir.expr<?x!fir.logical<4>>
 ! 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<!fir.box<!fir.heap<!fir.array<?x!fir.logical<4>>>>>
+! CHECK:           %[[ARG1:.*]]: !fir.ref<!fir.logical<4>>
+! 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.heap<!fir.array<?x!fir.logical<4>>>>) -> !fir.logical<4>
+! CHECK-NEXT:    hlfir.assign %[[EXPR]] to %[[OUT]]#0  : !fir.logical<4>, !fir.ref<!fir.logical<4>>
+! CHECK-NEXT:    return
+! CHECK-NEXT:  }

diff  --git a/flang/test/Lower/HLFIR/any.f90 b/flang/test/Lower/HLFIR/any.f90
index 521890b3c08ed9..84918af2d9e8dc 100644
--- a/flang/test/Lower/HLFIR/any.f90
+++ b/flang/test/Lower/HLFIR/any.f90
@@ -77,3 +77,19 @@ subroutine any4(a, s, d)
 ! CHECK-NEXT:    hlfir.destroy %[[EXPR]] : !hlfir.expr<?x!fir.logical<4>>
 ! 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<!fir.box<!fir.heap<!fir.array<?x!fir.logical<4>>>>>
+! CHECK:           %[[ARG1:.*]]: !fir.ref<!fir.logical<4>>
+! 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.heap<!fir.array<?x!fir.logical<4>>>>) -> !fir.logical<4>
+! CHECK-NEXT:    hlfir.assign %[[EXPR]] to %[[OUT]]#0  : !fir.logical<4>, !fir.ref<!fir.logical<4>>
+! CHECK-NEXT:    return
+! CHECK-NEXT:  }

diff  --git a/flang/test/Lower/HLFIR/count.f90 b/flang/test/Lower/HLFIR/count.f90
index 4ce196450cfed2..252f92789c7607 100644
--- a/flang/test/Lower/HLFIR/count.f90
+++ b/flang/test/Lower/HLFIR/count.f90
@@ -80,3 +80,19 @@ subroutine count4(a, s, d)
 ! CHECK-NEXT:    hlfir.destroy %[[EXPR]] : !hlfir.expr<?xi64>
 ! 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<!fir.box<!fir.heap<!fir.array<?x!fir.logical<4>>>>>
+! CHECK:           %[[ARG1:.*]]: !fir.ref<i32>
+! 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<!fir.heap<!fir.array<?x!fir.logical<4>>>>) -> i32
+! CHECK-NEXT:    hlfir.assign %[[EXPR]] to %[[OUT]]#0 : i32, !fir.ref<i32>
+! CHECK-NEXT:    return
+! CHECK-NEXT:  }

diff  --git a/flang/test/Lower/HLFIR/dot_product.f90 b/flang/test/Lower/HLFIR/dot_product.f90
index 94ee46d63a288e..47e623ae253921 100644
--- a/flang/test/Lower/HLFIR/dot_product.f90
+++ b/flang/test/Lower/HLFIR/dot_product.f90
@@ -51,3 +51,22 @@ subroutine dot_product3(lhs, rhs, res)
 ! CHECK-NEXT:    hlfir.assign %[[EXPR]] to %[[RES_VAR]]#0 : i32, !fir.ref<i32>
 ! 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.box<!fir.heap<!fir.array<?xi32>>>> {fir.bindc_name = "lhs"}
+! CHECK:           %[[RHS:.*]]: !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>> {fir.bindc_name = "rhs"}
+! CHECK:           %[[RES:.*]]: !fir.ref<i32> {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<contract>} : (!fir.box<!fir.heap<!fir.array<?xi32>>>, !fir.box<!fir.heap<!fir.array<?xi32>>>) -> i32
+! CHECK-NEXT:    hlfir.assign %[[PROD]] to %[[RES_VAR]]#0 : i32, !fir.ref<i32>
+! CHECK-NEXT:    return
+! CHECK-NEXT:   }

diff  --git a/flang/test/Lower/HLFIR/matmul.f90 b/flang/test/Lower/HLFIR/matmul.f90
index 6cf1495ad08c92..298dd2b800636f 100644
--- a/flang/test/Lower/HLFIR/matmul.f90
+++ b/flang/test/Lower/HLFIR/matmul.f90
@@ -55,3 +55,22 @@ subroutine matmul2(c)
 
 ! The shapes in these types are what is being tested:
 ! CHECK-NEXT:    %[[MATMUL:.*]] = hlfir.matmul %[[A_BOX]] %[[ELEMENTAL]] {{.*}} : (!fir.box<!fir.heap<!fir.array<?x?xi32>>>, !hlfir.expr<?x?xi32>) -> !hlfir.expr<?x4xi32>
+
+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.box<!fir.heap<!fir.array<?x?xi32>>>> {fir.bindc_name = "lhs"}
+! CHECK:           %[[RHS:.*]]: !fir.ref<!fir.box<!fir.heap<!fir.array<?x?xi32>>>> {fir.bindc_name = "rhs"}
+! CHECK:           %[[RES:.*]]: !fir.ref<!fir.box<!fir.heap<!fir.array<?x?xi32>>>> {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<contract>} : (!fir.box<!fir.heap<!fir.array<?x?xi32>>>, !fir.box<!fir.heap<!fir.array<?x?xi32>>>) -> !hlfir.expr<?x?xi32>
+! CHECK-NEXT:    hlfir.assign %[[EXPR]] to %[[RES_VAR]]#0 realloc : !hlfir.expr<?x?xi32>, !fir.ref<!fir.box<!fir.heap<!fir.array<?x?xi32>>>>
+! 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
index ff59be3905e953..41c0c89777d8f9 100644
--- a/flang/test/Lower/HLFIR/product.f90
+++ b/flang/test/Lower/HLFIR/product.f90
@@ -105,3 +105,70 @@ subroutine product6(a, s, d)
 ! 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<!fir.array<?xi32>>
+! CHECK-SAME:      %[[ARG1:.*]]: !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.logical<4>>>>>
+! CHECK-SAME:      %[[ARG2:.*]]: !fir.ref<i32>
+! 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<!fir.heap<!fir.array<?x!fir.logical<4>>>>
+! 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<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+! CHECK-SAME:      %[[ARG1:.*]]: !fir.box<!fir.array<?x!fir.logical<4>>>
+! CHECK-SAME:      %[[ARG2:.*]]: !fir.ref<i32>
+! 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.array<?xi32>> {fir.bindc_name = "array"},
+! CHECK-SAME:                                     %[[MASK_ARG:.*]]: !fir.ref<!fir.logical<4>> {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<!fir.logical<4>>) -> i1
+! CHECK:           %[[MASK_BOX:.*]] = fir.embox %[[MASK_VAR]]#1
+! CHECK:           %[[ABSENT:.*]] = fir.absent !fir.box<!fir.logical<4>>
+! CHECK:           %[[MASK_SELECT:.*]] = arith.select %[[MASK_IS_PRESENT]], %[[MASK_BOX]], %[[ABSENT]]
+! CHECK:           %[[RES:.*]] = hlfir.product %[[ARRAY_VAR]]#0 mask %[[MASK_SELECT]] {{.*}}: (!fir.box<!fir.array<?xi32>>, !fir.box<!fir.logical<4>>) -> i32
+! CHECK:           hlfir.assign %[[RES]] to %[[RET_VAR]]#0
+! CHECK:           %[[RET:.*]] = fir.load %[[RET_VAR]]#1 : !fir.ref<i32>
+! 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
index 9c2155fee6f747..339582088b0321 100644
--- a/flang/test/Lower/HLFIR/sum.f90
+++ b/flang/test/Lower/HLFIR/sum.f90
@@ -106,3 +106,72 @@ subroutine sum6(a, s, d)
 ! 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<!fir.array<?xi32>>
+! CHECK-SAME:      %[[ARG1:.*]]: !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.logical<4>>>>>
+! CHECK-SAME:      %[[ARG2:.*]]: !fir.ref<i32>
+! 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<!fir.heap<!fir.array<?x!fir.logical<4>>>>
+! 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<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+! CHECK-SAME:      %[[ARG1:.*]]: !fir.box<!fir.array<?x!fir.logical<4>>>
+! CHECK-SAME:      %[[ARG2:.*]]: !fir.ref<i32>
+! 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.array<?xi32>> {fir.bindc_name = "array"},
+! CHECK-SAME:                                     %[[MASK_ARG:.*]]: !fir.ref<!fir.logical<4>> {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<!fir.logical<4>>) -> i1
+! CHECK:           %[[MASK_BOX:.*]] = fir.embox %[[MASK_VAR]]#1
+! CHECK:           %[[ABSENT:.*]] = fir.absent !fir.box<!fir.logical<4>>
+! CHECK:           %[[MASK_SELECT:.*]] = arith.select %[[MASK_IS_PRESENT]], %[[MASK_BOX]], %[[ABSENT]]
+! CHECK:           %[[RES:.*]] = hlfir.sum %[[ARRAY_VAR]]#0 mask %[[MASK_SELECT]] {{.*}}: (!fir.box<!fir.array<?xi32>>, !fir.box<!fir.logical<4>>) -> i32
+! CHECK:           hlfir.assign %[[RES]] to %[[RET_VAR]]#0
+! CHECK:           %[[RET:.*]] = fir.load %[[RET_VAR]]#1 : !fir.ref<i32>
+! 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
index 56a4c83b4947e0..f15028c4742694 100644
--- a/flang/test/Lower/HLFIR/transpose.f90
+++ b/flang/test/Lower/HLFIR/transpose.f90
@@ -28,3 +28,20 @@ subroutine transpose2(a, out)
   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<!fir.box<!fir.heap<!fir.array<?x?xi32>>>>
+! CHECK:           %[[RES_ARG:.*]]: !fir.ref<!fir.array<2x1xi32>>
+! CHECK-DAG:     %[[ARG:.*]]:2 = hlfir.declare %[[M_ARG]]
+! CHECK-DAG:     %[[RES:.*]]:2 = hlfir.declare %[[RES_ARG]](%[[RES_SHAPE:.*]]) {[[NAME2:.*]]} : (!fir.ref<!fir.array<2x1xi32>>, !fir.shape<2>) -> (!fir.ref<!fir.array<2x1xi32>>, !fir.ref<!fir.array<2x1xi32>>)
+! CHECK:         %[[ARG_LOADED:.*]] = fir.load %[[ARG]]#0
+! CHECK:         %[[EXPR:.*]] = hlfir.transpose %[[ARG_LOADED]] : (!fir.box<!fir.heap<!fir.array<?x?xi32>>>) -> !hlfir.expr<?x?xi32>
+! CHECK-NEXT:    hlfir.assign %[[EXPR]] to %[[RES]]#0
+! CHECK-NEXT:    hlfir.destroy %[[EXPR]]
+! CHECK-NEXT:    return
+! CHECK-NEXT:  }


        


More information about the flang-commits mailing list