Skip to content

[flang] add fir.rebox_assumed_rank operation #93334

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 2 commits into from
May 27, 2024
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
11 changes: 11 additions & 0 deletions flang/include/flang/Optimizer/Dialect/FIRAttr.td
Original file line number Diff line number Diff line change
Expand Up @@ -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
37 changes: 37 additions & 0 deletions flang/include/flang/Optimizer/Dialect/FIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down
46 changes: 46 additions & 0 deletions flang/lib/Optimizer/Dialect/FIROps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
//===----------------------------------------------------------------------===//
Expand Down
12 changes: 12 additions & 0 deletions flang/test/Fir/fir-ops.fir
Original file line number Diff line number Diff line change
Expand Up @@ -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>>
24 changes: 24 additions & 0 deletions flang/test/Fir/invalid.fir
Original file line number Diff line number Diff line change
Expand Up @@ -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@+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@+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@+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
}
Loading