Skip to content

Commit b0b3596

Browse files
authored
[flang] add fir.rebox_assumed_rank operation (#93334)
As described in https://github.com/llvm/llvm-project/blob/main/flang/docs/AssumedRank.md, add an operation to make copies of assumed-rank descriptors where lower bounds, attributes, or dynamic type may have been changed.
1 parent cc184ee commit b0b3596

File tree

5 files changed

+130
-0
lines changed

5 files changed

+130
-0
lines changed

flang/include/flang/Optimizer/Dialect/FIRAttr.td

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,4 +70,15 @@ def fir_BoxFieldAttr : I32EnumAttr<
7070
// mlir::SideEffects::Resource for modelling operations which add debugging information
7171
def DebuggingResource : Resource<"::fir::DebuggingResource">;
7272

73+
def fir_LowerBoundModifierAttribute : I32EnumAttr<
74+
"LowerBoundModifierAttribute",
75+
"Describes how to modify lower bounds",
76+
[
77+
I32EnumAttrCase<"Preserve", 0, "preserve">,
78+
I32EnumAttrCase<"SetToOnes", 1, "ones">,
79+
I32EnumAttrCase<"SetToZeroes", 2, "zeroes">,
80+
]> {
81+
let cppNamespace = "::fir";
82+
}
83+
7384
#endif // FIR_DIALECT_FIR_ATTRS

flang/include/flang/Optimizer/Dialect/FIROps.td

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -857,6 +857,43 @@ def fir_ReboxOp : fir_Op<"rebox", [NoMemoryEffect, AttrSizedOperandSegments]> {
857857
let hasVerifier = 1;
858858
}
859859

860+
def fir_ReboxAssumedRankOp : fir_Op<"rebox_assumed_rank",
861+
[DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
862+
let summary = "create an assumed-rank box given another assumed-rank box";
863+
864+
let description = [{
865+
Limited version of fir.rebox for assumed-rank. Only the lower bounds,
866+
attribute, and element type may change.
867+
868+
The input may be a box or a reference to a box, in which case the operation
869+
reads the incoming reference.
870+
Since a fir.shift cannot be built without knowing the rank statically,
871+
lower bound changes are encoded via a LowerBoundModifierAttribute.
872+
Attribute and element type change are encoded in the result type.
873+
Changing the element type is only allowed if the input type is a derived
874+
type that extends the output element type.
875+
876+
Example:
877+
```
878+
fir.rebox_assumed_rank %1 lbs zeroes : (!fir.box<!fir.array<*:f32>>) -> !fir.box<!fir.array<*:f32>>
879+
```
880+
}];
881+
882+
let arguments = (ins
883+
AnyRefOrBoxType:$box,
884+
fir_LowerBoundModifierAttribute:$lbs_modifier
885+
);
886+
887+
let results = (outs BoxOrClassType);
888+
889+
let assemblyFormat = [{
890+
$box `lbs` $lbs_modifier
891+
attr-dict `:` functional-type(operands, results)
892+
}];
893+
894+
let hasVerifier = 1;
895+
}
896+
860897
def fir_EmboxCharOp : fir_Op<"emboxchar", [NoMemoryEffect]> {
861898
let summary = "boxes a given CHARACTER reference and its LEN parameter";
862899

flang/lib/Optimizer/Dialect/FIROps.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2412,6 +2412,52 @@ mlir::LogicalResult fir::ReboxOp::verify() {
24122412
return mlir::success();
24132413
}
24142414

2415+
//===----------------------------------------------------------------------===//
2416+
// ReboxAssumedRankOp
2417+
//===----------------------------------------------------------------------===//
2418+
2419+
static bool areCompatibleAssumedRankElementType(mlir::Type inputEleTy,
2420+
mlir::Type outEleTy) {
2421+
if (inputEleTy == outEleTy)
2422+
return true;
2423+
// Output is unlimited polymorphic -> output dynamic type is the same as input
2424+
// type.
2425+
if (mlir::isa<mlir::NoneType>(outEleTy))
2426+
return true;
2427+
// Output/Input are derived types. Assuming input extends output type, output
2428+
// dynamic type is the output static type, unless output is polymorphic.
2429+
if (mlir::isa<fir::RecordType>(inputEleTy) &&
2430+
mlir::isa<fir::RecordType>(outEleTy))
2431+
return true;
2432+
if (areCompatibleCharacterTypes(inputEleTy, outEleTy))
2433+
return true;
2434+
return false;
2435+
}
2436+
2437+
mlir::LogicalResult fir::ReboxAssumedRankOp::verify() {
2438+
mlir::Type inputType = getBox().getType();
2439+
if (!mlir::isa<fir::BaseBoxType>(inputType) && !fir::isBoxAddress(inputType))
2440+
return emitOpError("input must be a box or box address");
2441+
mlir::Type inputEleTy =
2442+
mlir::cast<fir::BaseBoxType>(fir::unwrapRefType(inputType))
2443+
.unwrapInnerType();
2444+
mlir::Type outEleTy =
2445+
mlir::cast<fir::BaseBoxType>(getType()).unwrapInnerType();
2446+
if (!areCompatibleAssumedRankElementType(inputEleTy, outEleTy))
2447+
return emitOpError("input and output element types are incompatible");
2448+
return mlir::success();
2449+
}
2450+
2451+
void fir::ReboxAssumedRankOp::getEffects(
2452+
llvm::SmallVectorImpl<
2453+
mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
2454+
&effects) {
2455+
mlir::Value inputBox = getBox();
2456+
if (fir::isBoxAddress(inputBox.getType()))
2457+
effects.emplace_back(mlir::MemoryEffects::Read::get(), inputBox,
2458+
mlir::SideEffects::DefaultResource::get());
2459+
}
2460+
24152461
//===----------------------------------------------------------------------===//
24162462
// ResultOp
24172463
//===----------------------------------------------------------------------===//

flang/test/Fir/fir-ops.fir

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -900,3 +900,15 @@ fir.global @t1 {keep_my_attr = "data"} : i32 {
900900
}
901901

902902
// CHECK-LABEL: fir.global @t1 {keep_my_attr = "data"} : i32
903+
904+
func.func @test_rebox_assumed_rank(%arg0: !fir.box<!fir.array<*:f32>> ) {
905+
%1 = fir.rebox_assumed_rank %arg0 lbs ones : (!fir.box<!fir.array<*:f32>>) -> !fir.box<!fir.array<*:f32>>
906+
%2 = fir.rebox_assumed_rank %arg0 lbs zeroes : (!fir.box<!fir.array<*:f32>>) -> !fir.box<!fir.array<*:f32>>
907+
%3 = fir.rebox_assumed_rank %arg0 lbs preserve : (!fir.box<!fir.array<*:f32>>) -> !fir.box<!fir.array<*:f32>>
908+
return
909+
}
910+
// CHECK-LABEL: func.func @test_rebox_assumed_rank(
911+
// CHECK-SAME: %[[A:.*]]: !fir.box<!fir.array<*:f32>>)
912+
// CHECK: fir.rebox_assumed_rank %[[A]] lbs ones : (!fir.box<!fir.array<*:f32>>) -> !fir.box<!fir.array<*:f32>>
913+
// CHECK: fir.rebox_assumed_rank %[[A]] lbs zeroes : (!fir.box<!fir.array<*:f32>>) -> !fir.box<!fir.array<*:f32>>
914+
// CHECK: fir.rebox_assumed_rank %[[A]] lbs preserve : (!fir.box<!fir.array<*:f32>>) -> !fir.box<!fir.array<*:f32>>

flang/test/Fir/invalid.fir

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -978,3 +978,27 @@ func.func @bad_box_offset(%no_addendum : !fir.ref<!fir.box<i32>>) {
978978
%addr1 = fir.box_offset %no_addendum derived_type : (!fir.ref<!fir.box<i32>>) -> !fir.llvm_ptr<!fir.tdesc<!fir.type<none>>>
979979
return
980980
}
981+
982+
// -----
983+
984+
func.func @bad_rebox_assumed_rank_1(%arg0: !fir.ref<!fir.array<*:f32>> ) {
985+
// expected-error@+1{{'fir.rebox_assumed_rank' op input must be a box or box address}}
986+
%1 = fir.rebox_assumed_rank %arg0 lbs ones : (!fir.ref<!fir.array<*:f32>>) -> !fir.box<!fir.array<*:f32>>
987+
return
988+
}
989+
990+
// -----
991+
992+
func.func @bad_rebox_assumed_rank_2(%arg0: !fir.box<!fir.array<*:f32>> ) {
993+
// expected-error@+1{{'fir.rebox_assumed_rank' op result #0 must be box or class, but got '!fir.ref<!fir.box<!fir.array<*:f32>>>'}}
994+
%1 = fir.rebox_assumed_rank %arg0 lbs ones : (!fir.box<!fir.array<*:f32>>) -> !fir.ref<!fir.box<!fir.array<*:f32>>>
995+
return
996+
}
997+
998+
// -----
999+
1000+
func.func @bad_rebox_assumed_rank_3(%arg0: !fir.box<!fir.array<*:f32>> ) {
1001+
// expected-error@+1{{'fir.rebox_assumed_rank' op input and output element types are incompatible}}
1002+
%1 = fir.rebox_assumed_rank %arg0 lbs ones : (!fir.box<!fir.array<*:f32>>) -> !fir.box<!fir.array<*:i32>>
1003+
return
1004+
}

0 commit comments

Comments
 (0)