Skip to content

Commit

Permalink
[flang] Add conditional rebox when passing fir.box to optional fir.class
Browse files Browse the repository at this point in the history
When a `!fir.box<>` is passed as an actual argument to an optional
`!fir.class<>` dummy it needs a `fir.rebox` in order to propagate
the dynamic type information.
The `fir.rebox` needs to happen only on present argument.

Reviewed By: jeanPerier

Differential Revision: https://reviews.llvm.org/D142340
  • Loading branch information
clementval committed Jan 23, 2023
1 parent 602e1cb commit 959caaa
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 6 deletions.
35 changes: 34 additions & 1 deletion flang/lib/Lower/ConvertExpr.cpp
Expand Up @@ -2709,11 +2709,16 @@ class ScalarExprLowering {
// select op requires the same type for its two argument, convert
// !fir.box<none> to !fir.class<none> when the argument is
// polymorphic.
if (fir::isBoxNone(box.getType()) && fir::isPolymorphicType(argTy))
if (fir::isBoxNone(box.getType()) && fir::isPolymorphicType(argTy)) {
box = builder.createConvert(
loc,
fir::ClassType::get(mlir::NoneType::get(builder.getContext())),
box);
} else if (box.getType().isa<fir::BoxType>() &&
fir::isPolymorphicType(argTy)) {
box = builder.create<fir::ReboxOp>(loc, argTy, box, mlir::Value{},
/*slice=*/mlir::Value{});
}

// Need the box types to be exactly similar for the selectOp.
mlir::Value convertedBox = builder.createConvert(loc, argTy, box);
Expand All @@ -2728,6 +2733,34 @@ class ScalarExprLowering {
fir::isPolymorphicType(argTy))
: builder.createBox(getLoc(), genTempExtAddr(*expr),
fir::isPolymorphicType(argTy));

if (box.getType().isa<fir::BoxType>() &&
fir::isPolymorphicType(argTy)) {
// Rebox can only be performed on a present argument.
if (arg.isOptional()) {
mlir::Value isPresent = genActualIsPresentTest(builder, loc, box);
box =
builder
.genIfOp(loc, {argTy}, isPresent, /*withElseRegion=*/true)
.genThen([&]() {
auto rebox = builder
.create<fir::ReboxOp>(
loc, argTy, box, mlir::Value{},
/*slice=*/mlir::Value{})
.getResult();
builder.create<fir::ResultOp>(loc, rebox);
})
.genElse([&]() {
auto absent = builder.create<fir::AbsentOp>(loc, argTy)
.getResult();
builder.create<fir::ResultOp>(loc, absent);
})
.getResults()[0];
} else {
box = builder.create<fir::ReboxOp>(loc, argTy, box, mlir::Value{},
/*slice=*/mlir::Value{});
}
}
caller.placeInput(arg, box);
}
} else if (arg.passBy == PassBy::AddressAndLength) {
Expand Down
20 changes: 15 additions & 5 deletions flang/lib/Optimizer/CodeGen/CodeGen.cpp
Expand Up @@ -1346,6 +1346,10 @@ struct EmboxCommonConversion : public FIROpConversion<OP> {
static bool isDerivedType(fir::BaseBoxType boxTy) {
return static_cast<bool>(unwrapIfDerived(boxTy));
}
static bool hasAddendum(fir::BaseBoxType boxTy) {
return static_cast<bool>(unwrapIfDerived(boxTy)) ||
fir::isUnlimitedPolymorphicType(boxTy);
}

// Get the element size and CFI type code of the boxed value.
std::tuple<mlir::Value, mlir::Value> getSizeAndTypeCode(
Expand Down Expand Up @@ -1647,24 +1651,30 @@ struct EmboxCommonConversion : public FIROpConversion<OP> {
mlir::Value typeDesc = {}) const {
auto loc = box.getLoc();
auto boxTy = box.getType().dyn_cast<fir::BaseBoxType>();
auto inputBoxTy = box.getBox().getType().dyn_cast<fir::BaseBoxType>();
llvm::SmallVector<mlir::Value> typeparams = lenParams;
if (!box.getSubstr().empty() && fir::hasDynamicSize(boxTy.getEleTy()))
typeparams.push_back(box.getSubstr()[1]);

auto [eleSize, cfiTy] =
getSizeAndTypeCode(loc, rewriter, boxTy.getEleTy(), typeparams);

// Reboxing a polymorphic entities. eleSize and type code need to
// Reboxing to a polymorphic entity. eleSize and type code need to
// be retrived from the initial box and propagated to the new box.
if (fir::isPolymorphicType(boxTy) &&
fir::isPolymorphicType(box.getBox().getType())) {
// If the initial box has an addendum, the type desc must be propagated as
// well.
if (fir::isPolymorphicType(boxTy)) {
mlir::Type idxTy = this->lowerTy().indexType();
eleSize =
this->getElementSizeFromBox(loc, idxTy, boxTy, loweredBox, rewriter);
cfiTy = this->getValueFromBox(loc, boxTy, loweredBox, cfiTy.getType(),
rewriter, kTypePosInBox);
typeDesc = this->loadTypeDescAddress(loc, box.getBox().getType(),
loweredBox, rewriter);
// TODO: For initial box that are unlimited polymorphic entities, this
// code must be made conditional because unlimited polymorphic entities
// with intrinsic type spec does not have addendum.
if (hasAddendum(inputBoxTy))
typeDesc = this->loadTypeDescAddress(loc, box.getBox().getType(),
loweredBox, rewriter);
}

auto mod = box->template getParentOfType<mlir::ModuleOp>();
Expand Down
35 changes: 35 additions & 0 deletions flang/test/Lower/polymorphic.f90
Expand Up @@ -789,6 +789,41 @@ subroutine test_call_with_null()
! CHECK: %[[ARG:.*]] = arith.select %[[IS_ALLOCATED_OR_ASSOCIATED]], %[[CLASS_NONE]], %[[ABSENT]] : !fir.class<none>
! CHECK: fir.call @_QMpolymorphic_testPsub_with_poly_optional(%[[ARG]]) {{.*}} : (!fir.class<none>) -> ()

subroutine sub_with_poly_array_optional(a)
class(*), optional :: a(:)
end subroutine

subroutine test_call_with_pointer_to_optional()
real, pointer :: p(:)
call sub_with_poly_array_optional(p)
end subroutine

! CHECK-LABEL: func.func @_QMpolymorphic_testPtest_call_with_pointer_to_optional() {
! CHECK: %[[P:.*]] = fir.alloca !fir.box<!fir.ptr<!fir.array<?xf32>>> {bindc_name = "p", uniq_name = "_QMpolymorphic_testFtest_call_with_pointer_to_optionalEp"}
! CHECK: %[[IS_ALLOCATED_OR_ASSOCIATED:.*]] = arith.cmpi ne
! CHECK: %[[ABSENT:.*]] = fir.absent !fir.class<!fir.array<?xnone>>
! CHECK: %[[LOAD_P:.*]] = fir.load %[[P]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>
! CHECK: %[[REBOX:.*]] = fir.rebox %[[LOAD_P]] : (!fir.box<!fir.ptr<!fir.array<?xf32>>>) -> !fir.class<!fir.array<?xnone>>
! CHECK: %[[ARG:.*]] = arith.select %[[IS_ALLOCATED_OR_ASSOCIATED]], %[[REBOX]], %[[ABSENT]] : !fir.class<!fir.array<?xnone>>
! CHECK: fir.call @_QMpolymorphic_testPsub_with_poly_array_optional(%[[ARG]]) {{.*}} : (!fir.class<!fir.array<?xnone>>) -> ()

subroutine sub_with_real_pointer_optional(p)
real, optional :: p(:)
call sub_with_poly_array_optional(p)
end subroutine

! CHECK-LABEL: func.func @_QMpolymorphic_testPsub_with_real_pointer_optional(
! CHECK-SAME: %[[P:.*]]: !fir.box<!fir.array<?xf32>> {fir.bindc_name = "p", fir.optional}) {
! CHECK: %[[IS_PRESENT:.*]] = fir.is_present %[[P]] : (!fir.box<!fir.array<?xf32>>) -> i1
! CHECK: %[[BOX:.*]] = fir.if %[[IS_PRESENT]] -> (!fir.class<!fir.array<?xnone>>) {
! CHECK: %[[REBOX:.*]] = fir.rebox %[[P]] : (!fir.box<!fir.array<?xf32>>) -> !fir.class<!fir.array<?xnone>>
! CHECK: fir.result %[[REBOX]] : !fir.class<!fir.array<?xnone>>
! CHECK: } else {
! CHECK: %[[ABSENT:.*]] = fir.absent !fir.class<!fir.array<?xnone>>
! CHECK: fir.result %[[ABSENT]] : !fir.class<!fir.array<?xnone>>
! CHECK: }
! CHECK: fir.call @_QMpolymorphic_testPsub_with_poly_array_optional(%[[BOX]]) {{.*}} : (!fir.class<!fir.array<?xnone>>) -> ()

end module

program test
Expand Down

0 comments on commit 959caaa

Please sign in to comment.