Skip to content

[Flang] HLFIR maxloc intrinsic #75450

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
Dec 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
26 changes: 26 additions & 0 deletions flang/include/flang/Optimizer/HLFIR/HLFIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,32 @@ def hlfir_MinlocOp : hlfir_Op<"minloc", [AttrSizedOperandSegments,
let hasVerifier = 1;
}

def hlfir_MaxlocOp : hlfir_Op<"maxloc", [AttrSizedOperandSegments,
DeclareOpInterfaceMethods<ArithFastMathInterface>,
DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
let summary = "MAXLOC transformational intrinsic";
let description = [{
Maxlocs of an array.
}];

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

let results = (outs AnyFortranValue);

let assemblyFormat = [{
$array (`dim` $dim^)? (`mask` $mask^)? (`back` $back^)? 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 @@ -105,6 +105,7 @@ class HlfirMinMaxLocIntrinsic : public HlfirTransformationalIntrinsic {
mlir::Type stmtResultType) override;
};
using HlfirMinlocLowering = HlfirMinMaxLocIntrinsic<hlfir::MinlocOp>;
using HlfirMaxlocLowering = HlfirMinMaxLocIntrinsic<hlfir::MaxlocOp>;

template <typename OP>
class HlfirProductIntrinsic : public HlfirTransformationalIntrinsic {
Expand Down Expand Up @@ -429,6 +430,9 @@ std::optional<hlfir::EntityWithAttributes> Fortran::lower::lowerHlfirIntrinsic(
if (name == "minloc")
return HlfirMinlocLowering{builder, loc}.lower(loweredActuals, argLowering,
stmtResultType);
if (name == "maxloc")
return HlfirMaxlocLowering{builder, loc}.lower(loweredActuals, argLowering,
stmtResultType);
if (mlir::isa<fir::CharacterType>(stmtResultType)) {
if (name == "min")
return HlfirCharExtremumLowering{builder, loc,
Expand Down
54 changes: 40 additions & 14 deletions flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -864,17 +864,15 @@ void hlfir::MinvalOp::getEffects(
// MinlocOp
//===----------------------------------------------------------------------===//

mlir::LogicalResult hlfir::MinlocOp::verify() {
mlir::Operation *op = getOperation();
template <typename NumericalReductionOp>
static mlir::LogicalResult
verifyResultForMinMaxLoc(NumericalReductionOp reductionOp) {
mlir::Operation *op = reductionOp->getOperation();
auto results = op->getResultTypes();
assert(results.size() == 1);

auto res = verifyArrayAndMaskForReductionOp(this);
if (failed(res))
return res;

mlir::Value array = getArray();
mlir::Value dim = getDim();
mlir::Value array = reductionOp->getArray();
mlir::Value dim = reductionOp->getDim();
fir::SequenceType arrayTy =
hlfir::getFortranElementOrSequenceType(array.getType())
.cast<fir::SequenceType>();
Expand All @@ -883,35 +881,63 @@ mlir::LogicalResult hlfir::MinlocOp::verify() {
mlir::Type resultType = results[0];
if (dim && arrayShape.size() == 1) {
if (!fir::isa_integer(resultType))
return emitOpError("result must be scalar integer");
return reductionOp->emitOpError("result must be scalar integer");
} else if (auto resultExpr =
mlir::dyn_cast_or_null<hlfir::ExprType>(resultType)) {
if (!resultExpr.isArray())
return emitOpError("result must be an array");
return reductionOp->emitOpError("result must be an array");

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

llvm::ArrayRef<int64_t> resultShape = resultExpr.getShape();
// With dim the result has rank n-1
if (dim && resultShape.size() != (arrayShape.size() - 1))
return emitOpError("result rank must be one less than ARRAY");
return reductionOp->emitOpError(
"result rank must be one less than ARRAY");
// With dim the result has rank n
if (!dim && resultShape.size() != 1)
return emitOpError("result rank must be 1");
return reductionOp->emitOpError("result rank must be 1");
} else {
return emitOpError("result must be of numerical expr type");
return reductionOp->emitOpError("result must be of numerical expr type");
}
return mlir::success();
}

mlir::LogicalResult hlfir::MinlocOp::verify() {
auto res = verifyArrayAndMaskForReductionOp(this);
if (failed(res))
return res;

return verifyResultForMinMaxLoc(this);
}

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

//===----------------------------------------------------------------------===//
// MaxlocOp
//===----------------------------------------------------------------------===//

mlir::LogicalResult hlfir::MaxlocOp::verify() {
auto res = verifyArrayAndMaskForReductionOp(this);
if (failed(res))
return res;

return verifyResultForMinMaxLoc(this);
}

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

//===----------------------------------------------------------------------===//
// SetLengthOp
//===----------------------------------------------------------------------===//
Expand Down
22 changes: 14 additions & 8 deletions flang/lib/Optimizer/HLFIR/Transforms/LowerHLFIRIntrinsics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,8 @@ class HlfirReductionIntrinsicConversion : public HlfirIntrinsicConversion<OP> {
opName = "minval";
} else if constexpr (std::is_same_v<OP, hlfir::MinlocOp>) {
opName = "minloc";
} else if constexpr (std::is_same_v<OP, hlfir::MaxlocOp>) {
opName = "maxloc";
} else if constexpr (std::is_same_v<OP, hlfir::AnyOp>) {
opName = "any";
} else if constexpr (std::is_same_v<OP, hlfir::AllOp>) {
Expand All @@ -265,7 +267,8 @@ class HlfirReductionIntrinsicConversion : public HlfirIntrinsicConversion<OP> {
std::is_same_v<OP, hlfir::MaxvalOp> ||
std::is_same_v<OP, hlfir::MinvalOp>) {
args = buildNumericalArgs(operation, i32, logicalType, rewriter, opName);
} else if constexpr (std::is_same_v<OP, hlfir::MinlocOp>) {
} else if constexpr (std::is_same_v<OP, hlfir::MinlocOp> ||
std::is_same_v<OP, hlfir::MaxlocOp>) {
args = buildMinMaxLocArgs(operation, i32, logicalType, rewriter, opName,
builder);
} else {
Expand Down Expand Up @@ -293,6 +296,8 @@ using MinvalOpConversion = HlfirReductionIntrinsicConversion<hlfir::MinvalOp>;

using MinlocOpConversion = HlfirReductionIntrinsicConversion<hlfir::MinlocOp>;

using MaxlocOpConversion = HlfirReductionIntrinsicConversion<hlfir::MaxlocOp>;

using AnyOpConversion = HlfirReductionIntrinsicConversion<hlfir::AnyOp>;

using AllOpConversion = HlfirReductionIntrinsicConversion<hlfir::AllOp>;
Expand Down Expand Up @@ -465,20 +470,21 @@ class LowerHLFIRIntrinsics
mlir::ModuleOp module = this->getOperation();
mlir::MLIRContext *context = &getContext();
mlir::RewritePatternSet patterns(context);
patterns.insert<MatmulOpConversion, MatmulTransposeOpConversion,
AllOpConversion, AnyOpConversion, SumOpConversion,
ProductOpConversion, TransposeOpConversion,
CountOpConversion, DotProductOpConversion,
MaxvalOpConversion, MinvalOpConversion, MinlocOpConversion>(
context);
patterns
.insert<MatmulOpConversion, MatmulTransposeOpConversion,
AllOpConversion, AnyOpConversion, SumOpConversion,
ProductOpConversion, TransposeOpConversion, CountOpConversion,
DotProductOpConversion, MaxvalOpConversion, MinvalOpConversion,
MinlocOpConversion, MaxlocOpConversion>(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::MinvalOp, hlfir::MinlocOp>();
hlfir::MaxvalOp, hlfir::MinvalOp, hlfir::MinlocOp,
hlfir::MaxlocOp>();
target.markUnknownOpDynamicallyLegal(
[](mlir::Operation *) { return true; });
if (mlir::failed(
Expand Down
65 changes: 65 additions & 0 deletions flang/test/HLFIR/invalid.fir
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,71 @@ func.func @bad_minloc11(%arg0: !hlfir.expr<?x?x!fir.char<1,?>>, %arg1: i32, %arg
%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>
}

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

// -----
func.func @bad_maxloc2(%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.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>
}

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

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

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

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

// -----
func.func @bad_maxloc8(%arg0: !hlfir.expr<?xi32>){
// expected-error@+1 {{'hlfir.maxloc' op result must have integer elements}}
%0 = hlfir.maxloc %arg0 : (!hlfir.expr<?xi32>) -> !hlfir.expr<?xf32>
}

// -----
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>>>) {
// expected-warning@+1 {{MASK must be conformable to ARRAY}}
%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,?>>
}

// -----
func.func @bad_maxloc10(%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.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,?>>
}

// -----
func.func @bad_maxloc11(%arg0: !hlfir.expr<?x?x!fir.char<1,?>>, %arg1: i32, %arg2: !fir.box<!fir.logical<4>>) {
// expected-error@+1 {{'hlfir.maxloc' op result rank must be one less than ARRAY}}
%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>
}


// -----
Expand Down
Loading