[flang] lower vector subscripted polymorphic designators (#84778)
A mold argument need to be added to the hlfir.element_addr and set in lowering so that when the hlfir.element_addr need to be turned into an hlfir.elemental operation because the designator must be turned into a value, the mold can be set on the hlfir.elemental to later allocate the temporary according the the dynamic type. This situation happens whenever the vector subscripted polymorphic designator does not appear as an assignment left-hand side, or as an IO-input item. I initially thought retrieving the mold would be tricky if the dynamic type of the designator was set by a part-ref of the right of the vector subscripts ("array(vector)%polymorphic_comp"), but this turned out to be impossible because: 1. A derived type component can be polymorphic only if it has the POINTER or ALLOCATABLE attribute (F2023 C708). 2. Vector-subscripted part are ranked and F2023 C919 prohibits any part-ref on the right of the rank part to have the POINTER or ALLOCATABLE attribute. => If a vector subscripted designator is polymorphic, the vector subscripted part is the rightmost part, and the mold is the base of the vector subscripted part. This makes the retrieval of the mold easy in lowering. The mold argument is always set to be the base of the vector subscripted part when lowering the vector subscripted part, and it is removed at the end of the designator lowering if the designator is not polymorphic. This way there is no need to find back the mold from the inside of the hlfir.element_addr body.
This commit is contained in:
parent
b274b23665
commit
939f038296
@ -1358,7 +1358,9 @@ def hlfir_YieldOp : hlfir_Op<"yield", [Terminator, ParentOneOf<["RegionAssignOp"
|
||||
let assemblyFormat = "$entity attr-dict `:` type($entity) custom<YieldOpCleanup>($cleanup)";
|
||||
}
|
||||
|
||||
def hlfir_ElementalAddrOp : hlfir_Op<"elemental_addr", [Terminator, HasParent<"RegionAssignOp">, RecursiveMemoryEffects, RecursivelySpeculatable, hlfir_ElementalOpInterface]> {
|
||||
def hlfir_ElementalAddrOp : hlfir_Op<"elemental_addr", [Terminator, HasParent<"RegionAssignOp">,
|
||||
RecursiveMemoryEffects, RecursivelySpeculatable, hlfir_ElementalOpInterface,
|
||||
AttrSizedOperandSegments]> {
|
||||
let summary = "Yield the address of a vector subscripted variable inside an hlfir.region_assign";
|
||||
let description = [{
|
||||
Special terminator node for the left-hand side region of an hlfir.region_assign
|
||||
@ -1398,6 +1400,7 @@ def hlfir_ElementalAddrOp : hlfir_Op<"elemental_addr", [Terminator, HasParent<"R
|
||||
|
||||
let arguments = (ins
|
||||
fir_ShapeType:$shape,
|
||||
Optional<AnyPolymorphicObject>:$mold,
|
||||
Variadic<AnyIntegerType>:$typeparams,
|
||||
OptionalAttr<UnitAttr>:$unordered
|
||||
);
|
||||
@ -1406,11 +1409,15 @@ def hlfir_ElementalAddrOp : hlfir_Op<"elemental_addr", [Terminator, HasParent<"R
|
||||
MaxSizedRegion<1>:$cleanup);
|
||||
|
||||
let builders = [
|
||||
OpBuilder<(ins "mlir::Value":$shape, CArg<"bool", "false">:$isUnordered)>
|
||||
OpBuilder<(ins "mlir::Value":$shape,
|
||||
CArg<"mlir::Value", "{}">:$mold,
|
||||
CArg<"mlir::ValueRange", "{}">:$typeparams,
|
||||
CArg<"bool", "false">:$isUnordered)>
|
||||
];
|
||||
|
||||
let assemblyFormat = [{
|
||||
$shape (`typeparams` $typeparams^)? (`unordered` $unordered^)?
|
||||
$shape (`mold` $mold^)? (`typeparams` $typeparams^)?
|
||||
(`unordered` $unordered^)?
|
||||
attr-dict `:` type(operands) $body
|
||||
custom<YieldOpCleanup>($cleanup)}];
|
||||
|
||||
|
@ -761,9 +761,17 @@ private:
|
||||
// of the whole designator (not the ones of the vector subscripted part).
|
||||
// These are not yet known and will be added when finalizing the designator
|
||||
// lowering.
|
||||
auto elementalAddrOp =
|
||||
builder.create<hlfir::ElementalAddrOp>(loc, shape,
|
||||
/*isUnordered=*/true);
|
||||
// The resulting designator may be polymorphic, in which case the resulting
|
||||
// type is the base of the vector subscripted part because
|
||||
// allocatable/pointer components cannot be referenced after a vector
|
||||
// subscripted part. Set the mold to the current base. It will be erased if
|
||||
// the resulting designator is not polymorphic.
|
||||
assert(partInfo.base.has_value() &&
|
||||
"vector subscripted part must have a base");
|
||||
mlir::Value mold = *partInfo.base;
|
||||
auto elementalAddrOp = builder.create<hlfir::ElementalAddrOp>(
|
||||
loc, shape, mold, mlir::ValueRange{},
|
||||
/*isUnordered=*/true);
|
||||
setVectorSubscriptElementAddrOp(elementalAddrOp);
|
||||
builder.setInsertionPointToEnd(&elementalAddrOp.getBody().front());
|
||||
mlir::Region::BlockArgListType indices = elementalAddrOp.getIndices();
|
||||
@ -804,15 +812,8 @@ private:
|
||||
hlfir::EntityWithAttributes elementAddr) {
|
||||
fir::FirOpBuilder &builder = getBuilder();
|
||||
builder.setInsertionPointToEnd(&elementalAddrOp.getBody().front());
|
||||
// For polymorphic entities, it will be needed to add a mold on the
|
||||
// hlfir.elemental so that we are able to create temporary storage
|
||||
// for it using the dynamic type. It seems that a reference to the mold
|
||||
// entity can be created by evaluating the hlfir.elemental_addr
|
||||
// for a single index. The evaluation should be legal as long as
|
||||
// the hlfir.elemental_addr has no side effects, otherwise,
|
||||
// it is not clear how to get the mold reference.
|
||||
if (elementAddr.isPolymorphic())
|
||||
TODO(loc, "vector subscripted polymorphic entity in HLFIR");
|
||||
if (!elementAddr.isPolymorphic())
|
||||
elementalAddrOp.getMoldMutable().clear();
|
||||
builder.create<hlfir::YieldOp>(loc, elementAddr);
|
||||
builder.setInsertionPointAfter(elementalAddrOp);
|
||||
}
|
||||
@ -929,6 +930,8 @@ HlfirDesignatorBuilder::convertVectorSubscriptedExprToElementalAddr(
|
||||
hlfir::genLengthParameters(loc, builder, elementAddrEntity, lengths);
|
||||
if (!lengths.empty())
|
||||
elementalAddrOp.getTypeparamsMutable().assign(lengths);
|
||||
if (!elementAddrEntity.isPolymorphic())
|
||||
elementalAddrOp.getMoldMutable().clear();
|
||||
// Create the hlfir.yield terminator inside the hlfir.elemental_body.
|
||||
builder.setInsertionPointToEnd(&elementalAddrOp.getBody().front());
|
||||
builder.create<hlfir::YieldOp>(loc, elementAddrEntity);
|
||||
|
@ -1036,9 +1036,9 @@ hlfir::cloneToElementalOp(mlir::Location loc, fir::FirOpBuilder &builder,
|
||||
return hlfir::loadTrivialScalar(l, b, newAddr);
|
||||
};
|
||||
mlir::Type elementType = scalarAddress.getFortranElementType();
|
||||
return hlfir::genElementalOp(loc, builder, elementType,
|
||||
elementalAddrOp.getShape(), typeParams,
|
||||
genKernel, !elementalAddrOp.isOrdered());
|
||||
return hlfir::genElementalOp(
|
||||
loc, builder, elementType, elementalAddrOp.getShape(), typeParams,
|
||||
genKernel, !elementalAddrOp.isOrdered(), elementalAddrOp.getMold());
|
||||
}
|
||||
|
||||
bool hlfir::elementalOpMustProduceTemp(hlfir::ElementalOp elemental) {
|
||||
|
@ -1406,31 +1406,43 @@ void hlfir::AsExprOp::getEffects(
|
||||
// ElementalOp
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// Common builder for ElementalOp and ElementalAddrOp to add the arguments and
|
||||
/// create the elemental body. Result and clean-up body must be handled in
|
||||
/// specific builders.
|
||||
template <typename Op>
|
||||
static void buildElemental(mlir::OpBuilder &builder,
|
||||
mlir::OperationState &odsState, mlir::Value shape,
|
||||
mlir::Value mold, mlir::ValueRange typeparams,
|
||||
bool isUnordered) {
|
||||
odsState.addOperands(shape);
|
||||
if (mold)
|
||||
odsState.addOperands(mold);
|
||||
odsState.addOperands(typeparams);
|
||||
odsState.addAttribute(
|
||||
Op::getOperandSegmentSizesAttrName(odsState.name),
|
||||
builder.getDenseI32ArrayAttr({/*shape=*/1, (mold ? 1 : 0),
|
||||
static_cast<int32_t>(typeparams.size())}));
|
||||
if (isUnordered)
|
||||
odsState.addAttribute(Op::getUnorderedAttrName(odsState.name),
|
||||
isUnordered ? builder.getUnitAttr() : nullptr);
|
||||
mlir::Region *bodyRegion = odsState.addRegion();
|
||||
bodyRegion->push_back(new mlir::Block{});
|
||||
if (auto shapeType = shape.getType().dyn_cast<fir::ShapeType>()) {
|
||||
unsigned dim = shapeType.getRank();
|
||||
mlir::Type indexType = builder.getIndexType();
|
||||
for (unsigned d = 0; d < dim; ++d)
|
||||
bodyRegion->front().addArgument(indexType, odsState.location);
|
||||
}
|
||||
}
|
||||
|
||||
void hlfir::ElementalOp::build(mlir::OpBuilder &builder,
|
||||
mlir::OperationState &odsState,
|
||||
mlir::Type resultType, mlir::Value shape,
|
||||
mlir::Value mold, mlir::ValueRange typeparams,
|
||||
bool isUnordered) {
|
||||
odsState.addOperands(shape);
|
||||
if (mold)
|
||||
odsState.addOperands(mold);
|
||||
odsState.addOperands(typeparams);
|
||||
odsState.addTypes(resultType);
|
||||
odsState.addAttribute(
|
||||
getOperandSegmentSizesAttrName(odsState.name),
|
||||
builder.getDenseI32ArrayAttr({/*shape=*/1, (mold ? 1 : 0),
|
||||
static_cast<int32_t>(typeparams.size())}));
|
||||
if (isUnordered)
|
||||
odsState.addAttribute(getUnorderedAttrName(odsState.name),
|
||||
isUnordered ? builder.getUnitAttr() : nullptr);
|
||||
mlir::Region *bodyRegion = odsState.addRegion();
|
||||
bodyRegion->push_back(new mlir::Block{});
|
||||
if (auto exprType = resultType.dyn_cast<hlfir::ExprType>()) {
|
||||
unsigned dim = exprType.getRank();
|
||||
mlir::Type indexType = builder.getIndexType();
|
||||
for (unsigned d = 0; d < dim; ++d)
|
||||
bodyRegion->front().addArgument(indexType, odsState.location);
|
||||
}
|
||||
buildElemental<hlfir::ElementalOp>(builder, odsState, shape, mold, typeparams,
|
||||
isUnordered);
|
||||
}
|
||||
|
||||
mlir::Value hlfir::ElementalOp::getElementEntity() {
|
||||
@ -1681,19 +1693,11 @@ static void printYieldOpCleanup(mlir::OpAsmPrinter &p, YieldOp yieldOp,
|
||||
|
||||
void hlfir::ElementalAddrOp::build(mlir::OpBuilder &builder,
|
||||
mlir::OperationState &odsState,
|
||||
mlir::Value shape, bool isUnordered) {
|
||||
odsState.addOperands(shape);
|
||||
if (isUnordered)
|
||||
odsState.addAttribute(getUnorderedAttrName(odsState.name),
|
||||
isUnordered ? builder.getUnitAttr() : nullptr);
|
||||
mlir::Region *bodyRegion = odsState.addRegion();
|
||||
bodyRegion->push_back(new mlir::Block{});
|
||||
if (auto shapeType = shape.getType().dyn_cast<fir::ShapeType>()) {
|
||||
unsigned dim = shapeType.getRank();
|
||||
mlir::Type indexType = builder.getIndexType();
|
||||
for (unsigned d = 0; d < dim; ++d)
|
||||
bodyRegion->front().addArgument(indexType, odsState.location);
|
||||
}
|
||||
mlir::Value shape, mlir::Value mold,
|
||||
mlir::ValueRange typeparams,
|
||||
bool isUnordered) {
|
||||
buildElemental<hlfir::ElementalAddrOp>(builder, odsState, shape, mold,
|
||||
typeparams, isUnordered);
|
||||
// Push cleanUp region.
|
||||
odsState.addRegion();
|
||||
}
|
||||
|
@ -114,3 +114,45 @@ func.func @unordered() {
|
||||
// CHECK: }
|
||||
// CHECK: return
|
||||
// CHECK: }
|
||||
|
||||
// "X(VECTOR) = Y" with polymorphic X and Y and user defined assignment.
|
||||
func.func @test_mold(%x: !fir.class<!fir.array<?x!fir.type<t>>>, %y: !fir.class<!fir.array<?x!fir.type<t>>>, %vector: !fir.box<!fir.array<?xi64>>) {
|
||||
hlfir.region_assign {
|
||||
hlfir.yield %y : !fir.class<!fir.array<?x!fir.type<t>>>
|
||||
} to {
|
||||
%c0 = arith.constant 0 : index
|
||||
%0:3 = fir.box_dims %vector, %c0 : (!fir.box<!fir.array<?xi64>>, index) -> (index, index, index)
|
||||
%1 = fir.shape %0#1 : (index) -> !fir.shape<1>
|
||||
hlfir.elemental_addr %1 mold %x unordered : !fir.shape<1>, !fir.class<!fir.array<?x!fir.type<t>>> {
|
||||
^bb0(%arg3: index):
|
||||
%2 = hlfir.designate %vector (%arg3) : (!fir.box<!fir.array<?xi64>>, index) -> !fir.ref<i64>
|
||||
%3 = fir.load %2 : !fir.ref<i64>
|
||||
%4 = hlfir.designate %x (%3) : (!fir.class<!fir.array<?x!fir.type<t>>>, i64) -> !fir.class<!fir.type<t>>
|
||||
hlfir.yield %4 : !fir.class<!fir.type<t>>
|
||||
}
|
||||
} user_defined_assign (%arg3: !fir.class<!fir.type<t>>) to (%arg4: !fir.class<!fir.type<t>>) {
|
||||
fir.call @user_def_assign(%arg4, %arg3) : (!fir.class<!fir.type<t>>, !fir.class<!fir.type<t>>) -> ()
|
||||
}
|
||||
return
|
||||
}
|
||||
func.func private @user_def_assign(!fir.class<!fir.type<t>>, !fir.class<!fir.type<t>>)
|
||||
// CHECK-LABEL: func.func @test_mold(
|
||||
// CHECK-SAME: %[[VAL_0:[^:]*]]: !fir.class<!fir.array<?x!fir.type<t>>>,
|
||||
// CHECK-SAME: %[[VAL_1:.*]]: !fir.class<!fir.array<?x!fir.type<t>>>,
|
||||
// CHECK-SAME: %[[VAL_2:.*]]: !fir.box<!fir.array<?xi64>>) {
|
||||
// CHECK: hlfir.region_assign {
|
||||
// CHECK: hlfir.yield %[[VAL_1]] : !fir.class<!fir.array<?x!fir.type<t>>>
|
||||
// CHECK: } to {
|
||||
// CHECK: %[[VAL_3:.*]] = arith.constant 0 : index
|
||||
// CHECK: %[[VAL_4:.*]]:3 = fir.box_dims %[[VAL_2]], %[[VAL_3]] : (!fir.box<!fir.array<?xi64>>, index) -> (index, index, index)
|
||||
// CHECK: %[[VAL_5:.*]] = fir.shape %[[VAL_4]]#1 : (index) -> !fir.shape<1>
|
||||
// CHECK: hlfir.elemental_addr %[[VAL_5]] mold %[[VAL_0]] unordered : !fir.shape<1>, !fir.class<!fir.array<?x!fir.type<t>>> {
|
||||
// CHECK: ^bb0(%[[VAL_6:.*]]: index):
|
||||
// CHECK: %[[VAL_7:.*]] = hlfir.designate %[[VAL_2]] (%[[VAL_6]]) : (!fir.box<!fir.array<?xi64>>, index) -> !fir.ref<i64>
|
||||
// CHECK: %[[VAL_8:.*]] = fir.load %[[VAL_7]] : !fir.ref<i64>
|
||||
// CHECK: %[[VAL_9:.*]] = hlfir.designate %[[VAL_0]] (%[[VAL_8]]) : (!fir.class<!fir.array<?x!fir.type<t>>>, i64) -> !fir.class<!fir.type<t>>
|
||||
// CHECK: hlfir.yield %[[VAL_9]] : !fir.class<!fir.type<t>>
|
||||
// CHECK: }
|
||||
// CHECK: } user_defined_assign (%[[VAL_10:.*]]: !fir.class<!fir.type<t>>) to (%[[VAL_11:.*]]: !fir.class<!fir.type<t>>) {
|
||||
// CHECK: fir.call @user_def_assign(%[[VAL_11]], %[[VAL_10]]) : (!fir.class<!fir.type<t>>, !fir.class<!fir.type<t>>) -> ()
|
||||
// CHECK: }
|
||||
|
@ -1,6 +1,6 @@
|
||||
! Test lowering of vector subscript designators outside of the
|
||||
! assignment left-and side and input IO context.
|
||||
! RUN: bbc -emit-hlfir -o - -I nw %s 2>&1 | FileCheck %s
|
||||
! RUN: bbc -emit-hlfir -o - -I nw %s --polymorphic-type 2>&1 | FileCheck %s
|
||||
|
||||
subroutine foo(x, y)
|
||||
integer :: x(100)
|
||||
@ -182,3 +182,37 @@ end subroutine
|
||||
! CHECK: %[[VAL_27:.*]] = hlfir.designate %[[VAL_4]]#0 (%[[VAL_26]]) substr %[[VAL_15]], %[[VAL_16]] typeparams %[[VAL_22]] : (!fir.box<!fir.array<?x!fir.char<1,?>>>, i64, index, index, index) -> !fir.boxchar<1>
|
||||
! CHECK: hlfir.yield_element %[[VAL_27]] : !fir.boxchar<1>
|
||||
! CHECK: }
|
||||
|
||||
subroutine test_passing_subscripted_poly(x, vector)
|
||||
interface
|
||||
subroutine do_something(x)
|
||||
class(*) :: x(:)
|
||||
end subroutine
|
||||
end interface
|
||||
class(*) :: x(:, :)
|
||||
integer(8) :: vector(:)
|
||||
call do_something(x(314, vector))
|
||||
end subroutine
|
||||
! CHECK-LABEL: func.func @_QPtest_passing_subscripted_poly(
|
||||
! CHECK-SAME: %[[VAL_0:.*]]: !fir.class<!fir.array<?x?xnone>>
|
||||
! CHECK-SAME: %[[VAL_1:.*]]: !fir.box<!fir.array<?xi64>>
|
||||
! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_1]] {uniq_name = "_QFtest_passing_subscripted_polyEvector"} : (!fir.box<!fir.array<?xi64>>) -> (!fir.box<!fir.array<?xi64>>, !fir.box<!fir.array<?xi64>>)
|
||||
! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFtest_passing_subscripted_polyEx"} : (!fir.class<!fir.array<?x?xnone>>) -> (!fir.class<!fir.array<?x?xnone>>, !fir.class<!fir.array<?x?xnone>>)
|
||||
! CHECK: %[[VAL_4:.*]] = arith.constant 314 : index
|
||||
! CHECK: %[[VAL_5:.*]] = arith.constant 0 : index
|
||||
! CHECK: %[[VAL_6:.*]]:3 = fir.box_dims %[[VAL_2]]#0, %[[VAL_5]] : (!fir.box<!fir.array<?xi64>>, index) -> (index, index, index)
|
||||
! CHECK: %[[VAL_7:.*]] = fir.shape %[[VAL_6]]#1 : (index) -> !fir.shape<1>
|
||||
! CHECK: %[[VAL_8:.*]] = hlfir.elemental %[[VAL_7]] mold %[[VAL_3]]#0 unordered : (!fir.shape<1>, !fir.class<!fir.array<?x?xnone>>) -> !hlfir.expr<?xnone?> {
|
||||
! CHECK: ^bb0(%[[VAL_9:.*]]: index):
|
||||
! CHECK: %[[VAL_10:.*]] = hlfir.designate %[[VAL_2]]#0 (%[[VAL_9]]) : (!fir.box<!fir.array<?xi64>>, index) -> !fir.ref<i64>
|
||||
! CHECK: %[[VAL_11:.*]] = fir.load %[[VAL_10]] : !fir.ref<i64>
|
||||
! CHECK: %[[VAL_12:.*]] = hlfir.designate %[[VAL_3]]#0 (%[[VAL_4]], %[[VAL_11]]) : (!fir.class<!fir.array<?x?xnone>>, index, i64) -> !fir.class<none>
|
||||
! CHECK: hlfir.yield_element %[[VAL_12]] : !fir.class<none>
|
||||
! CHECK: }
|
||||
! CHECK: %[[VAL_13:.*]]:3 = hlfir.associate %[[VAL_8]](%[[VAL_7]]) {adapt.valuebyref} : (!hlfir.expr<?xnone?>, !fir.shape<1>) -> (!fir.class<!fir.heap<!fir.array<?xnone>>>, !fir.class<!fir.heap<!fir.array<?xnone>>>, i1)
|
||||
! CHECK: %[[VAL_14:.*]] = fir.rebox %[[VAL_13]]#0 : (!fir.class<!fir.heap<!fir.array<?xnone>>>) -> !fir.class<!fir.array<?xnone>>
|
||||
! CHECK: fir.call @_QPdo_something(%[[VAL_14]]) fastmath<contract> : (!fir.class<!fir.array<?xnone>>) -> ()
|
||||
! CHECK: hlfir.end_associate %[[VAL_13]]#0, %[[VAL_13]]#2 : !fir.class<!fir.heap<!fir.array<?xnone>>>, i1
|
||||
! CHECK: hlfir.destroy %[[VAL_8]] : !hlfir.expr<?xnone?>
|
||||
! CHECK: return
|
||||
! CHECK: }
|
||||
|
Loading…
x
Reference in New Issue
Block a user