Skip to content

[flang][hlfir] Add hlfir.minval intrinsic #66306

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions flang/include/flang/Optimizer/HLFIR/HLFIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,33 @@ def hlfir_MaxvalOp : hlfir_Op<"maxval", [AttrSizedOperandSegments,
let hasVerifier = 1;
}

def hlfir_MinvalOp : hlfir_Op<"minval", [AttrSizedOperandSegments,
DeclareOpInterfaceMethods<ArithFastMathInterface>,
DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
let summary = "MINVAL transformational intrinsic";
let description = [{
Minimum value(s) of an array.
If DIM is absent, the result is a scalar.
If DIM is present, the result is an array of rank n-1, where n is the rank of ARRAY.
}];

let arguments = (ins
AnyFortranArrayObject:$array,
Optional<AnyIntegerType>:$dim,
Optional<AnyFortranLogicalOrI1ArrayObject>:$mask,
DefaultValuedAttr<Arith_FastMathAttr,
"::mlir::arith::FastMathFlags::none">:$fastmath
);

let results = (outs AnyFortranValue);

let assemblyFormat = [{
$array (`dim` $dim^)? (`mask` $mask^)? attr-dict `:` functional-type(operands, results)
}];

let hasVerifier = 1;
}

def hlfir_ProductOp : hlfir_Op<"product", [AttrSizedOperandSegments,
DeclareOpInterfaceMethods<ArithFastMathInterface>,
DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
Expand Down
4 changes: 4 additions & 0 deletions flang/lib/Lower/HlfirIntrinsics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ class HlfirReductionIntrinsic : public HlfirTransformationalIntrinsic {
using HlfirSumLowering = HlfirReductionIntrinsic<hlfir::SumOp, true>;
using HlfirProductLowering = HlfirReductionIntrinsic<hlfir::ProductOp, true>;
using HlfirMaxvalLowering = HlfirReductionIntrinsic<hlfir::MaxvalOp, true>;
using HlfirMinvalLowering = HlfirReductionIntrinsic<hlfir::MinvalOp, true>;
using HlfirAnyLowering = HlfirReductionIntrinsic<hlfir::AnyOp, false>;
using HlfirAllLowering = HlfirReductionIntrinsic<hlfir::AllOp, false>;

Expand Down Expand Up @@ -356,6 +357,9 @@ std::optional<hlfir::EntityWithAttributes> Fortran::lower::lowerHlfirIntrinsic(
if (name == "maxval")
return HlfirMaxvalLowering{builder, loc}.lower(loweredActuals, argLowering,
stmtResultType);
if (name == "minval")
return HlfirMinvalLowering{builder, loc}.lower(loweredActuals, argLowering,
stmtResultType);
if (mlir::isa<fir::CharacterType>(stmtResultType)) {
if (name == "min")
return HlfirCharExtremumLowering{builder, loc,
Expand Down
25 changes: 25 additions & 0 deletions flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -845,6 +845,31 @@ void hlfir::MaxvalOp::getEffects(
getIntrinsicEffects(getOperation(), effects);
}

//===----------------------------------------------------------------------===//
// MinvalOp
//===----------------------------------------------------------------------===//

mlir::LogicalResult hlfir::MinvalOp::verify() {
mlir::Operation *op = getOperation();

auto results = op->getResultTypes();
assert(results.size() == 1);

auto resultExpr = mlir::dyn_cast<hlfir::ExprType>(results[0]);
if (resultExpr && mlir::isa<fir::CharacterType>(resultExpr.getEleTy())) {
return verifyCharacterReductionOp<hlfir::MinvalOp *>(this);
} else {
return verifyNumericalReductionOp<hlfir::MinvalOp *>(this);
}
}

void hlfir::MinvalOp::getEffects(
llvm::SmallVectorImpl<
mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
&effects) {
getIntrinsicEffects(getOperation(), effects);
}

//===----------------------------------------------------------------------===//
// SetLengthOp
//===----------------------------------------------------------------------===//
Expand Down
12 changes: 9 additions & 3 deletions flang/lib/Optimizer/HLFIR/Transforms/LowerHLFIRIntrinsics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,8 @@ class HlfirReductionIntrinsicConversion : public HlfirIntrinsicConversion<OP> {
opName = "product";
} else if constexpr (std::is_same_v<OP, hlfir::MaxvalOp>) {
opName = "maxval";
} else if constexpr (std::is_same_v<OP, hlfir::MinvalOp>) {
opName = "minval";
} else if constexpr (std::is_same_v<OP, hlfir::AnyOp>) {
opName = "any";
} else if constexpr (std::is_same_v<OP, hlfir::AllOp>) {
Expand All @@ -241,7 +243,8 @@ class HlfirReductionIntrinsicConversion : public HlfirIntrinsicConversion<OP> {

if constexpr (std::is_same_v<OP, hlfir::SumOp> ||
std::is_same_v<OP, hlfir::ProductOp> ||
std::is_same_v<OP, hlfir::MaxvalOp>) {
std::is_same_v<OP, hlfir::MaxvalOp> ||
std::is_same_v<OP, hlfir::MinvalOp>) {
args = buildNumericalArgs(operation, i32, logicalType, rewriter, opName);
} else {
args = buildLogicalArgs(operation, i32, logicalType, rewriter, opName);
Expand All @@ -264,6 +267,8 @@ using ProductOpConversion = HlfirReductionIntrinsicConversion<hlfir::ProductOp>;

using MaxvalOpConversion = HlfirReductionIntrinsicConversion<hlfir::MaxvalOp>;

using MinvalOpConversion = HlfirReductionIntrinsicConversion<hlfir::MinvalOp>;

using AnyOpConversion = HlfirReductionIntrinsicConversion<hlfir::AnyOp>;

using AllOpConversion = HlfirReductionIntrinsicConversion<hlfir::AllOp>;
Expand Down Expand Up @@ -440,15 +445,16 @@ class LowerHLFIRIntrinsics
.insert<MatmulOpConversion, MatmulTransposeOpConversion,
AllOpConversion, AnyOpConversion, SumOpConversion,
ProductOpConversion, TransposeOpConversion, CountOpConversion,
DotProductOpConversion, MaxvalOpConversion>(context);
DotProductOpConversion, MaxvalOpConversion, MinvalOpConversion>(
context);
mlir::ConversionTarget target(*context);
target.addLegalDialect<mlir::BuiltinDialect, mlir::arith::ArithDialect,
mlir::func::FuncDialect, fir::FIROpsDialect,
hlfir::hlfirDialect>();
target.addIllegalOp<hlfir::MatmulOp, hlfir::MatmulTransposeOp, hlfir::SumOp,
hlfir::ProductOp, hlfir::TransposeOp, hlfir::AnyOp,
hlfir::AllOp, hlfir::DotProductOp, hlfir::CountOp,
hlfir::MaxvalOp>();
hlfir::MaxvalOp, hlfir::MinvalOp>();
target.markUnknownOpDynamicallyLegal(
[](mlir::Operation *) { return true; });
if (mlir::failed(
Expand Down
78 changes: 78 additions & 0 deletions flang/test/HLFIR/invalid.fir
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,84 @@ func.func @bad_maxval13(%arg0: !hlfir.expr<?x?x!fir.char<1,?>>, %arg1: i32){
%0 = hlfir.maxval %arg0 dim %arg1 : (!hlfir.expr<?x?x!fir.char<1,?>>, i32) -> !hlfir.expr<!fir.char<1,?>>
}

// -----
func.func @bad_minval1(%arg0: !hlfir.expr<?xi32>, %arg1: i32, %arg2: !fir.box<!fir.logical<4>>) {
// expected-error@+1 {{'hlfir.minval' op result must have the same element type as ARRAY argument}}
%0 = hlfir.minval %arg0 dim %arg1 mask %arg2 : (!hlfir.expr<?xi32>, i32, !fir.box<!fir.logical<4>>) -> f32
}

// -----
func.func @bad_minval2(%arg0: !hlfir.expr<?xi32>, %arg1: i32, %arg2: !fir.box<!fir.array<?x?x?x?x?x!fir.logical<4>>>) {
// expected-warning@+1 {{MASK must be conformable to ARRAY}}
%0 = hlfir.minval %arg0 dim %arg1 mask %arg2 : (!hlfir.expr<?xi32>, i32, !fir.box<!fir.array<?x?x?x?x?x!fir.logical<4>>>) -> !hlfir.expr<i32>
}

// -----
func.func @bad_minval3(%arg0: !hlfir.expr<?x5x?xi32>, %arg1: i32, %arg2: !fir.box<!fir.array<2x6x?x!fir.logical<4>>>) {
// expected-warning@+1 {{MASK must be conformable to ARRAY}}
%0 = hlfir.minval %arg0 dim %arg1 mask %arg2 : (!hlfir.expr<?x5x?xi32>, i32, !fir.box<!fir.array<2x6x?x!fir.logical<4>>>) -> !hlfir.expr<i32>
}

// -----
func.func @bad_minval4(%arg0: !hlfir.expr<?x?xi32>, %arg1: i32, %arg2: !fir.box<!fir.logical<4>>) {
// expected-error@+1 {{'hlfir.minval' op result rank must be one less than ARRAY}}
%0 = hlfir.minval %arg0 dim %arg1 mask %arg2 : (!hlfir.expr<?x?xi32>, i32, !fir.box<!fir.logical<4>>) -> !hlfir.expr<?x?xi32>
}

// -----
func.func @bad_minval5(%arg0: !hlfir.expr<?xi32>, %arg1: i32, %arg2: !fir.box<!fir.logical<4>>) {
// expected-error@+1 {{'hlfir.minval' op result must be of numerical scalar type}}
%0 = hlfir.minval %arg0 dim %arg1 mask %arg2 : (!hlfir.expr<?xi32>, i32, !fir.box<!fir.logical<4>>) -> !fir.logical<4>
}

// -----
func.func @bad_minval6(%arg0: !hlfir.expr<?x?xi32>, %arg1: i32){
// expected-error@+1 {{'hlfir.minval' op result must be an array}}
%0 = hlfir.minval %arg0 dim %arg1 : (!hlfir.expr<?x?xi32>, i32) -> !hlfir.expr<i32>
}

// -----
func.func @bad_minval7(%arg0: !hlfir.expr<?xi32>){
// expected-error@+1 {{'hlfir.minval' op result must be of numerical scalar type}}
%0 = hlfir.minval %arg0 : (!hlfir.expr<?xi32>) -> !hlfir.expr<i32>
}

// -----
func.func @bad_minval8(%arg0: !hlfir.expr<?x!fir.char<1,?>>, %arg1: i32, %arg2: !fir.box<!fir.logical<4>>) {
// expected-error@+1 {{'hlfir.minval' op result must have the same element type as ARRAY argument}}
%0 = hlfir.minval %arg0 dim %arg1 mask %arg2 : (!hlfir.expr<?x!fir.char<1,?>>, i32, !fir.box<!fir.logical<4>>) -> i32
}

// -----
func.func @bad_minval9(%arg0: !hlfir.expr<?x!fir.char<1,?>>, %arg1: i32, %arg2: !fir.box<!fir.array<?x?x?x?x?x!fir.logical<4>>>) {
// expected-warning@+1 {{MASK must be conformable to ARRAY}}
%0 = hlfir.minval %arg0 dim %arg1 mask %arg2 : (!hlfir.expr<?x!fir.char<1,?>>, i32, !fir.box<!fir.array<?x?x?x?x?x!fir.logical<4>>>) -> !hlfir.expr<!fir.char<1,?>>
}

// -----
func.func @bad_minval10(%arg0: !hlfir.expr<?x5x?x!fir.char<1,?>>, %arg1: i32, %arg2: !fir.box<!fir.array<2x6x?x!fir.logical<4>>>) {
// expected-warning@+1 {{MASK must be conformable to ARRAY}}
%0 = hlfir.minval %arg0 dim %arg1 mask %arg2 : (!hlfir.expr<?x5x?x!fir.char<1,?>>, i32, !fir.box<!fir.array<2x6x?x!fir.logical<4>>>) -> !hlfir.expr<!fir.char<1,?>>
}

// -----
func.func @bad_minval11(%arg0: !hlfir.expr<?x?x!fir.char<1,?>>, %arg1: i32, %arg2: !fir.box<!fir.logical<4>>) {
// expected-error@+1 {{'hlfir.minval' op result rank must be one less than ARRAY}}
%0 = hlfir.minval %arg0 dim %arg1 mask %arg2 : (!hlfir.expr<?x?x!fir.char<1,?>>, i32, !fir.box<!fir.logical<4>>) -> !hlfir.expr<?x?x!fir.char<1,?>>
}

// -----
func.func @bad_minval12(%arg0: !hlfir.expr<?x!fir.char<1,?>>, %arg1: i32, %arg2: !fir.box<!fir.logical<4>>) {
// expected-error@+1 {{'hlfir.minval' op result must be scalar character}}
%0 = hlfir.minval %arg0 dim %arg1 mask %arg2 : (!hlfir.expr<?x!fir.char<1,?>>, i32, !fir.box<!fir.logical<4>>) -> !hlfir.expr<?x!fir.char<1,?>>
}

// -----
func.func @bad_minval13(%arg0: !hlfir.expr<?x?x!fir.char<1,?>>, %arg1: i32){
// expected-error@+1 {{'hlfir.minval' op result must be an array}}
%0 = hlfir.minval %arg0 dim %arg1 : (!hlfir.expr<?x?x!fir.char<1,?>>, i32) -> !hlfir.expr<!fir.char<1,?>>
}

// -----
func.func @bad_product1(%arg0: !hlfir.expr<?xi32>, %arg1: i32, %arg2: !fir.box<!fir.logical<4>>) {
// expected-error@+1 {{'hlfir.product' op result must have the same element type as ARRAY argument}}
Expand Down
15 changes: 15 additions & 0 deletions flang/test/HLFIR/memory-effects.fir
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,21 @@ func.func @maxval_effects(%arg0: !fir.ref<!fir.array<2x2xf32>>, %arg1: i32) {
return
}

func.func @minval_no_effects(%arg0: !hlfir.expr<?xf32>) {
// expected-remark@+1 {{operation has no memory effects}}
%minval = hlfir.minval %arg0 : (!hlfir.expr<?xf32>) -> f32
// expected-remark@+1 {{operation has no memory effects}}
return
}

func.func @minval_effects(%arg0: !fir.ref<!fir.array<2x2xf32>>, %arg1: i32) {
// expected-remark@+2 {{found an instance of 'allocate' on a value, on resource '<Default>'}}
// expected-remark@+1 {{found an instance of 'read' on a value, on resource '<Default>'}}
%minval = hlfir.minval %arg0 dim %arg1 : (!fir.ref<!fir.array<2x2xf32>>, i32) -> !hlfir.expr<2xf32>
// expected-remark@+1 {{operation has no memory effects}}
return
}

func.func @dot_product_no_effects(%arg0: !hlfir.expr<?xf32>, %arg1: !hlfir.expr<?xf32>) {
// expected-remark@+1 {{operation has no memory effects}}
%0 = hlfir.dot_product %arg0 %arg1 : (!hlfir.expr<?xf32>, !hlfir.expr<?xf32>) -> f32
Expand Down
Loading