[flang] Inline fir.is_contiguous_box in some cases. (#133812)

Added inlining for `rank == 1` and `innermost` cases.
This commit is contained in:
Slava Zakharin
2025-04-01 08:41:11 -07:00
committed by GitHub
parent 65ad6267e8
commit 58551faaf1
2 changed files with 132 additions and 87 deletions

View File

@@ -75,27 +75,50 @@ mlir::LogicalResult IsContiguousBoxCoversion::matchAndRewrite(
fir::IsContiguousBoxOp op, mlir::PatternRewriter &rewriter) const {
mlir::Location loc = op.getLoc();
fir::FirOpBuilder builder(rewriter, op.getOperation());
// TODO: support preferInlineImplementation.
bool doInline = options.preferInlineImplementation && false;
if (!doInline) {
// Generate Fortran runtime call.
mlir::Value result;
if (op.getInnermost()) {
mlir::Value one =
builder.createIntegerConstant(loc, builder.getI32Type(), 1);
result =
fir::runtime::genIsContiguousUpTo(builder, loc, op.getBox(), one);
} else {
result = fir::runtime::genIsContiguous(builder, loc, op.getBox());
mlir::Value box = op.getBox();
if (options.preferInlineImplementation) {
auto boxType = mlir::cast<fir::BaseBoxType>(box.getType());
unsigned rank = fir::getBoxRank(boxType);
// If rank is one, or 'innermost' attribute is set and
// it is not a scalar, then generate a simple comparison
// for the leading dimension: (stride == elem_size || extent == 0).
//
// The scalar cases are supposed to be optimized by the canonicalization.
if (rank == 1 || (op.getInnermost() && rank > 0)) {
mlir::Type idxTy = builder.getIndexType();
auto eleSize = builder.create<fir::BoxEleSizeOp>(loc, idxTy, box);
mlir::Value zero = fir::factory::createZeroValue(builder, loc, idxTy);
auto dimInfo =
builder.create<fir::BoxDimsOp>(loc, idxTy, idxTy, idxTy, box, zero);
mlir::Value stride = dimInfo.getByteStride();
mlir::Value pred1 = builder.create<mlir::arith::CmpIOp>(
loc, mlir::arith::CmpIPredicate::eq, eleSize, stride);
mlir::Value extent = dimInfo.getExtent();
mlir::Value pred2 = builder.create<mlir::arith::CmpIOp>(
loc, mlir::arith::CmpIPredicate::eq, extent, zero);
mlir::Value result =
builder.create<mlir::arith::OrIOp>(loc, pred1, pred2);
result = builder.createConvert(loc, op.getType(), result);
rewriter.replaceOp(op, result);
return mlir::success();
}
result = builder.createConvert(loc, op.getType(), result);
rewriter.replaceOp(op, result);
return mlir::success();
// TODO: support arrays with multiple dimensions.
}
// Generate inline implementation.
TODO(loc, "inline IsContiguousBoxOp");
return mlir::failure();
// Generate Fortran runtime call.
mlir::Value result;
if (op.getInnermost()) {
mlir::Value one =
builder.createIntegerConstant(loc, builder.getI32Type(), 1);
result = fir::runtime::genIsContiguousUpTo(builder, loc, box, one);
} else {
result = fir::runtime::genIsContiguous(builder, loc, box);
}
result = builder.createConvert(loc, op.getType(), result);
rewriter.replaceOp(op, result);
return mlir::success();
}
/// Generate a call to Size runtime function or an inline

View File

@@ -1,17 +1,15 @@
// RUN: fir-opt --split-input-file --simplify-fir-operations %s | FileCheck %s
// -----
// RUN: fir-opt --split-input-file --simplify-fir-operations %s | FileCheck --check-prefixes=ALL,NOOPT %s
// RUN: fir-opt --split-input-file --simplify-fir-operations=prefer-inline-implementation=true %s | FileCheck --check-prefixes=ALL,OPT %s
func.func @test_none_innermost(%arg0: !fir.box<none>) -> i1 {
%0 = fir.is_contiguous_box %arg0 innermost : (!fir.box<none>) -> i1
return %0 : i1
}
// CHECK-LABEL: func.func @test_none_innermost(
// CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box<none>) -> i1 {
// CHECK: %[[VAL_1:.*]] = arith.constant 1 : i32
// CHECK: %[[VAL_2:.*]] = fir.call @_FortranAIsContiguousUpTo(%[[VAL_0]], %[[VAL_1]]) : (!fir.box<none>, i32) -> i1
// CHECK: return %[[VAL_2]] : i1
// CHECK: }
// ALL-LABEL: func.func @test_none_innermost(
// ALL-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box<none>) -> i1 {
// ALL: %[[VAL_1:.*]] = arith.constant 1 : i32
// ALL: %[[VAL_2:.*]] = fir.call @_FortranAIsContiguousUpTo(%[[VAL_0]], %[[VAL_1]]) : (!fir.box<none>, i32) -> i1
// ALL: return %[[VAL_2]] : i1
// -----
@@ -19,11 +17,11 @@ func.func @test_none_whole(%arg0: !fir.box<none>) -> i1 {
%0 = fir.is_contiguous_box %arg0 whole : (!fir.box<none>) -> i1
return %0 : i1
}
// CHECK-LABEL: func.func @test_none_whole(
// CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box<none>) -> i1 {
// CHECK: %[[VAL_1:.*]] = fir.call @_FortranAIsContiguous(%[[VAL_0]]) : (!fir.box<none>) -> i1
// CHECK: return %[[VAL_1]] : i1
// CHECK: }
// ALL-LABEL: func.func @test_none_whole(
// ALL-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box<none>) -> i1 {
// ALL: %[[VAL_1:.*]] = fir.call @_FortranAIsContiguous(%[[VAL_0]]) : (!fir.box<none>) -> i1
// ALL: return %[[VAL_1]] : i1
// ALL: }
// -----
@@ -31,13 +29,19 @@ func.func @test_array_innermost(%arg0: !fir.box<!fir.array<?xf32>>) -> i1 {
%0 = fir.is_contiguous_box %arg0 innermost : (!fir.box<!fir.array<?xf32>>) -> i1
return %0 : i1
}
// CHECK-LABEL: func.func @test_array_innermost(
// CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box<!fir.array<?xf32>>) -> i1 {
// CHECK: %[[VAL_1:.*]] = arith.constant 1 : i32
// CHECK: %[[VAL_2:.*]] = fir.convert %[[VAL_0]] : (!fir.box<!fir.array<?xf32>>) -> !fir.box<none>
// CHECK: %[[VAL_3:.*]] = fir.call @_FortranAIsContiguousUpTo(%[[VAL_2]], %[[VAL_1]]) : (!fir.box<none>, i32) -> i1
// CHECK: return %[[VAL_3]] : i1
// CHECK: }
// ALL-LABEL: func.func @test_array_innermost(
// ALL-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box<!fir.array<?xf32>>) -> i1 {
// NOOPT: %[[VAL_1:.*]] = arith.constant 1 : i32
// NOOPT: %[[VAL_2:.*]] = fir.convert %[[VAL_0]] : (!fir.box<!fir.array<?xf32>>) -> !fir.box<none>
// NOOPT: %[[VAL_3:.*]] = fir.call @_FortranAIsContiguousUpTo(%[[VAL_2]], %[[VAL_1]]) : (!fir.box<none>, i32) -> i1
// NOOPT: return %[[VAL_3]] : i1
// OPT: %[[VAL_1:.*]] = arith.constant 0 : index
// OPT: %[[VAL_2:.*]] = fir.box_elesize %[[VAL_0]] : (!fir.box<!fir.array<?xf32>>) -> index
// OPT: %[[VAL_3:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_1]] : (!fir.box<!fir.array<?xf32>>, index) -> (index, index, index)
// OPT: %[[VAL_4:.*]] = arith.cmpi eq, %[[VAL_2]], %[[VAL_3]]#2 : index
// OPT: %[[VAL_5:.*]] = arith.cmpi eq, %[[VAL_3]]#1, %[[VAL_1]] : index
// OPT: %[[VAL_6:.*]] = arith.ori %[[VAL_4]], %[[VAL_5]] : i1
// OPT: return %[[VAL_6]] : i1
// -----
@@ -45,12 +49,18 @@ func.func @test_array_whole(%arg0: !fir.box<!fir.array<?xf32>>) -> i1 {
%0 = fir.is_contiguous_box %arg0 whole : (!fir.box<!fir.array<?xf32>>) -> i1
return %0 : i1
}
// CHECK-LABEL: func.func @test_array_whole(
// CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box<!fir.array<?xf32>>) -> i1 {
// CHECK: %[[VAL_1:.*]] = fir.convert %[[VAL_0]] : (!fir.box<!fir.array<?xf32>>) -> !fir.box<none>
// CHECK: %[[VAL_2:.*]] = fir.call @_FortranAIsContiguous(%[[VAL_1]]) : (!fir.box<none>) -> i1
// CHECK: return %[[VAL_2]] : i1
// CHECK: }
// ALL-LABEL: func.func @test_array_whole(
// ALL-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box<!fir.array<?xf32>>) -> i1 {
// NOOPT: %[[VAL_1:.*]] = fir.convert %[[VAL_0]] : (!fir.box<!fir.array<?xf32>>) -> !fir.box<none>
// NOOPT: %[[VAL_2:.*]] = fir.call @_FortranAIsContiguous(%[[VAL_1]]) : (!fir.box<none>) -> i1
// NOOPT: return %[[VAL_2]] : i1
// OPT: %[[VAL_1:.*]] = arith.constant 0 : index
// OPT: %[[VAL_2:.*]] = fir.box_elesize %[[VAL_0]] : (!fir.box<!fir.array<?xf32>>) -> index
// OPT: %[[VAL_3:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_1]] : (!fir.box<!fir.array<?xf32>>, index) -> (index, index, index)
// OPT: %[[VAL_4:.*]] = arith.cmpi eq, %[[VAL_2]], %[[VAL_3]]#2 : index
// OPT: %[[VAL_5:.*]] = arith.cmpi eq, %[[VAL_3]]#1, %[[VAL_1]] : index
// OPT: %[[VAL_6:.*]] = arith.ori %[[VAL_4]], %[[VAL_5]] : i1
// OPT: return %[[VAL_6]] : i1
// -----
@@ -58,13 +68,12 @@ func.func @test_assumed_rank_innermost(%arg0: !fir.box<!fir.array<*:f32>>) -> i1
%0 = fir.is_contiguous_box %arg0 innermost : (!fir.box<!fir.array<*:f32>>) -> i1
return %0 : i1
}
// CHECK-LABEL: func.func @test_assumed_rank_innermost(
// CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box<!fir.array<*:f32>>) -> i1 {
// CHECK: %[[VAL_1:.*]] = arith.constant 1 : i32
// CHECK: %[[VAL_2:.*]] = fir.convert %[[VAL_0]] : (!fir.box<!fir.array<*:f32>>) -> !fir.box<none>
// CHECK: %[[VAL_3:.*]] = fir.call @_FortranAIsContiguousUpTo(%[[VAL_2]], %[[VAL_1]]) : (!fir.box<none>, i32) -> i1
// CHECK: return %[[VAL_3]] : i1
// CHECK: }
// ALL-LABEL: func.func @test_assumed_rank_innermost(
// ALL-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box<!fir.array<*:f32>>) -> i1 {
// ALL: %[[VAL_1:.*]] = arith.constant 1 : i32
// ALL: %[[VAL_2:.*]] = fir.convert %[[VAL_0]] : (!fir.box<!fir.array<*:f32>>) -> !fir.box<none>
// ALL: %[[VAL_3:.*]] = fir.call @_FortranAIsContiguousUpTo(%[[VAL_2]], %[[VAL_1]]) : (!fir.box<none>, i32) -> i1
// ALL: return %[[VAL_3]] : i1
// -----
@@ -72,12 +81,25 @@ func.func @test_assumed_rank_whole(%arg0: !fir.box<!fir.array<*:f32>>) -> i1 {
%0 = fir.is_contiguous_box %arg0 whole : (!fir.box<!fir.array<*:f32>>) -> i1
return %0 : i1
}
// CHECK-LABEL: func.func @test_assumed_rank_whole(
// CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box<!fir.array<*:f32>>) -> i1 {
// CHECK: %[[VAL_1:.*]] = fir.convert %[[VAL_0]] : (!fir.box<!fir.array<*:f32>>) -> !fir.box<none>
// CHECK: %[[VAL_2:.*]] = fir.call @_FortranAIsContiguous(%[[VAL_1]]) : (!fir.box<none>) -> i1
// CHECK: return %[[VAL_2]] : i1
// CHECK: }
// ALL-LABEL: func.func @test_assumed_rank_whole(
// ALL-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box<!fir.array<*:f32>>) -> i1 {
// ALL: %[[VAL_1:.*]] = fir.convert %[[VAL_0]] : (!fir.box<!fir.array<*:f32>>) -> !fir.box<none>
// ALL: %[[VAL_2:.*]] = fir.call @_FortranAIsContiguous(%[[VAL_1]]) : (!fir.box<none>) -> i1
// ALL: return %[[VAL_2]] : i1
// ALL: }
// -----
func.func @test_scalar_upoly(%arg0: !fir.class<none>) -> i1 {
%0 = fir.is_contiguous_box %arg0 innermost : (!fir.class<none>) -> i1
return %0 : i1
}
// ALL-LABEL: func.func @test_scalar_upoly(
// ALL-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.class<none>) -> i1 {
// ALL: %[[VAL_1:.*]] = arith.constant 1 : i32
// ALL: %[[VAL_2:.*]] = fir.convert %[[VAL_0]] : (!fir.class<none>) -> !fir.box<none>
// ALL: %[[VAL_3:.*]] = fir.call @_FortranAIsContiguousUpTo(%[[VAL_2]], %[[VAL_1]]) : (!fir.box<none>, i32) -> i1
// ALL: return %[[VAL_3]] : i1
// -----
@@ -85,15 +107,15 @@ func.func @test_none(%arg0: !fir.box<none>) -> i16 {
%0 = fir.box_total_elements %arg0 : (!fir.box<none>) -> i16
return %0 : i16
}
// CHECK-LABEL: func.func @test_none(
// CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box<none>) -> i16 {
// CHECK: %[[VAL_3:.*]] = arith.constant {{.*}} : i32
// CHECK: %[[VAL_1:.*]] = fir.address_of(@{{.*}}) : !fir.ref<!fir.char<1,{{.*}}>>
// CHECK: %[[VAL_4:.*]] = fir.convert %[[VAL_1]] : (!fir.ref<!fir.char<1,{{.*}}>>) -> !fir.ref<i8>
// CHECK: %[[VAL_5:.*]] = fir.call @_FortranASize(%[[VAL_0]], %[[VAL_4]], %[[VAL_3]]) : (!fir.box<none>, !fir.ref<i8>, i32) -> i64
// CHECK: %[[VAL_6:.*]] = fir.convert %[[VAL_5]] : (i64) -> i16
// CHECK: return %[[VAL_6]] : i16
// CHECK: }
// ALL-LABEL: func.func @test_none(
// ALL-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box<none>) -> i16 {
// ALL: %[[VAL_3:.*]] = arith.constant {{.*}} : i32
// ALL: %[[VAL_1:.*]] = fir.address_of(@{{.*}}) : !fir.ref<!fir.char<1,{{.*}}>>
// ALL: %[[VAL_4:.*]] = fir.convert %[[VAL_1]] : (!fir.ref<!fir.char<1,{{.*}}>>) -> !fir.ref<i8>
// ALL: %[[VAL_5:.*]] = fir.call @_FortranASize(%[[VAL_0]], %[[VAL_4]], %[[VAL_3]]) : (!fir.box<none>, !fir.ref<i8>, i32) -> i64
// ALL: %[[VAL_6:.*]] = fir.convert %[[VAL_5]] : (i64) -> i16
// ALL: return %[[VAL_6]] : i16
// ALL: }
// -----
@@ -101,16 +123,16 @@ func.func @test_array(%arg0: !fir.box<!fir.array<?x?xf32>>) -> i32 {
%0 = fir.box_total_elements %arg0 : (!fir.box<!fir.array<?x?xf32>>) -> i32
return %0 : i32
}
// CHECK-LABEL: func.func @test_array(
// CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box<!fir.array<?x?xf32>>) -> i32 {
// CHECK: %[[VAL_3:.*]] = arith.constant {{.*}} : i32
// CHECK: %[[VAL_1:.*]] = fir.address_of({{.*}}) : !fir.ref<!fir.char<1,{{.*}}>>
// CHECK: %[[VAL_4:.*]] = fir.convert %[[VAL_0]] : (!fir.box<!fir.array<?x?xf32>>) -> !fir.box<none>
// CHECK: %[[VAL_5:.*]] = fir.convert %[[VAL_1]] : (!fir.ref<!fir.char<1,{{.*}}>>) -> !fir.ref<i8>
// CHECK: %[[VAL_6:.*]] = fir.call @_FortranASize(%[[VAL_4]], %[[VAL_5]], %[[VAL_3]]) : (!fir.box<none>, !fir.ref<i8>, i32) -> i64
// CHECK: %[[VAL_7:.*]] = fir.convert %[[VAL_6]] : (i64) -> i32
// CHECK: return %[[VAL_7]] : i32
// CHECK: }
// ALL-LABEL: func.func @test_array(
// ALL-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box<!fir.array<?x?xf32>>) -> i32 {
// ALL: %[[VAL_3:.*]] = arith.constant {{.*}} : i32
// ALL: %[[VAL_1:.*]] = fir.address_of({{.*}}) : !fir.ref<!fir.char<1,{{.*}}>>
// ALL: %[[VAL_4:.*]] = fir.convert %[[VAL_0]] : (!fir.box<!fir.array<?x?xf32>>) -> !fir.box<none>
// ALL: %[[VAL_5:.*]] = fir.convert %[[VAL_1]] : (!fir.ref<!fir.char<1,{{.*}}>>) -> !fir.ref<i8>
// ALL: %[[VAL_6:.*]] = fir.call @_FortranASize(%[[VAL_4]], %[[VAL_5]], %[[VAL_3]]) : (!fir.box<none>, !fir.ref<i8>, i32) -> i64
// ALL: %[[VAL_7:.*]] = fir.convert %[[VAL_6]] : (i64) -> i32
// ALL: return %[[VAL_7]] : i32
// ALL: }
// -----
@@ -118,13 +140,13 @@ func.func @test_assumed_rank(%arg0: !fir.box<!fir.array<*:f32>>) -> index {
%0 = fir.box_total_elements %arg0 : (!fir.box<!fir.array<*:f32>>) -> index
return %0 : index
}
// CHECK-LABEL: func.func @test_assumed_rank(
// CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box<!fir.array<*:f32>>) -> index {
// CHECK: %[[VAL_3:.*]] = arith.constant {{.*}} : i32
// CHECK: %[[VAL_1:.*]] = fir.address_of({{.*}}) : !fir.ref<!fir.char<1,{{.*}}>>
// CHECK: %[[VAL_4:.*]] = fir.convert %[[VAL_0]] : (!fir.box<!fir.array<*:f32>>) -> !fir.box<none>
// CHECK: %[[VAL_5:.*]] = fir.convert %[[VAL_1]] : (!fir.ref<!fir.char<1,{{.*}}>>) -> !fir.ref<i8>
// CHECK: %[[VAL_6:.*]] = fir.call @_FortranASize(%[[VAL_4]], %[[VAL_5]], %[[VAL_3]]) : (!fir.box<none>, !fir.ref<i8>, i32) -> i64
// CHECK: %[[VAL_7:.*]] = fir.convert %[[VAL_6]] : (i64) -> index
// CHECK: return %[[VAL_7]] : index
// CHECK: }
// ALL-LABEL: func.func @test_assumed_rank(
// ALL-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box<!fir.array<*:f32>>) -> index {
// ALL: %[[VAL_3:.*]] = arith.constant {{.*}} : i32
// ALL: %[[VAL_1:.*]] = fir.address_of({{.*}}) : !fir.ref<!fir.char<1,{{.*}}>>
// ALL: %[[VAL_4:.*]] = fir.convert %[[VAL_0]] : (!fir.box<!fir.array<*:f32>>) -> !fir.box<none>
// ALL: %[[VAL_5:.*]] = fir.convert %[[VAL_1]] : (!fir.ref<!fir.char<1,{{.*}}>>) -> !fir.ref<i8>
// ALL: %[[VAL_6:.*]] = fir.call @_FortranASize(%[[VAL_4]], %[[VAL_5]], %[[VAL_3]]) : (!fir.box<none>, !fir.ref<i8>, i32) -> i64
// ALL: %[[VAL_7:.*]] = fir.convert %[[VAL_6]] : (i64) -> index
// ALL: return %[[VAL_7]] : index
// ALL: }