From 3ad26060e4bceb2cf9f4959d659cbb29d88344cf Mon Sep 17 00:00:00 2001 From: Tom Eccles Date: Tue, 17 Jan 2023 17:37:15 +0000 Subject: [PATCH] [flang] add hlfir.sum operation Add an HLFIR operation for the SUM transformational intrinsic, according to the design set out in flang/doc/HighLevelFIR.md. I decided to make hlfir.sum very lenient about the form of its arguments. This allows the sum intrinsic to be lowered to only this HLFIR operation, without needing several operations to convert and box arguments. Having only one operation generated for the intrinsic invocation should make optimisation passes on HLFIR simpler. Differential Revision: https://reviews.llvm.org/D142897 --- .../flang/Optimizer/Builder/HLFIRTools.h | 1 + .../flang/Optimizer/HLFIR/HLFIRDialect.h | 7 + .../flang/Optimizer/HLFIR/HLFIROpBase.td | 15 ++ .../include/flang/Optimizer/HLFIR/HLFIROps.h | 1 + .../include/flang/Optimizer/HLFIR/HLFIROps.td | 27 ++ flang/lib/Optimizer/Builder/HLFIRTools.cpp | 2 + flang/lib/Optimizer/HLFIR/IR/HLFIRDialect.cpp | 41 +++ flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp | 69 +++++ flang/test/HLFIR/invalid.fir | 24 ++ flang/test/HLFIR/sum.fir | 239 ++++++++++++++++++ 10 files changed, 426 insertions(+) create mode 100644 flang/test/HLFIR/sum.fir diff --git a/flang/include/flang/Optimizer/Builder/HLFIRTools.h b/flang/include/flang/Optimizer/Builder/HLFIRTools.h index e610478c3499..389f5ce1c3f2 100644 --- a/flang/include/flang/Optimizer/Builder/HLFIRTools.h +++ b/flang/include/flang/Optimizer/Builder/HLFIRTools.h @@ -373,6 +373,7 @@ convertToAddress(mlir::Location loc, fir::FirOpBuilder &builder, std::pair> convertToBox(mlir::Location loc, fir::FirOpBuilder &builder, const hlfir::Entity &entity, mlir::Type targetType); + } // namespace hlfir #endif // FORTRAN_OPTIMIZER_BUILDER_HLFIRTOOLS_H diff --git a/flang/include/flang/Optimizer/HLFIR/HLFIRDialect.h b/flang/include/flang/Optimizer/HLFIR/HLFIRDialect.h index 8aace6b8ffb0..6a9acb443f9d 100644 --- a/flang/include/flang/Optimizer/HLFIR/HLFIRDialect.h +++ b/flang/include/flang/Optimizer/HLFIR/HLFIRDialect.h @@ -69,6 +69,13 @@ inline bool isBoxAddressOrValueType(mlir::Type type) { return fir::unwrapRefType(type).isa(); } +bool isFortranScalarNumericalType(mlir::Type); +bool isFortranNumericalArrayObject(mlir::Type); +bool isPassByRefOrIntegerType(mlir::Type); +bool isI1Type(mlir::Type); +// scalar i1 or logical, or sequence of logical (via (boxed?) array or expr) +bool isMaskArgument(mlir::Type); + } // namespace hlfir #endif // FORTRAN_OPTIMIZER_HLFIR_HLFIRDIALECT_H diff --git a/flang/include/flang/Optimizer/HLFIR/HLFIROpBase.td b/flang/include/flang/Optimizer/HLFIR/HLFIROpBase.td index d17a4cbf5e1b..23ad2eda3673 100644 --- a/flang/include/flang/Optimizer/HLFIR/HLFIROpBase.td +++ b/flang/include/flang/Optimizer/HLFIR/HLFIROpBase.td @@ -107,4 +107,19 @@ def IsFortranScalarCharacterExprPred def AnyScalarCharacterExpr : Type; +def IsFortranNumericalArrayObjectPred + : CPred<"::hlfir::isFortranNumericalArrayObject($_self)">; +def AnyFortranNumericalArrayObject : Type; + +def IsPassByRefOrIntegerTypePred + : CPred<"::hlfir::isPassByRefOrIntegerType($_self)">; +def AnyPassByRefOrIntegerType : Type; + +def IsMaskArgumentPred + : CPred<"::hlfir::isMaskArgument($_self)">; +def AnyFortranLogicalOrI1ArrayObject : Type; + #endif // FORTRAN_DIALECT_HLFIR_OP_BASE diff --git a/flang/include/flang/Optimizer/HLFIR/HLFIROps.h b/flang/include/flang/Optimizer/HLFIR/HLFIROps.h index 33530d12e617..e0e718346c11 100644 --- a/flang/include/flang/Optimizer/HLFIR/HLFIROps.h +++ b/flang/include/flang/Optimizer/HLFIR/HLFIROps.h @@ -13,6 +13,7 @@ #include "flang/Optimizer/Dialect/FIRType.h" #include "flang/Optimizer/Dialect/FortranVariableInterface.h" #include "flang/Optimizer/HLFIR/HLFIRDialect.h" +#include "mlir/Dialect/Arith/IR/Arith.h" #include "mlir/Interfaces/InferTypeOpInterface.h" #include "mlir/Interfaces/SideEffectInterfaces.h" diff --git a/flang/include/flang/Optimizer/HLFIR/HLFIROps.td b/flang/include/flang/Optimizer/HLFIR/HLFIROps.td index 322868512283..1321eab11041 100644 --- a/flang/include/flang/Optimizer/HLFIR/HLFIROps.td +++ b/flang/include/flang/Optimizer/HLFIR/HLFIROps.td @@ -18,6 +18,8 @@ include "flang/Optimizer/HLFIR/HLFIROpBase.td" include "flang/Optimizer/Dialect/FIRTypes.td" include "flang/Optimizer/Dialect/FIRAttr.td" include "flang/Optimizer/Dialect/FortranVariableInterface.td" +include "mlir/Dialect/Arith/IR/ArithBase.td" +include "mlir/Dialect/Arith/IR/ArithOpsInterfaces.td" include "mlir/IR/BuiltinAttributes.td" // Base class for FIR operations. @@ -256,6 +258,31 @@ def hlfir_SetLengthOp : hlfir_Op<"set_length", []> { let builders = [OpBuilder<(ins "mlir::Value":$string,"mlir::Value":$len)>]; } +def hlfir_SumOp : hlfir_Op<"sum", [AttrSizedOperandSegments, + DeclareOpInterfaceMethods]> { + let summary = "SUM transformational intrinsic"; + let description = [{ + Sums the elements of an array, optionally along a particular dimension, + optionally if a mask is true. + }]; + + let arguments = (ins + AnyFortranNumericalArrayObject:$array, + Optional:$dim, + Optional:$mask, + DefaultValuedAttr:$fastmath + ); + + let results = (outs hlfir_ExprType); + + let assemblyFormat = [{ + $array (`dim` $dim^)? (`mask` $mask^)? attr-dict `:` functional-type(operands, results) + }]; + + let hasVerifier = 1; +} + def hlfir_AssociateOp : hlfir_Op<"associate", [AttrSizedOperandSegments, DeclareOpInterfaceMethods]> { let summary = "Create a variable from an expression value"; diff --git a/flang/lib/Optimizer/Builder/HLFIRTools.cpp b/flang/lib/Optimizer/Builder/HLFIRTools.cpp index 41cc800ac182..072fb5c0fc27 100644 --- a/flang/lib/Optimizer/Builder/HLFIRTools.cpp +++ b/flang/lib/Optimizer/Builder/HLFIRTools.cpp @@ -17,6 +17,8 @@ #include "flang/Optimizer/Builder/Todo.h" #include "flang/Optimizer/HLFIR/HLFIROps.h" #include "mlir/IR/IRMapping.h" +#include "mlir/Support/LLVM.h" +#include "llvm/ADT/TypeSwitch.h" #include // Return explicit extents. If the base is a fir.box, this won't read it to diff --git a/flang/lib/Optimizer/HLFIR/IR/HLFIRDialect.cpp b/flang/lib/Optimizer/HLFIR/IR/HLFIRDialect.cpp index fbb7d77e25ca..f23be5de3be1 100644 --- a/flang/lib/Optimizer/HLFIR/IR/HLFIRDialect.cpp +++ b/flang/lib/Optimizer/HLFIR/IR/HLFIRDialect.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "flang/Optimizer/HLFIR/HLFIRDialect.h" +#include "flang/Optimizer/Dialect/FIRType.h" #include "flang/Optimizer/HLFIR/HLFIROps.h" #include "mlir/IR/Builders.h" #include "mlir/IR/BuiltinTypes.h" @@ -99,3 +100,43 @@ bool hlfir::isFortranScalarCharacterExprType(mlir::Type type) { exprType.getElementType().isa(); return false; } + +bool hlfir::isFortranScalarNumericalType(mlir::Type type) { + return fir::isa_integer(type) || fir::isa_real(type) || + fir::isa_complex(type); +} + +bool hlfir::isFortranNumericalArrayObject(mlir::Type type) { + if (isBoxAddressType(type)) + return false; + if (auto arrayTy = + getFortranElementOrSequenceType(type).dyn_cast()) + return isFortranScalarNumericalType(arrayTy.getEleTy()); + return false; +} + +bool hlfir::isPassByRefOrIntegerType(mlir::Type type) { + mlir::Type unwrappedType = fir::unwrapPassByRefType(type); + return fir::isa_integer(unwrappedType); +} + +bool hlfir::isI1Type(mlir::Type type) { + if (mlir::IntegerType integer = type.dyn_cast()) + if (integer.getWidth() == 1) + return true; + return false; +} + +bool hlfir::isMaskArgument(mlir::Type type) { + if (isBoxAddressType(type)) + return false; + + mlir::Type unwrappedType = fir::unwrapPassByRefType(fir::unwrapRefType(type)); + mlir::Type elementType = getFortranElementType(unwrappedType); + if (unwrappedType != elementType) + // input type is an array + return mlir::isa(elementType); + + // input is a scalar, so allow i1 too + return mlir::isa(elementType) || isI1Type(elementType); +} diff --git a/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp b/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp index 9bf5601ce652..feea448b3d4c 100644 --- a/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp +++ b/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp @@ -11,7 +11,10 @@ //===----------------------------------------------------------------------===// #include "flang/Optimizer/HLFIR/HLFIROps.h" +#include "flang/Optimizer/Builder/HLFIRTools.h" #include "flang/Optimizer/Dialect/FIROpsSupport.h" +#include "flang/Optimizer/Dialect/FIRType.h" +#include "flang/Optimizer/HLFIR/HLFIRDialect.h" #include "mlir/IR/Builders.h" #include "mlir/IR/BuiltinTypes.h" #include "mlir/IR/DialectImplementation.h" @@ -420,6 +423,72 @@ void hlfir::SetLengthOp::build(mlir::OpBuilder &builder, build(builder, result, resultType, string, len); } +//===----------------------------------------------------------------------===// +// SumOp +//===----------------------------------------------------------------------===// + +mlir::LogicalResult hlfir::SumOp::verify() { + mlir::Operation *op = getOperation(); + + auto results = op->getResultTypes(); + assert(results.size() == 1); + + mlir::Value array = getArray(); + mlir::Value mask = getMask(); + + fir::SequenceType arrayTy = + hlfir::getFortranElementOrSequenceType(array.getType()) + .cast(); + mlir::Type numTy = arrayTy.getEleTy(); + llvm::ArrayRef arrayShape = arrayTy.getShape(); + hlfir::ExprType resultTy = results[0].cast(); + + if (mask) { + fir::SequenceType maskSeq = + hlfir::getFortranElementOrSequenceType(mask.getType()) + .dyn_cast(); + llvm::ArrayRef maskShape; + + if (maskSeq) + maskShape = maskSeq.getShape(); + + if (!maskShape.empty()) { + if (maskShape.size() != arrayShape.size()) + return emitWarning("MASK must be conformable to ARRAY"); + static_assert(fir::SequenceType::getUnknownExtent() == + hlfir::ExprType::getUnknownExtent()); + constexpr int64_t unknownExtent = fir::SequenceType::getUnknownExtent(); + for (std::size_t i = 0; i < arrayShape.size(); ++i) { + int64_t arrayExtent = arrayShape[i]; + int64_t maskExtent = maskShape[i]; + if ((arrayExtent != maskExtent) && (arrayExtent != unknownExtent) && + (maskExtent != unknownExtent)) + return emitWarning("MASK must be conformable to ARRAY"); + } + } + } + + if (resultTy.isArray()) { + // Result is of the same type as ARRAY + if (resultTy.getEleTy() != numTy) + return emitOpError( + "result must have the same element type as ARRAY argument"); + + llvm::ArrayRef resultShape = resultTy.getShape(); + + // Result has rank n-1 + if (resultShape.size() != (arrayShape.size() - 1)) + return emitOpError("result rank must be one less than ARRAY"); + } else { + // Result is of the same type as ARRAY + if (resultTy.getElementType() != numTy) + return emitOpError( + "result must have the same element type as ARRAY argument"); + } + + return mlir::success(); +} + //===----------------------------------------------------------------------===// // AssociateOp //===----------------------------------------------------------------------===// diff --git a/flang/test/HLFIR/invalid.fir b/flang/test/HLFIR/invalid.fir index a7a3150a1534..dd801634c6f7 100644 --- a/flang/test/HLFIR/invalid.fir +++ b/flang/test/HLFIR/invalid.fir @@ -295,3 +295,27 @@ func.func @bad_concat_4(%arg0: !fir.ref>) { %0 = hlfir.concat %arg0 len %c30 : (!fir.ref>, index) -> (!hlfir.expr>) return } + +// ----- +func.func @bad_sum1(%arg0: !hlfir.expr, %arg1: i32, %arg2: !fir.box>) { + // expected-error@+1 {{'hlfir.sum' op result must have the same element type as ARRAY argument}} + %0 = hlfir.sum %arg0 dim %arg1 mask %arg2 : (!hlfir.expr, i32, !fir.box>) -> !hlfir.expr +} + +// ----- +func.func @bad_sum2(%arg0: !hlfir.expr, %arg1: i32, %arg2: !fir.box>>) { + // expected-warning@+1 {{MASK must be conformable to ARRAY}} + %0 = hlfir.sum %arg0 dim %arg1 mask %arg2 : (!hlfir.expr, i32, !fir.box>>) -> !hlfir.expr +} + +// ----- +func.func @bad_sum3(%arg0: !hlfir.expr, %arg1: i32, %arg2: !fir.box>>) { + // expected-warning@+1 {{MASK must be conformable to ARRAY}} + %0 = hlfir.sum %arg0 dim %arg1 mask %arg2 : (!hlfir.expr, i32, !fir.box>>) -> !hlfir.expr +} + +// ----- +func.func @bad_sum4(%arg0: !hlfir.expr, %arg1: i32, %arg2: !fir.box>) { + // expected-error@+1 {{'hlfir.sum' op result rank must be one less than ARRAY}} + %0 = hlfir.sum %arg0 dim %arg1 mask %arg2 : (!hlfir.expr, i32, !fir.box>) -> !hlfir.expr +} diff --git a/flang/test/HLFIR/sum.fir b/flang/test/HLFIR/sum.fir new file mode 100644 index 000000000000..45388c33091e --- /dev/null +++ b/flang/test/HLFIR/sum.fir @@ -0,0 +1,239 @@ +// Test hlfir.sum operation parse, verify (no errors), and unparse + +// RUN: fir-opt %s | fir-opt | FileCheck %s + +// array is an expression of known shape +func.func @sum0(%arg0: !hlfir.expr<42xi32>) { + %mask = fir.alloca !fir.logical<4> + %c_1 = arith.constant 1 : index + %true = arith.constant true + %true_logical = fir.convert %true : (i1) -> !fir.logical<4> + fir.store %true_logical to %mask : !fir.ref> + %mask_box = fir.embox %mask : (!fir.ref>) -> !fir.box> + %0 = hlfir.sum %arg0 dim %c_1 mask %mask_box : (!hlfir.expr<42xi32>, index, !fir.box>) -> !hlfir.expr + return +} +// CHECK: func.func @sum0(%[[ARRAY:.*]]: !hlfir.expr<42xi32>) { +// CHECK-NEXT: %[[MASK:.*]] = fir.alloca !fir.logical<4> +// CHECK-NEXT: %[[C1:.*]] = arith.constant 1 : index +// CHECK-NEXT: %[[TRUE:.*]] = arith.constant true +// CHECK-NEXT: %[[LOGICAL:.*]] = fir.convert %[[TRUE]] : (i1) -> !fir.logical<4> +// CHECK-NEXT: fir.store %[[LOGICAL]] to %[[MASK]] : !fir.ref> +// CHECK-NEXT: %[[BOX:.*]] = fir.embox %0 : (!fir.ref>) -> !fir.box> +// CHECK-NEXT: hlfir.sum %[[ARRAY]] dim %[[C1]] mask %[[BOX]] : (!hlfir.expr<42xi32>, index, !fir.box>) -> !hlfir.expr +// CHECK-NEXT: return +// CHECK-NEXT: } + +// array is an expression of assumed shape +func.func @sum1(%arg0: !hlfir.expr) { + %mask = fir.alloca !fir.logical<4> + %c_1 = arith.constant 1 : index + %true = arith.constant true + %true_logical = fir.convert %true : (i1) -> !fir.logical<4> + fir.store %true_logical to %mask : !fir.ref> + %mask_box = fir.embox %mask : (!fir.ref>) -> !fir.box> + %0 = hlfir.sum %arg0 dim %c_1 mask %mask_box : (!hlfir.expr, index, !fir.box>) -> !hlfir.expr + return +} +// CHECK: func.func @sum1(%[[ARRAY:.*]]: !hlfir.expr) { +// CHECK-NEXT: %[[MASK:.*]] = fir.alloca !fir.logical<4> +// CHECK-NEXT: %[[C1:.*]] = arith.constant 1 : index +// CHECK-NEXT: %[[TRUE:.*]] = arith.constant true +// CHECK-NEXT: %[[LOGICAL:.*]] = fir.convert %[[TRUE]] : (i1) -> !fir.logical<4> +// CHECK-NEXT: fir.store %[[LOGICAL:.*]] to %[[MASK:.*]] : !fir.ref> +// CHECK-NEXT: %[[BOX:.*]] = fir.embox %[[MASK:.*]] : (!fir.ref>) -> !fir.box> +// CHECK-NEXT: hlfir.sum %[[ARRAY:.*]] dim %[[C1]] mask %[[BOX]] : (!hlfir.expr, index, !fir.box>) -> !hlfir.expr +// CHECK-NEXT: return +// CHECK-NEXT: } + +// boxed array +func.func @sum2(%arg0: !fir.box>) { + %mask = fir.alloca !fir.logical<4> + %c_1 = arith.constant 1 : index + %true = arith.constant true + %true_logical = fir.convert %true : (i1) -> !fir.logical<4> + fir.store %true_logical to %mask : !fir.ref> + %mask_box = fir.embox %mask : (!fir.ref>) -> !fir.box> + %0 = hlfir.sum %arg0 dim %c_1 mask %mask_box : (!fir.box>, index, !fir.box>) -> !hlfir.expr + return +} +// CHECK: func.func @sum2(%[[ARRAY:.*]]: !fir.box>) { +// CHECK-NEXT: %[[MASK:.*]] = fir.alloca !fir.logical<4> +// CHECK-NEXT: %[[C1:.*]] = arith.constant 1 : index +// CHECK-NEXT: %[[TRUE:.*]] = arith.constant true +// CHECK-NEXT: %[[LOGICAL:.*]] = fir.convert %[[TRUE]] : (i1) -> !fir.logical<4> +// CHECK-NEXT: fir.store %[[LOGICAL:.*]] to %[[MASK:.*]] : !fir.ref> +// CHECK-NEXT: %[[BOX:.*]] = fir.embox %[[MASK:.*]] : (!fir.ref>) -> !fir.box> +// CHECK-NEXT: hlfir.sum %[[ARRAY:.*]] dim %[[C1]] mask %[[BOX]] : (!fir.box>, index, !fir.box>) -> !hlfir.expr +// CHECK-NEXT: return +// CHECK-NEXT: } + +// assumed shape boxed array +func.func @sum3(%arg0: !fir.box>) { + %mask = fir.alloca !fir.logical<4> + %c_1 = arith.constant 1 : index + %true = arith.constant true + %true_logical = fir.convert %true : (i1) -> !fir.logical<4> + fir.store %true_logical to %mask : !fir.ref> + %mask_box = fir.embox %mask : (!fir.ref>) -> !fir.box> + %0 = hlfir.sum %arg0 dim %c_1 mask %mask_box : (!fir.box>, index, !fir.box>) -> !hlfir.expr + return +} +// CHECK: func.func @sum3(%[[ARRAY:.*]]: !fir.box>) { +// CHECK-NEXT: %[[MASK:.*]] = fir.alloca !fir.logical<4> +// CHECK-NEXT: %[[C1:.*]] = arith.constant 1 : index +// CHECK-NEXT: %[[TRUE:.*]] = arith.constant true +// CHECK-NEXT: %[[LOGICAL:.*]] = fir.convert %[[TRUE]] : (i1) -> !fir.logical<4> +// CHECK-NEXT: fir.store %[[LOGICAL:.*]] to %[[MASK:.*]] : !fir.ref> +// CHECK-NEXT: %[[BOX:.*]] = fir.embox %[[MASK:.*]] : (!fir.ref>) -> !fir.box> +// CHECK-NEXT: hlfir.sum %[[ARRAY:.*]] dim %[[C1]] mask %[[BOX]] : (!fir.box>, index, !fir.box>) -> !hlfir.expr +// CHECK-NEXT: return +// CHECK-NEXT: } + +// known shape expr mask +func.func @sum4(%arg0: !fir.box>, %arg1: !hlfir.expr<42x!fir.logical<4>>) { + %c_1 = arith.constant 1 : index + %0 = hlfir.sum %arg0 dim %c_1 mask %arg1 : (!fir.box>, index, !hlfir.expr<42x!fir.logical<4>>) -> !hlfir.expr + return +} +// CHECK: func.func @sum4(%[[ARRAY:.*]]: !fir.box>, %[[MASK:.*]]: !hlfir.expr<42x!fir.logical<4>>) { +// CHECK-NEXT: %[[C1:.*]] = arith.constant 1 : index +// CHECK-NEXT: hlfir.sum %[[ARRAY]] dim %[[C1]] mask %[[MASK]] : (!fir.box>, index, !hlfir.expr<42x!fir.logical<4>>) -> !hlfir.expr +// CHECK-NEXT: return +// CHECK-NEXT: } + +// assumed shape expr mask +func.func @sum5(%arg0: !fir.box>, %arg1: !hlfir.expr>) { + %c_1 = arith.constant 1 : index + %0 = hlfir.sum %arg0 dim %c_1 mask %arg1 : (!fir.box>, index, !hlfir.expr>) -> !hlfir.expr + return +} +// CHECK: func.func @sum5(%[[ARRAY:.*]]: !fir.box>, %[[MASK:.*]]: !hlfir.expr>) { +// CHECK-NEXT: %[[C1:.*]] = arith.constant 1 : index +// CHECK-NEXT: hlfir.sum %[[ARRAY]] dim %[[C1]] mask %[[MASK]] : (!fir.box>, index, !hlfir.expr>) -> !hlfir.expr +// CHECK-NEXT: return +// CHECK-NEXT: } + +// known shape array mask +func.func @sum6(%arg0: !fir.box>, %arg1: !fir.box>>) { + %c_1 = arith.constant 1 : index + %0 = hlfir.sum %arg0 dim %c_1 mask %arg1 : (!fir.box>, index, !fir.box>>) -> !hlfir.expr + return +} +// CHECK: func.func @sum6(%[[ARRAY:.*]]: !fir.box>, %[[MASK:.*]]: !fir.box>>) { +// CHECK-NEXT: %[[C1:.*]] = arith.constant 1 : index +// CHECK-NEXT: hlfir.sum %[[ARRAY]] dim %[[C1]] mask %[[MASK]] : (!fir.box>, index, !fir.box>>) -> !hlfir.expr +// CHECK-NEXT: return +// CHECK-NEXT: } + +// assumed shape array mask +func.func @sum7(%arg0: !fir.box>, %arg1: !fir.box>>) { + %c_1 = arith.constant 1 : index + %0 = hlfir.sum %arg0 dim %c_1 mask %arg1 : (!fir.box>, index, !fir.box>>) -> !hlfir.expr + return +} +// CHECK: func.func @sum7(%[[ARRAY:.*]]: !fir.box>, %[[MASK:.*]]: !fir.box>>) { +// CHECK-NEXT: %[[C1:.*]] = arith.constant 1 : index +// CHECK-NEXT: hlfir.sum %[[ARRAY]] dim %[[C1]] mask %[[MASK]] : (!fir.box>, index, !fir.box>>) -> !hlfir.expr +// CHECK-NEXT: return +// CHECK-NEXT: } + +// known shape expr return +func.func @sum8(%arg0: !fir.box>, %arg1: i32) { + %mask = fir.alloca !fir.logical<4> + %true = arith.constant true + %true_logical = fir.convert %true : (i1) -> !fir.logical<4> + fir.store %true_logical to %mask : !fir.ref> + %mask_box = fir.embox %mask : (!fir.ref>) -> !fir.box> + %0 = hlfir.sum %arg0 dim %arg1 mask %mask_box : (!fir.box>, i32, !fir.box>) -> !hlfir.expr<2xi32> + return +} +// CHECK: func.func @sum8(%[[ARRAY:.*]]: !fir.box>, %[[DIM:.*]]: i32) { +// CHECK-NEXT: %[[MASK:.*]] = fir.alloca !fir.logical<4> +// CHECK-NEXT: %[[TRUE:.*]] = arith.constant true +// CHECK-NEXT: %[[LOGICAL:.*]] = fir.convert %[[TRUE]] : (i1) -> !fir.logical<4> +// CHECK-NEXT: fir.store %[[LOGICAL]] to %[[MASK]] : !fir.ref> +// CHECK-NEXT: %[[BOX:.*]] = fir.embox %0 : (!fir.ref>) -> !fir.box> +// CHECK-NEXT: hlfir.sum %[[ARRAY]] dim %[[DIM]] mask %[[BOX]] : (!fir.box>, i32, !fir.box>) -> !hlfir.expr<2xi32> +// CHECK-NEXT: return +// CHECK-NEXT: } + +// assumed shape expr return +func.func @sum9(%arg0: !fir.box>, %arg1: i32) { + %mask = fir.alloca !fir.logical<4> + %true = arith.constant true + %true_logical = fir.convert %true : (i1) -> !fir.logical<4> + fir.store %true_logical to %mask : !fir.ref> + %mask_box = fir.embox %mask : (!fir.ref>) -> !fir.box> + %0 = hlfir.sum %arg0 dim %arg1 mask %mask_box : (!fir.box>, i32, !fir.box>) -> !hlfir.expr + return +} +// CHECK: func.func @sum9(%[[ARRAY:.*]]: !fir.box>, %[[DIM:.*]]: i32) { +// CHECK-NEXT: %[[MASK:.*]] = fir.alloca !fir.logical<4> +// CHECK-NEXT: %[[TRUE:.*]] = arith.constant true +// CHECK-NEXT: %[[LOGICAL:.*]] = fir.convert %[[TRUE]] : (i1) -> !fir.logical<4> +// CHECK-NEXT: fir.store %[[LOGICAL]] to %[[MASK]] : !fir.ref> +// CHECK-NEXT: %[[BOX:.*]] = fir.embox %0 : (!fir.ref>) -> !fir.box> +// CHECK-NEXT: hlfir.sum %[[ARRAY]] dim %[[DIM]] mask %[[BOX]] : (!fir.box>, i32, !fir.box>) -> !hlfir.expr +// CHECK-NEXT: return +// CHECK-NEXT: } + +// hlfir.sum with only an array argument +func.func @sum10(%arg0: !fir.box>) { + %sum = hlfir.sum %arg0 : (!fir.box>) -> !hlfir.expr + return +} +// CHECK: func.func @sum10(%[[ARRAY:.*]]: !fir.box> +// CHECK-NEXT: %[[SUM:.*]] = hlfir.sum %[[ARRAY]] : (!fir.box>) -> !hlfir.expr +// CHECK-NEXT: return +// CHECK-NEXT: } + +// hlfir.sum with array and dim argument +func.func @sum11(%arg0: !fir.box>, %arg1: i32) { + %sum = hlfir.sum %arg0 dim %arg1 : (!fir.box>, i32) -> !hlfir.expr + return +} +// CHECK: func.func @sum11(%[[ARRAY:.*]]: !fir.box>, %[[DIM:.*]]: i32 +// CHECK-NEXT: %[[SUM:.*]] = hlfir.sum %[[ARRAY]] dim %[[DIM]] : (!fir.box>, i32) -> !hlfir.expr +// CHECK-NEXT: return +// CHECK-NEXT: } + +// hlfir.sum with array and mask argument +func.func @sum12(%arg0: !fir.box>, %arg1: !fir.logical<4>) { + %sum = hlfir.sum %arg0 mask %arg1 : (!fir.box>, !fir.logical<4>) -> !hlfir.expr + return +} +// CHECK: func.func @sum12(%[[ARRAY:.*]]: !fir.box>, %[[MASK:.*]]: !fir.logical<4> +// CHECK-NEXT: %[[SUM:.*]] = hlfir.sum %[[ARRAY]] mask %[[MASK]] : (!fir.box>, !fir.logical<4>) -> !hlfir.expr +// CHECK-NEXT: return +// CHECK-NEXT: } + +// hlfir.sum with dim argument with an unusual type +func.func @sum13(%arg0: !fir.box>, %arg1: index) { + %sum = hlfir.sum %arg0 dim %arg1 : (!fir.box>, index) -> !hlfir.expr + return +} +// CHECK: func.func @sum13(%[[ARRAY:.*]]: !fir.box>, %[[DIM:.*]]: index +// CHECK-NEXT: %[[SUM:.*]] = hlfir.sum %[[ARRAY]] dim %[[DIM]] : (!fir.box>, index) -> !hlfir.expr +// CHECK-NEXT: return +// CHECK-NEXT: } + +// hlfir.sum with mask argument of unusual type +func.func @sum14(%arg0: !fir.box>, %arg1: i1) { + %sum = hlfir.sum %arg0 mask %arg1 : (!fir.box>, i1) -> !hlfir.expr + return +} +// CHECK: func.func @sum14(%[[ARRAY:.*]]: !fir.box>, %[[MASK:.*]]: i1 +// CHECK-NEXT: %[[SUM:.*]] = hlfir.sum %[[ARRAY]] mask %[[MASK]] : (!fir.box>, i1) -> !hlfir.expr +// CHECK-NEXT: return +// CHECK-NEXT: } + +// hlfir.sum with mask argument of ref> type +func.func @sum15(%arg0: !fir.box>, %arg1: !fir.ref>>) { + %sum = hlfir.sum %arg0 mask %arg1 : (!fir.box>, !fir.ref>>) -> !hlfir.expr + return +} +// CHECK: func.func @sum15(%[[ARRAY:.*]]: !fir.box>, %[[MASK:.*]]: !fir.ref>> +// CHECK-NEXT: %[[SUM:.*]] = hlfir.sum %[[ARRAY]] mask %[[MASK]] : (!fir.box>, !fir.ref>>) -> !hlfir.expr +// CHECK-NEXT: return +// CHECK-NEXT: } -- 2.34.1