[flang-commits] [flang] [flang] add fir.rebox_assumed_rank operation (PR #93334)
via flang-commits
flang-commits at lists.llvm.org
Mon May 27 01:33:28 PDT 2024
https://github.com/jeanPerier updated https://github.com/llvm/llvm-project/pull/93334
>From e25a6254bb19c392b89b338f66b7e7ca2831e3de Mon Sep 17 00:00:00 2001
From: Jean Perier <jperier at nvidia.com>
Date: Fri, 24 May 2024 07:04:44 -0700
Subject: [PATCH 1/2] [flang] add fir.rebox_assumed_rank operation
As described in https://github.com/llvm/llvm-project/blob/main/flang/docs/AssumedRank.md,
add an operation to get copies of assumed-rank descriptors where lower bounds,
attributes, and dynamic type may have been changed.
---
.../flang/Optimizer/Dialect/FIRAttr.td | 11 +++++
.../include/flang/Optimizer/Dialect/FIROps.td | 37 +++++++++++++++
flang/lib/Optimizer/Dialect/FIROps.cpp | 46 +++++++++++++++++++
flang/test/Fir/fir-ops.fir | 12 +++++
flang/test/Fir/invalid.fir | 24 ++++++++++
5 files changed, 130 insertions(+)
diff --git a/flang/include/flang/Optimizer/Dialect/FIRAttr.td b/flang/include/flang/Optimizer/Dialect/FIRAttr.td
index 989319ff3ddaf..0c34b640a5c9c 100644
--- a/flang/include/flang/Optimizer/Dialect/FIRAttr.td
+++ b/flang/include/flang/Optimizer/Dialect/FIRAttr.td
@@ -70,4 +70,15 @@ def fir_BoxFieldAttr : I32EnumAttr<
// mlir::SideEffects::Resource for modelling operations which add debugging information
def DebuggingResource : Resource<"::fir::DebuggingResource">;
+def fir_LowerBoundModifierAttribute : I32EnumAttr<
+ "LowerBoundModifierAttribute",
+ "Describes how to modify lower bounds",
+ [
+ I32EnumAttrCase<"Preserve", 0, "preserve">,
+ I32EnumAttrCase<"SetToOnes", 1, "ones">,
+ I32EnumAttrCase<"SetToZeroes", 2, "zeroes">,
+ ]> {
+ let cppNamespace = "::fir";
+}
+
#endif // FIR_DIALECT_FIR_ATTRS
diff --git a/flang/include/flang/Optimizer/Dialect/FIROps.td b/flang/include/flang/Optimizer/Dialect/FIROps.td
index d9c1149040066..24dfde812039d 100644
--- a/flang/include/flang/Optimizer/Dialect/FIROps.td
+++ b/flang/include/flang/Optimizer/Dialect/FIROps.td
@@ -857,6 +857,43 @@ def fir_ReboxOp : fir_Op<"rebox", [NoMemoryEffect, AttrSizedOperandSegments]> {
let hasVerifier = 1;
}
+def fir_ReboxAssumedRankOp : fir_Op<"rebox_assumed_rank",
+ [DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
+ let summary = "create an assumed-rank box given another assumed rank-box";
+
+ let description = [{
+ Limited version of fir.rebox for assumed-rank. Only the lower bounds,
+ attribute, and element type may change.
+
+ The input may be a box or a reference to a box, in which case the operation
+ reads the incoming reference.
+ Since a fir.shift cannot be built without knowing the rank statically,
+ lower bound changes are encoded via a LowerBoundModifierAttribute.
+ Attribute and element type change are encoded in the result type.
+ Changing the element type is only allowed if the input type is a derived
+ type that extends the output element type.
+
+ Example:
+ ```
+ fir.rebox_assumed_rank %1 lbs zeroes : (!fir.box<!fir.array<*:f32>>) -> !fir.box<!fir.array<*:f32>>
+ ```
+ }];
+
+ let arguments = (ins
+ AnyRefOrBoxType:$box,
+ fir_LowerBoundModifierAttribute:$lbs_modifier
+ );
+
+ let results = (outs BoxOrClassType);
+
+ let assemblyFormat = [{
+ $box `lbs` $lbs_modifier
+ attr-dict `:` functional-type(operands, results)
+ }];
+
+ let hasVerifier = 1;
+}
+
def fir_EmboxCharOp : fir_Op<"emboxchar", [NoMemoryEffect]> {
let summary = "boxes a given CHARACTER reference and its LEN parameter";
diff --git a/flang/lib/Optimizer/Dialect/FIROps.cpp b/flang/lib/Optimizer/Dialect/FIROps.cpp
index 94113da9a46cf..998e9535582cb 100644
--- a/flang/lib/Optimizer/Dialect/FIROps.cpp
+++ b/flang/lib/Optimizer/Dialect/FIROps.cpp
@@ -2412,6 +2412,52 @@ mlir::LogicalResult fir::ReboxOp::verify() {
return mlir::success();
}
+//===----------------------------------------------------------------------===//
+// ReboxAssumedRankOp
+//===----------------------------------------------------------------------===//
+
+static bool areCompatibleAssumedRankElementType(mlir::Type inputEleTy,
+ mlir::Type outEleTy) {
+ if (inputEleTy == outEleTy)
+ return true;
+ // Output is unlimited polymorphic -> output dynamic type is the same as input
+ // type.
+ if (mlir::isa<mlir::NoneType>(outEleTy))
+ return true;
+ // Output/Input are derived types. Assuming input extends output type, output
+ // dynamic type is the output static type, unless output is polymorphic.
+ if (mlir::isa<fir::RecordType>(inputEleTy) &&
+ mlir::isa<fir::RecordType>(outEleTy))
+ return true;
+ if (areCompatibleCharacterTypes(inputEleTy, outEleTy))
+ return true;
+ return false;
+}
+
+mlir::LogicalResult fir::ReboxAssumedRankOp::verify() {
+ mlir::Type inputType = getBox().getType();
+ if (!mlir::isa<fir::BaseBoxType>(inputType) && !fir::isBoxAddress(inputType))
+ return emitOpError("input must be a box or box address");
+ mlir::Type inputEleTy =
+ mlir::cast<fir::BaseBoxType>(fir::unwrapRefType(inputType))
+ .unwrapInnerType();
+ mlir::Type outEleTy =
+ mlir::cast<fir::BaseBoxType>(getType()).unwrapInnerType();
+ if (!areCompatibleAssumedRankElementType(inputEleTy, outEleTy))
+ return emitOpError("input and output element types are incompatible");
+ return mlir::success();
+}
+
+void fir::ReboxAssumedRankOp::getEffects(
+ llvm::SmallVectorImpl<
+ mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
+ &effects) {
+ mlir::Value inputBox = getBox();
+ if (fir::isBoxAddress(inputBox.getType()))
+ effects.emplace_back(mlir::MemoryEffects::Read::get(), inputBox,
+ mlir::SideEffects::DefaultResource::get());
+}
+
//===----------------------------------------------------------------------===//
// ResultOp
//===----------------------------------------------------------------------===//
diff --git a/flang/test/Fir/fir-ops.fir b/flang/test/Fir/fir-ops.fir
index 962621c4e2e1a..a826dd49ef99d 100644
--- a/flang/test/Fir/fir-ops.fir
+++ b/flang/test/Fir/fir-ops.fir
@@ -900,3 +900,15 @@ fir.global @t1 {keep_my_attr = "data"} : i32 {
}
// CHECK-LABEL: fir.global @t1 {keep_my_attr = "data"} : i32
+
+func.func @test_rebox_assumed_rank(%arg0: !fir.box<!fir.array<*:f32>> ) {
+ %1 = fir.rebox_assumed_rank %arg0 lbs ones : (!fir.box<!fir.array<*:f32>>) -> !fir.box<!fir.array<*:f32>>
+ %2 = fir.rebox_assumed_rank %arg0 lbs zeroes : (!fir.box<!fir.array<*:f32>>) -> !fir.box<!fir.array<*:f32>>
+ %3 = fir.rebox_assumed_rank %arg0 lbs preserve : (!fir.box<!fir.array<*:f32>>) -> !fir.box<!fir.array<*:f32>>
+ return
+}
+// CHECK-LABEL: func.func @test_rebox_assumed_rank(
+// CHECK-SAME: %[[A:.*]]: !fir.box<!fir.array<*:f32>>)
+ // CHECK: fir.rebox_assumed_rank %[[A]] lbs ones : (!fir.box<!fir.array<*:f32>>) -> !fir.box<!fir.array<*:f32>>
+ // CHECK: fir.rebox_assumed_rank %[[A]] lbs zeroes : (!fir.box<!fir.array<*:f32>>) -> !fir.box<!fir.array<*:f32>>
+ // CHECK: fir.rebox_assumed_rank %[[A]] lbs preserve : (!fir.box<!fir.array<*:f32>>) -> !fir.box<!fir.array<*:f32>>
diff --git a/flang/test/Fir/invalid.fir b/flang/test/Fir/invalid.fir
index 049e108ba992d..f1e1aa433b9b0 100644
--- a/flang/test/Fir/invalid.fir
+++ b/flang/test/Fir/invalid.fir
@@ -978,3 +978,27 @@ func.func @bad_box_offset(%no_addendum : !fir.ref<!fir.box<i32>>) {
%addr1 = fir.box_offset %no_addendum derived_type : (!fir.ref<!fir.box<i32>>) -> !fir.llvm_ptr<!fir.tdesc<!fir.type<none>>>
return
}
+
+// -----
+
+func.func @bad_rebox_assumed_rank_1(%arg0: !fir.ref<!fir.array<*:f32>> ) {
+ // expected-error at +1{{'fir.rebox_assumed_rank' op input must be a box or box address}}
+ %1 = fir.rebox_assumed_rank %arg0 lbs ones : (!fir.ref<!fir.array<*:f32>>) -> !fir.box<!fir.array<*:f32>>
+ return
+}
+
+// -----
+
+func.func @bad_rebox_assumed_rank_2(%arg0: !fir.box<!fir.array<*:f32>> ) {
+ // expected-error at +1{{'fir.rebox_assumed_rank' op result #0 must be box or class, but got '!fir.ref<!fir.box<!fir.array<*:f32>>>'}}
+ %1 = fir.rebox_assumed_rank %arg0 lbs ones : (!fir.box<!fir.array<*:f32>>) -> !fir.ref<!fir.box<!fir.array<*:f32>>>
+ return
+}
+
+// -----
+
+func.func @bad_rebox_assumed_rank_3(%arg0: !fir.box<!fir.array<*:f32>> ) {
+ // expected-error at +1{{'fir.rebox_assumed_rank' op input and output element types are incompatible}}
+ %1 = fir.rebox_assumed_rank %arg0 lbs ones : (!fir.box<!fir.array<*:f32>>) -> !fir.box<!fir.array<*:i32>>
+ return
+}
>From 4ef00cd3e18dbcf9531b4f211682114177db8a65 Mon Sep 17 00:00:00 2001
From: jeanPerier <jean.perier.polytechnique at gmail.com>
Date: Mon, 27 May 2024 10:33:21 +0200
Subject: [PATCH 2/2] Update flang/include/flang/Optimizer/Dialect/FIROps.td
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Valentin Clement (バレンタイン クレメン) <clementval at gmail.com>
---
flang/include/flang/Optimizer/Dialect/FIROps.td | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/flang/include/flang/Optimizer/Dialect/FIROps.td b/flang/include/flang/Optimizer/Dialect/FIROps.td
index 24dfde812039d..584b7e82bf27a 100644
--- a/flang/include/flang/Optimizer/Dialect/FIROps.td
+++ b/flang/include/flang/Optimizer/Dialect/FIROps.td
@@ -859,7 +859,7 @@ def fir_ReboxOp : fir_Op<"rebox", [NoMemoryEffect, AttrSizedOperandSegments]> {
def fir_ReboxAssumedRankOp : fir_Op<"rebox_assumed_rank",
[DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
- let summary = "create an assumed-rank box given another assumed rank-box";
+ let summary = "create an assumed-rank box given another assumed-rank box";
let description = [{
Limited version of fir.rebox for assumed-rank. Only the lower bounds,
More information about the flang-commits
mailing list