Skip to content

Commit 2812cb0

Browse files
authored
[Flang] HLFIR maxloc intrinsic (#75450)
Similar to minloc from #74436, this adds a hlfir maxloc intrinsic so that we can keep them symmetrical. It's just a bit of copy and pasting.
1 parent 34eee5d commit 2812cb0

File tree

9 files changed

+1135
-22
lines changed

9 files changed

+1135
-22
lines changed

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,32 @@ def hlfir_MinlocOp : hlfir_Op<"minloc", [AttrSizedOperandSegments,
483483
let hasVerifier = 1;
484484
}
485485

486+
def hlfir_MaxlocOp : hlfir_Op<"maxloc", [AttrSizedOperandSegments,
487+
DeclareOpInterfaceMethods<ArithFastMathInterface>,
488+
DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
489+
let summary = "MAXLOC transformational intrinsic";
490+
let description = [{
491+
Maxlocs of an array.
492+
}];
493+
494+
let arguments = (ins
495+
AnyFortranArrayObject:$array,
496+
Optional<AnyIntegerType>:$dim,
497+
Optional<AnyFortranLogicalOrI1ArrayObject>:$mask,
498+
Optional<Type<AnyLogicalLike.predicate>>:$back,
499+
DefaultValuedAttr<Arith_FastMathAttr,
500+
"::mlir::arith::FastMathFlags::none">:$fastmath
501+
);
502+
503+
let results = (outs AnyFortranValue);
504+
505+
let assemblyFormat = [{
506+
$array (`dim` $dim^)? (`mask` $mask^)? (`back` $back^)? attr-dict `:` functional-type(operands, results)
507+
}];
508+
509+
let hasVerifier = 1;
510+
}
511+
486512
def hlfir_ProductOp : hlfir_Op<"product", [AttrSizedOperandSegments,
487513
DeclareOpInterfaceMethods<ArithFastMathInterface>,
488514
DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {

flang/lib/Lower/HlfirIntrinsics.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ class HlfirMinMaxLocIntrinsic : public HlfirTransformationalIntrinsic {
105105
mlir::Type stmtResultType) override;
106106
};
107107
using HlfirMinlocLowering = HlfirMinMaxLocIntrinsic<hlfir::MinlocOp>;
108+
using HlfirMaxlocLowering = HlfirMinMaxLocIntrinsic<hlfir::MaxlocOp>;
108109

109110
template <typename OP>
110111
class HlfirProductIntrinsic : public HlfirTransformationalIntrinsic {
@@ -428,6 +429,9 @@ std::optional<hlfir::EntityWithAttributes> Fortran::lower::lowerHlfirIntrinsic(
428429
if (name == "minloc")
429430
return HlfirMinlocLowering{builder, loc}.lower(loweredActuals, argLowering,
430431
stmtResultType);
432+
if (name == "maxloc")
433+
return HlfirMaxlocLowering{builder, loc}.lower(loweredActuals, argLowering,
434+
stmtResultType);
431435
if (mlir::isa<fir::CharacterType>(stmtResultType)) {
432436
if (name == "min")
433437
return HlfirCharExtremumLowering{builder, loc,

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

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -864,17 +864,15 @@ void hlfir::MinvalOp::getEffects(
864864
// MinlocOp
865865
//===----------------------------------------------------------------------===//
866866

867-
mlir::LogicalResult hlfir::MinlocOp::verify() {
868-
mlir::Operation *op = getOperation();
867+
template <typename NumericalReductionOp>
868+
static mlir::LogicalResult
869+
verifyResultForMinMaxLoc(NumericalReductionOp reductionOp) {
870+
mlir::Operation *op = reductionOp->getOperation();
869871
auto results = op->getResultTypes();
870872
assert(results.size() == 1);
871873

872-
auto res = verifyArrayAndMaskForReductionOp(this);
873-
if (failed(res))
874-
return res;
875-
876-
mlir::Value array = getArray();
877-
mlir::Value dim = getDim();
874+
mlir::Value array = reductionOp->getArray();
875+
mlir::Value dim = reductionOp->getDim();
878876
fir::SequenceType arrayTy =
879877
hlfir::getFortranElementOrSequenceType(array.getType())
880878
.cast<fir::SequenceType>();
@@ -883,35 +881,63 @@ mlir::LogicalResult hlfir::MinlocOp::verify() {
883881
mlir::Type resultType = results[0];
884882
if (dim && arrayShape.size() == 1) {
885883
if (!fir::isa_integer(resultType))
886-
return emitOpError("result must be scalar integer");
884+
return reductionOp->emitOpError("result must be scalar integer");
887885
} else if (auto resultExpr =
888886
mlir::dyn_cast_or_null<hlfir::ExprType>(resultType)) {
889887
if (!resultExpr.isArray())
890-
return emitOpError("result must be an array");
888+
return reductionOp->emitOpError("result must be an array");
891889

892890
if (!fir::isa_integer(resultExpr.getEleTy()))
893-
return emitOpError("result must have integer elements");
891+
return reductionOp->emitOpError("result must have integer elements");
894892

895893
llvm::ArrayRef<int64_t> resultShape = resultExpr.getShape();
896894
// With dim the result has rank n-1
897895
if (dim && resultShape.size() != (arrayShape.size() - 1))
898-
return emitOpError("result rank must be one less than ARRAY");
896+
return reductionOp->emitOpError(
897+
"result rank must be one less than ARRAY");
899898
// With dim the result has rank n
900899
if (!dim && resultShape.size() != 1)
901-
return emitOpError("result rank must be 1");
900+
return reductionOp->emitOpError("result rank must be 1");
902901
} else {
903-
return emitOpError("result must be of numerical expr type");
902+
return reductionOp->emitOpError("result must be of numerical expr type");
904903
}
905904
return mlir::success();
906905
}
907906

907+
mlir::LogicalResult hlfir::MinlocOp::verify() {
908+
auto res = verifyArrayAndMaskForReductionOp(this);
909+
if (failed(res))
910+
return res;
911+
912+
return verifyResultForMinMaxLoc(this);
913+
}
914+
908915
void hlfir::MinlocOp::getEffects(
909916
llvm::SmallVectorImpl<
910917
mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
911918
&effects) {
912919
getIntrinsicEffects(getOperation(), effects);
913920
}
914921

922+
//===----------------------------------------------------------------------===//
923+
// MaxlocOp
924+
//===----------------------------------------------------------------------===//
925+
926+
mlir::LogicalResult hlfir::MaxlocOp::verify() {
927+
auto res = verifyArrayAndMaskForReductionOp(this);
928+
if (failed(res))
929+
return res;
930+
931+
return verifyResultForMinMaxLoc(this);
932+
}
933+
934+
void hlfir::MaxlocOp::getEffects(
935+
llvm::SmallVectorImpl<
936+
mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
937+
&effects) {
938+
getIntrinsicEffects(getOperation(), effects);
939+
}
940+
915941
//===----------------------------------------------------------------------===//
916942
// SetLengthOp
917943
//===----------------------------------------------------------------------===//

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

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,8 @@ class HlfirReductionIntrinsicConversion : public HlfirIntrinsicConversion<OP> {
249249
opName = "minval";
250250
} else if constexpr (std::is_same_v<OP, hlfir::MinlocOp>) {
251251
opName = "minloc";
252+
} else if constexpr (std::is_same_v<OP, hlfir::MaxlocOp>) {
253+
opName = "maxloc";
252254
} else if constexpr (std::is_same_v<OP, hlfir::AnyOp>) {
253255
opName = "any";
254256
} else if constexpr (std::is_same_v<OP, hlfir::AllOp>) {
@@ -271,7 +273,8 @@ class HlfirReductionIntrinsicConversion : public HlfirIntrinsicConversion<OP> {
271273
std::is_same_v<OP, hlfir::MaxvalOp> ||
272274
std::is_same_v<OP, hlfir::MinvalOp>) {
273275
args = buildNumericalArgs(operation, i32, logicalType, rewriter, opName);
274-
} else if constexpr (std::is_same_v<OP, hlfir::MinlocOp>) {
276+
} else if constexpr (std::is_same_v<OP, hlfir::MinlocOp> ||
277+
std::is_same_v<OP, hlfir::MaxlocOp>) {
275278
args = buildMinMaxLocArgs(operation, i32, logicalType, rewriter, opName,
276279
builder);
277280
} else {
@@ -299,6 +302,8 @@ using MinvalOpConversion = HlfirReductionIntrinsicConversion<hlfir::MinvalOp>;
299302

300303
using MinlocOpConversion = HlfirReductionIntrinsicConversion<hlfir::MinlocOp>;
301304

305+
using MaxlocOpConversion = HlfirReductionIntrinsicConversion<hlfir::MaxlocOp>;
306+
302307
using AnyOpConversion = HlfirReductionIntrinsicConversion<hlfir::AnyOp>;
303308

304309
using AllOpConversion = HlfirReductionIntrinsicConversion<hlfir::AllOp>;
@@ -473,20 +478,21 @@ class LowerHLFIRIntrinsics
473478
mlir::ModuleOp module = this->getOperation();
474479
mlir::MLIRContext *context = &getContext();
475480
mlir::RewritePatternSet patterns(context);
476-
patterns.insert<MatmulOpConversion, MatmulTransposeOpConversion,
477-
AllOpConversion, AnyOpConversion, SumOpConversion,
478-
ProductOpConversion, TransposeOpConversion,
479-
CountOpConversion, DotProductOpConversion,
480-
MaxvalOpConversion, MinvalOpConversion, MinlocOpConversion>(
481-
context);
481+
patterns
482+
.insert<MatmulOpConversion, MatmulTransposeOpConversion,
483+
AllOpConversion, AnyOpConversion, SumOpConversion,
484+
ProductOpConversion, TransposeOpConversion, CountOpConversion,
485+
DotProductOpConversion, MaxvalOpConversion, MinvalOpConversion,
486+
MinlocOpConversion, MaxlocOpConversion>(context);
482487
mlir::ConversionTarget target(*context);
483488
target.addLegalDialect<mlir::BuiltinDialect, mlir::arith::ArithDialect,
484489
mlir::func::FuncDialect, fir::FIROpsDialect,
485490
hlfir::hlfirDialect>();
486491
target.addIllegalOp<hlfir::MatmulOp, hlfir::MatmulTransposeOp, hlfir::SumOp,
487492
hlfir::ProductOp, hlfir::TransposeOp, hlfir::AnyOp,
488493
hlfir::AllOp, hlfir::DotProductOp, hlfir::CountOp,
489-
hlfir::MaxvalOp, hlfir::MinvalOp, hlfir::MinlocOp>();
494+
hlfir::MaxvalOp, hlfir::MinvalOp, hlfir::MinlocOp,
495+
hlfir::MaxlocOp>();
490496
target.markUnknownOpDynamicallyLegal(
491497
[](mlir::Operation *) { return true; });
492498
if (mlir::failed(

flang/test/HLFIR/invalid.fir

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,71 @@ func.func @bad_minloc11(%arg0: !hlfir.expr<?x?x!fir.char<1,?>>, %arg1: i32, %arg
614614
%0 = hlfir.minloc %arg0 dim %arg1 mask %arg2 : (!hlfir.expr<?x?x!fir.char<1,?>>, i32, !fir.box<!fir.logical<4>>) -> !hlfir.expr<?x?xi32>
615615
}
616616

617+
// -----
618+
func.func @bad_maxloc1(%arg0: !hlfir.expr<?xi32>, %arg1: i32, %arg2: !fir.box<!fir.logical<4>>) {
619+
// expected-error@+1 {{'hlfir.maxloc' op result must be scalar integer}}
620+
%0 = hlfir.maxloc %arg0 dim %arg1 mask %arg2 : (!hlfir.expr<?xi32>, i32, !fir.box<!fir.logical<4>>) -> f32
621+
}
622+
623+
// -----
624+
func.func @bad_maxloc2(%arg0: !hlfir.expr<?xi32>, %arg1: i32, %arg2: !fir.box<!fir.array<?x?x?x?x?x!fir.logical<4>>>) {
625+
// expected-warning@+1 {{MASK must be conformable to ARRAY}}
626+
%0 = hlfir.maxloc %arg0 dim %arg1 mask %arg2 : (!hlfir.expr<?xi32>, i32, !fir.box<!fir.array<?x?x?x?x?x!fir.logical<4>>>) -> !hlfir.expr<i32>
627+
}
628+
629+
// -----
630+
func.func @bad_maxloc3(%arg0: !hlfir.expr<?x5x?xi32>, %arg1: i32, %arg2: !fir.box<!fir.array<2x6x?x!fir.logical<4>>>) {
631+
// expected-warning@+1 {{MASK must be conformable to ARRAY}}
632+
%0 = hlfir.maxloc %arg0 dim %arg1 mask %arg2 : (!hlfir.expr<?x5x?xi32>, i32, !fir.box<!fir.array<2x6x?x!fir.logical<4>>>) -> !hlfir.expr<i32>
633+
}
634+
635+
// -----
636+
func.func @bad_maxloc4(%arg0: !hlfir.expr<?x?xi32>, %arg1: i32, %arg2: !fir.box<!fir.logical<4>>) {
637+
// expected-error@+1 {{'hlfir.maxloc' op result rank must be one less than ARRAY}}
638+
%0 = hlfir.maxloc %arg0 dim %arg1 mask %arg2 : (!hlfir.expr<?x?xi32>, i32, !fir.box<!fir.logical<4>>) -> !hlfir.expr<?x?xi32>
639+
}
640+
641+
// -----
642+
func.func @bad_maxloc5(%arg0: !hlfir.expr<?xi32>, %arg1: i32, %arg2: !fir.box<!fir.logical<4>>) {
643+
// expected-error@+1 {{'hlfir.maxloc' op result must be scalar integer}}
644+
%0 = hlfir.maxloc %arg0 dim %arg1 mask %arg2 : (!hlfir.expr<?xi32>, i32, !fir.box<!fir.logical<4>>) -> !fir.logical<4>
645+
}
646+
647+
// -----
648+
func.func @bad_maxloc6(%arg0: !hlfir.expr<?x?xi32>, %arg1: i32){
649+
// expected-error@+1 {{'hlfir.maxloc' op result must be an array}}
650+
%0 = hlfir.maxloc %arg0 dim %arg1 : (!hlfir.expr<?x?xi32>, i32) -> !hlfir.expr<i32>
651+
}
652+
653+
// -----
654+
func.func @bad_maxloc7(%arg0: !hlfir.expr<?xi32>){
655+
// expected-error@+1 {{'hlfir.maxloc' op result must be of numerical expr type}}
656+
%0 = hlfir.maxloc %arg0 : (!hlfir.expr<?xi32>) -> i32
657+
}
658+
659+
// -----
660+
func.func @bad_maxloc8(%arg0: !hlfir.expr<?xi32>){
661+
// expected-error@+1 {{'hlfir.maxloc' op result must have integer elements}}
662+
%0 = hlfir.maxloc %arg0 : (!hlfir.expr<?xi32>) -> !hlfir.expr<?xf32>
663+
}
664+
665+
// -----
666+
func.func @bad_maxloc9(%arg0: !hlfir.expr<?x!fir.char<1,?>>, %arg1: i32, %arg2: !fir.box<!fir.array<?x?x?x?x?x!fir.logical<4>>>) {
667+
// expected-warning@+1 {{MASK must be conformable to ARRAY}}
668+
%0 = hlfir.maxloc %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,?>>
669+
}
670+
671+
// -----
672+
func.func @bad_maxloc10(%arg0: !hlfir.expr<?x5x?x!fir.char<1,?>>, %arg1: i32, %arg2: !fir.box<!fir.array<2x6x?x!fir.logical<4>>>) {
673+
// expected-warning@+1 {{MASK must be conformable to ARRAY}}
674+
%0 = hlfir.maxloc %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,?>>
675+
}
676+
677+
// -----
678+
func.func @bad_maxloc11(%arg0: !hlfir.expr<?x?x!fir.char<1,?>>, %arg1: i32, %arg2: !fir.box<!fir.logical<4>>) {
679+
// expected-error@+1 {{'hlfir.maxloc' op result rank must be one less than ARRAY}}
680+
%0 = hlfir.maxloc %arg0 dim %arg1 mask %arg2 : (!hlfir.expr<?x?x!fir.char<1,?>>, i32, !fir.box<!fir.logical<4>>) -> !hlfir.expr<?x?xi32>
681+
}
617682

618683

619684
// -----

0 commit comments

Comments
 (0)