Skip to content

Commit 23b302d

Browse files
committed
[flang][hlfir] Add hlfir.minval intrinsic
Adds a new HLFIR operation for the MINVAL intrinsic according to the design set out in flang/docs/HighLevelFIR.md.
1 parent 22e1df7 commit 23b302d

File tree

9 files changed

+887
-3
lines changed

9 files changed

+887
-3
lines changed

flang/include/flang/Optimizer/HLFIR/HLFIROps.td

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,33 @@ def hlfir_MaxvalOp : hlfir_Op<"maxval", [AttrSizedOperandSegments,
431431
let hasVerifier = 1;
432432
}
433433

434+
def hlfir_MinvalOp : hlfir_Op<"minval", [AttrSizedOperandSegments,
435+
DeclareOpInterfaceMethods<ArithFastMathInterface>,
436+
DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
437+
let summary = "MINVAL transformational intrinsic";
438+
let description = [{
439+
Minimum value(s) of an array.
440+
If DIM is absent, the result is a scalar.
441+
If DIM is present, the result is an array of rank n-1, where n is the rank of ARRAY.
442+
}];
443+
444+
let arguments = (ins
445+
AnyFortranArrayObject:$array,
446+
Optional<AnyIntegerType>:$dim,
447+
Optional<AnyFortranLogicalOrI1ArrayObject>:$mask,
448+
DefaultValuedAttr<Arith_FastMathAttr,
449+
"::mlir::arith::FastMathFlags::none">:$fastmath
450+
);
451+
452+
let results = (outs AnyFortranValue);
453+
454+
let assemblyFormat = [{
455+
$array (`dim` $dim^)? (`mask` $mask^)? attr-dict `:` functional-type(operands, results)
456+
}];
457+
458+
let hasVerifier = 1;
459+
}
460+
434461
def hlfir_ProductOp : hlfir_Op<"product", [AttrSizedOperandSegments,
435462
DeclareOpInterfaceMethods<ArithFastMathInterface>,
436463
DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {

flang/lib/Lower/HlfirIntrinsics.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ class HlfirReductionIntrinsic : public HlfirTransformationalIntrinsic {
8989
using HlfirSumLowering = HlfirReductionIntrinsic<hlfir::SumOp, true>;
9090
using HlfirProductLowering = HlfirReductionIntrinsic<hlfir::ProductOp, true>;
9191
using HlfirMaxvalLowering = HlfirReductionIntrinsic<hlfir::MaxvalOp, true>;
92+
using HlfirMinvalLowering = HlfirReductionIntrinsic<hlfir::MinvalOp, true>;
9293
using HlfirAnyLowering = HlfirReductionIntrinsic<hlfir::AnyOp, false>;
9394
using HlfirAllLowering = HlfirReductionIntrinsic<hlfir::AllOp, false>;
9495

@@ -356,6 +357,9 @@ std::optional<hlfir::EntityWithAttributes> Fortran::lower::lowerHlfirIntrinsic(
356357
if (name == "maxval")
357358
return HlfirMaxvalLowering{builder, loc}.lower(loweredActuals, argLowering,
358359
stmtResultType);
360+
if (name == "minval")
361+
return HlfirMinvalLowering{builder, loc}.lower(loweredActuals, argLowering,
362+
stmtResultType);
359363
if (mlir::isa<fir::CharacterType>(stmtResultType)) {
360364
if (name == "min")
361365
return HlfirCharExtremumLowering{builder, loc,

flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -845,6 +845,31 @@ void hlfir::MaxvalOp::getEffects(
845845
getIntrinsicEffects(getOperation(), effects);
846846
}
847847

848+
//===----------------------------------------------------------------------===//
849+
// MinvalOp
850+
//===----------------------------------------------------------------------===//
851+
852+
mlir::LogicalResult hlfir::MinvalOp::verify() {
853+
mlir::Operation *op = getOperation();
854+
855+
auto results = op->getResultTypes();
856+
assert(results.size() == 1);
857+
858+
auto resultExpr = mlir::dyn_cast<hlfir::ExprType>(results[0]);
859+
if (resultExpr && mlir::isa<fir::CharacterType>(resultExpr.getEleTy())) {
860+
return verifyCharacterReductionOp<hlfir::MinvalOp *>(this);
861+
} else {
862+
return verifyNumericalReductionOp<hlfir::MinvalOp *>(this);
863+
}
864+
}
865+
866+
void hlfir::MinvalOp::getEffects(
867+
llvm::SmallVectorImpl<
868+
mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
869+
&effects) {
870+
getIntrinsicEffects(getOperation(), effects);
871+
}
872+
848873
//===----------------------------------------------------------------------===//
849874
// SetLengthOp
850875
//===----------------------------------------------------------------------===//

flang/lib/Optimizer/HLFIR/Transforms/LowerHLFIRIntrinsics.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,8 @@ class HlfirReductionIntrinsicConversion : public HlfirIntrinsicConversion<OP> {
222222
opName = "product";
223223
} else if constexpr (std::is_same_v<OP, hlfir::MaxvalOp>) {
224224
opName = "maxval";
225+
} else if constexpr (std::is_same_v<OP, hlfir::MinvalOp>) {
226+
opName = "minval";
225227
} else if constexpr (std::is_same_v<OP, hlfir::AnyOp>) {
226228
opName = "any";
227229
} else if constexpr (std::is_same_v<OP, hlfir::AllOp>) {
@@ -241,7 +243,8 @@ class HlfirReductionIntrinsicConversion : public HlfirIntrinsicConversion<OP> {
241243

242244
if constexpr (std::is_same_v<OP, hlfir::SumOp> ||
243245
std::is_same_v<OP, hlfir::ProductOp> ||
244-
std::is_same_v<OP, hlfir::MaxvalOp>) {
246+
std::is_same_v<OP, hlfir::MaxvalOp> ||
247+
std::is_same_v<OP, hlfir::MinvalOp>) {
245248
args = buildNumericalArgs(operation, i32, logicalType, rewriter, opName);
246249
} else {
247250
args = buildLogicalArgs(operation, i32, logicalType, rewriter, opName);
@@ -264,6 +267,8 @@ using ProductOpConversion = HlfirReductionIntrinsicConversion<hlfir::ProductOp>;
264267

265268
using MaxvalOpConversion = HlfirReductionIntrinsicConversion<hlfir::MaxvalOp>;
266269

270+
using MinvalOpConversion = HlfirReductionIntrinsicConversion<hlfir::MinvalOp>;
271+
267272
using AnyOpConversion = HlfirReductionIntrinsicConversion<hlfir::AnyOp>;
268273

269274
using AllOpConversion = HlfirReductionIntrinsicConversion<hlfir::AllOp>;
@@ -440,15 +445,16 @@ class LowerHLFIRIntrinsics
440445
.insert<MatmulOpConversion, MatmulTransposeOpConversion,
441446
AllOpConversion, AnyOpConversion, SumOpConversion,
442447
ProductOpConversion, TransposeOpConversion, CountOpConversion,
443-
DotProductOpConversion, MaxvalOpConversion>(context);
448+
DotProductOpConversion, MaxvalOpConversion, MinvalOpConversion>(
449+
context);
444450
mlir::ConversionTarget target(*context);
445451
target.addLegalDialect<mlir::BuiltinDialect, mlir::arith::ArithDialect,
446452
mlir::func::FuncDialect, fir::FIROpsDialect,
447453
hlfir::hlfirDialect>();
448454
target.addIllegalOp<hlfir::MatmulOp, hlfir::MatmulTransposeOp, hlfir::SumOp,
449455
hlfir::ProductOp, hlfir::TransposeOp, hlfir::AnyOp,
450456
hlfir::AllOp, hlfir::DotProductOp, hlfir::CountOp,
451-
hlfir::MaxvalOp>();
457+
hlfir::MaxvalOp, hlfir::MinvalOp>();
452458
target.markUnknownOpDynamicallyLegal(
453459
[](mlir::Operation *) { return true; });
454460
if (mlir::failed(

flang/test/HLFIR/invalid.fir

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,84 @@ func.func @bad_maxval13(%arg0: !hlfir.expr<?x?x!fir.char<1,?>>, %arg1: i32){
470470
%0 = hlfir.maxval %arg0 dim %arg1 : (!hlfir.expr<?x?x!fir.char<1,?>>, i32) -> !hlfir.expr<!fir.char<1,?>>
471471
}
472472

473+
// -----
474+
func.func @bad_minval1(%arg0: !hlfir.expr<?xi32>, %arg1: i32, %arg2: !fir.box<!fir.logical<4>>) {
475+
// expected-error@+1 {{'hlfir.minval' op result must have the same element type as ARRAY argument}}
476+
%0 = hlfir.minval %arg0 dim %arg1 mask %arg2 : (!hlfir.expr<?xi32>, i32, !fir.box<!fir.logical<4>>) -> f32
477+
}
478+
479+
// -----
480+
func.func @bad_minval2(%arg0: !hlfir.expr<?xi32>, %arg1: i32, %arg2: !fir.box<!fir.array<?x?x?x?x?x!fir.logical<4>>>) {
481+
// expected-warning@+1 {{MASK must be conformable to ARRAY}}
482+
%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>
483+
}
484+
485+
// -----
486+
func.func @bad_minval3(%arg0: !hlfir.expr<?x5x?xi32>, %arg1: i32, %arg2: !fir.box<!fir.array<2x6x?x!fir.logical<4>>>) {
487+
// expected-warning@+1 {{MASK must be conformable to ARRAY}}
488+
%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>
489+
}
490+
491+
// -----
492+
func.func @bad_minval4(%arg0: !hlfir.expr<?x?xi32>, %arg1: i32, %arg2: !fir.box<!fir.logical<4>>) {
493+
// expected-error@+1 {{'hlfir.minval' op result rank must be one less than ARRAY}}
494+
%0 = hlfir.minval %arg0 dim %arg1 mask %arg2 : (!hlfir.expr<?x?xi32>, i32, !fir.box<!fir.logical<4>>) -> !hlfir.expr<?x?xi32>
495+
}
496+
497+
// -----
498+
func.func @bad_minval5(%arg0: !hlfir.expr<?xi32>, %arg1: i32, %arg2: !fir.box<!fir.logical<4>>) {
499+
// expected-error@+1 {{'hlfir.minval' op result must be of numerical scalar type}}
500+
%0 = hlfir.minval %arg0 dim %arg1 mask %arg2 : (!hlfir.expr<?xi32>, i32, !fir.box<!fir.logical<4>>) -> !fir.logical<4>
501+
}
502+
503+
// -----
504+
func.func @bad_minval6(%arg0: !hlfir.expr<?x?xi32>, %arg1: i32){
505+
// expected-error@+1 {{'hlfir.minval' op result must be an array}}
506+
%0 = hlfir.minval %arg0 dim %arg1 : (!hlfir.expr<?x?xi32>, i32) -> !hlfir.expr<i32>
507+
}
508+
509+
// -----
510+
func.func @bad_minval7(%arg0: !hlfir.expr<?xi32>){
511+
// expected-error@+1 {{'hlfir.minval' op result must be of numerical scalar type}}
512+
%0 = hlfir.minval %arg0 : (!hlfir.expr<?xi32>) -> !hlfir.expr<i32>
513+
}
514+
515+
// -----
516+
func.func @bad_minval8(%arg0: !hlfir.expr<?x!fir.char<1,?>>, %arg1: i32, %arg2: !fir.box<!fir.logical<4>>) {
517+
// expected-error@+1 {{'hlfir.minval' op result must have the same element type as ARRAY argument}}
518+
%0 = hlfir.minval %arg0 dim %arg1 mask %arg2 : (!hlfir.expr<?x!fir.char<1,?>>, i32, !fir.box<!fir.logical<4>>) -> i32
519+
}
520+
521+
// -----
522+
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>>>) {
523+
// expected-warning@+1 {{MASK must be conformable to ARRAY}}
524+
%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,?>>
525+
}
526+
527+
// -----
528+
func.func @bad_minval10(%arg0: !hlfir.expr<?x5x?x!fir.char<1,?>>, %arg1: i32, %arg2: !fir.box<!fir.array<2x6x?x!fir.logical<4>>>) {
529+
// expected-warning@+1 {{MASK must be conformable to ARRAY}}
530+
%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,?>>
531+
}
532+
533+
// -----
534+
func.func @bad_minval11(%arg0: !hlfir.expr<?x?x!fir.char<1,?>>, %arg1: i32, %arg2: !fir.box<!fir.logical<4>>) {
535+
// expected-error@+1 {{'hlfir.minval' op result rank must be one less than ARRAY}}
536+
%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,?>>
537+
}
538+
539+
// -----
540+
func.func @bad_minval12(%arg0: !hlfir.expr<?x!fir.char<1,?>>, %arg1: i32, %arg2: !fir.box<!fir.logical<4>>) {
541+
// expected-error@+1 {{'hlfir.minval' op result must be scalar character}}
542+
%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,?>>
543+
}
544+
545+
// -----
546+
func.func @bad_minval13(%arg0: !hlfir.expr<?x?x!fir.char<1,?>>, %arg1: i32){
547+
// expected-error@+1 {{'hlfir.minval' op result must be an array}}
548+
%0 = hlfir.minval %arg0 dim %arg1 : (!hlfir.expr<?x?x!fir.char<1,?>>, i32) -> !hlfir.expr<!fir.char<1,?>>
549+
}
550+
473551
// -----
474552
func.func @bad_product1(%arg0: !hlfir.expr<?xi32>, %arg1: i32, %arg2: !fir.box<!fir.logical<4>>) {
475553
// expected-error@+1 {{'hlfir.product' op result must have the same element type as ARRAY argument}}

flang/test/HLFIR/memory-effects.fir

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,21 @@ func.func @maxval_effects(%arg0: !fir.ref<!fir.array<2x2xf32>>, %arg1: i32) {
107107
return
108108
}
109109

110+
func.func @minval_no_effects(%arg0: !hlfir.expr<?xf32>) {
111+
// expected-remark@+1 {{operation has no memory effects}}
112+
%minval = hlfir.minval %arg0 : (!hlfir.expr<?xf32>) -> f32
113+
// expected-remark@+1 {{operation has no memory effects}}
114+
return
115+
}
116+
117+
func.func @minval_effects(%arg0: !fir.ref<!fir.array<2x2xf32>>, %arg1: i32) {
118+
// expected-remark@+2 {{found an instance of 'allocate' on a value, on resource '<Default>'}}
119+
// expected-remark@+1 {{found an instance of 'read' on a value, on resource '<Default>'}}
120+
%minval = hlfir.minval %arg0 dim %arg1 : (!fir.ref<!fir.array<2x2xf32>>, i32) -> !hlfir.expr<2xf32>
121+
// expected-remark@+1 {{operation has no memory effects}}
122+
return
123+
}
124+
110125
func.func @dot_product_no_effects(%arg0: !hlfir.expr<?xf32>, %arg1: !hlfir.expr<?xf32>) {
111126
// expected-remark@+1 {{operation has no memory effects}}
112127
%0 = hlfir.dot_product %arg0 %arg1 : (!hlfir.expr<?xf32>, !hlfir.expr<?xf32>) -> f32

0 commit comments

Comments
 (0)