Skip to content

Commit 939f038

Browse files
authored
[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.
1 parent b274b23 commit 939f038

File tree

6 files changed

+132
-42
lines changed

6 files changed

+132
-42
lines changed

flang/include/flang/Optimizer/HLFIR/HLFIROps.td

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1358,7 +1358,9 @@ def hlfir_YieldOp : hlfir_Op<"yield", [Terminator, ParentOneOf<["RegionAssignOp"
13581358
let assemblyFormat = "$entity attr-dict `:` type($entity) custom<YieldOpCleanup>($cleanup)";
13591359
}
13601360

1361-
def hlfir_ElementalAddrOp : hlfir_Op<"elemental_addr", [Terminator, HasParent<"RegionAssignOp">, RecursiveMemoryEffects, RecursivelySpeculatable, hlfir_ElementalOpInterface]> {
1361+
def hlfir_ElementalAddrOp : hlfir_Op<"elemental_addr", [Terminator, HasParent<"RegionAssignOp">,
1362+
RecursiveMemoryEffects, RecursivelySpeculatable, hlfir_ElementalOpInterface,
1363+
AttrSizedOperandSegments]> {
13621364
let summary = "Yield the address of a vector subscripted variable inside an hlfir.region_assign";
13631365
let description = [{
13641366
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
13981400

13991401
let arguments = (ins
14001402
fir_ShapeType:$shape,
1403+
Optional<AnyPolymorphicObject>:$mold,
14011404
Variadic<AnyIntegerType>:$typeparams,
14021405
OptionalAttr<UnitAttr>:$unordered
14031406
);
@@ -1406,11 +1409,15 @@ def hlfir_ElementalAddrOp : hlfir_Op<"elemental_addr", [Terminator, HasParent<"R
14061409
MaxSizedRegion<1>:$cleanup);
14071410

14081411
let builders = [
1409-
OpBuilder<(ins "mlir::Value":$shape, CArg<"bool", "false">:$isUnordered)>
1412+
OpBuilder<(ins "mlir::Value":$shape,
1413+
CArg<"mlir::Value", "{}">:$mold,
1414+
CArg<"mlir::ValueRange", "{}">:$typeparams,
1415+
CArg<"bool", "false">:$isUnordered)>
14101416
];
14111417

14121418
let assemblyFormat = [{
1413-
$shape (`typeparams` $typeparams^)? (`unordered` $unordered^)?
1419+
$shape (`mold` $mold^)? (`typeparams` $typeparams^)?
1420+
(`unordered` $unordered^)?
14141421
attr-dict `:` type(operands) $body
14151422
custom<YieldOpCleanup>($cleanup)}];
14161423

flang/lib/Lower/ConvertExprToHLFIR.cpp

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -761,9 +761,17 @@ class HlfirDesignatorBuilder {
761761
// of the whole designator (not the ones of the vector subscripted part).
762762
// These are not yet known and will be added when finalizing the designator
763763
// lowering.
764-
auto elementalAddrOp =
765-
builder.create<hlfir::ElementalAddrOp>(loc, shape,
766-
/*isUnordered=*/true);
764+
// The resulting designator may be polymorphic, in which case the resulting
765+
// type is the base of the vector subscripted part because
766+
// allocatable/pointer components cannot be referenced after a vector
767+
// subscripted part. Set the mold to the current base. It will be erased if
768+
// the resulting designator is not polymorphic.
769+
assert(partInfo.base.has_value() &&
770+
"vector subscripted part must have a base");
771+
mlir::Value mold = *partInfo.base;
772+
auto elementalAddrOp = builder.create<hlfir::ElementalAddrOp>(
773+
loc, shape, mold, mlir::ValueRange{},
774+
/*isUnordered=*/true);
767775
setVectorSubscriptElementAddrOp(elementalAddrOp);
768776
builder.setInsertionPointToEnd(&elementalAddrOp.getBody().front());
769777
mlir::Region::BlockArgListType indices = elementalAddrOp.getIndices();
@@ -804,15 +812,8 @@ class HlfirDesignatorBuilder {
804812
hlfir::EntityWithAttributes elementAddr) {
805813
fir::FirOpBuilder &builder = getBuilder();
806814
builder.setInsertionPointToEnd(&elementalAddrOp.getBody().front());
807-
// For polymorphic entities, it will be needed to add a mold on the
808-
// hlfir.elemental so that we are able to create temporary storage
809-
// for it using the dynamic type. It seems that a reference to the mold
810-
// entity can be created by evaluating the hlfir.elemental_addr
811-
// for a single index. The evaluation should be legal as long as
812-
// the hlfir.elemental_addr has no side effects, otherwise,
813-
// it is not clear how to get the mold reference.
814-
if (elementAddr.isPolymorphic())
815-
TODO(loc, "vector subscripted polymorphic entity in HLFIR");
815+
if (!elementAddr.isPolymorphic())
816+
elementalAddrOp.getMoldMutable().clear();
816817
builder.create<hlfir::YieldOp>(loc, elementAddr);
817818
builder.setInsertionPointAfter(elementalAddrOp);
818819
}
@@ -929,6 +930,8 @@ HlfirDesignatorBuilder::convertVectorSubscriptedExprToElementalAddr(
929930
hlfir::genLengthParameters(loc, builder, elementAddrEntity, lengths);
930931
if (!lengths.empty())
931932
elementalAddrOp.getTypeparamsMutable().assign(lengths);
933+
if (!elementAddrEntity.isPolymorphic())
934+
elementalAddrOp.getMoldMutable().clear();
932935
// Create the hlfir.yield terminator inside the hlfir.elemental_body.
933936
builder.setInsertionPointToEnd(&elementalAddrOp.getBody().front());
934937
builder.create<hlfir::YieldOp>(loc, elementAddrEntity);

flang/lib/Optimizer/Builder/HLFIRTools.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1036,9 +1036,9 @@ hlfir::cloneToElementalOp(mlir::Location loc, fir::FirOpBuilder &builder,
10361036
return hlfir::loadTrivialScalar(l, b, newAddr);
10371037
};
10381038
mlir::Type elementType = scalarAddress.getFortranElementType();
1039-
return hlfir::genElementalOp(loc, builder, elementType,
1040-
elementalAddrOp.getShape(), typeParams,
1041-
genKernel, !elementalAddrOp.isOrdered());
1039+
return hlfir::genElementalOp(
1040+
loc, builder, elementType, elementalAddrOp.getShape(), typeParams,
1041+
genKernel, !elementalAddrOp.isOrdered(), elementalAddrOp.getMold());
10421042
}
10431043

10441044
bool hlfir::elementalOpMustProduceTemp(hlfir::ElementalOp elemental) {

flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1406,33 +1406,45 @@ void hlfir::AsExprOp::getEffects(
14061406
// ElementalOp
14071407
//===----------------------------------------------------------------------===//
14081408

1409-
void hlfir::ElementalOp::build(mlir::OpBuilder &builder,
1410-
mlir::OperationState &odsState,
1411-
mlir::Type resultType, mlir::Value shape,
1412-
mlir::Value mold, mlir::ValueRange typeparams,
1413-
bool isUnordered) {
1409+
/// Common builder for ElementalOp and ElementalAddrOp to add the arguments and
1410+
/// create the elemental body. Result and clean-up body must be handled in
1411+
/// specific builders.
1412+
template <typename Op>
1413+
static void buildElemental(mlir::OpBuilder &builder,
1414+
mlir::OperationState &odsState, mlir::Value shape,
1415+
mlir::Value mold, mlir::ValueRange typeparams,
1416+
bool isUnordered) {
14141417
odsState.addOperands(shape);
14151418
if (mold)
14161419
odsState.addOperands(mold);
14171420
odsState.addOperands(typeparams);
1418-
odsState.addTypes(resultType);
14191421
odsState.addAttribute(
1420-
getOperandSegmentSizesAttrName(odsState.name),
1422+
Op::getOperandSegmentSizesAttrName(odsState.name),
14211423
builder.getDenseI32ArrayAttr({/*shape=*/1, (mold ? 1 : 0),
14221424
static_cast<int32_t>(typeparams.size())}));
14231425
if (isUnordered)
1424-
odsState.addAttribute(getUnorderedAttrName(odsState.name),
1426+
odsState.addAttribute(Op::getUnorderedAttrName(odsState.name),
14251427
isUnordered ? builder.getUnitAttr() : nullptr);
14261428
mlir::Region *bodyRegion = odsState.addRegion();
14271429
bodyRegion->push_back(new mlir::Block{});
1428-
if (auto exprType = resultType.dyn_cast<hlfir::ExprType>()) {
1429-
unsigned dim = exprType.getRank();
1430+
if (auto shapeType = shape.getType().dyn_cast<fir::ShapeType>()) {
1431+
unsigned dim = shapeType.getRank();
14301432
mlir::Type indexType = builder.getIndexType();
14311433
for (unsigned d = 0; d < dim; ++d)
14321434
bodyRegion->front().addArgument(indexType, odsState.location);
14331435
}
14341436
}
14351437

1438+
void hlfir::ElementalOp::build(mlir::OpBuilder &builder,
1439+
mlir::OperationState &odsState,
1440+
mlir::Type resultType, mlir::Value shape,
1441+
mlir::Value mold, mlir::ValueRange typeparams,
1442+
bool isUnordered) {
1443+
odsState.addTypes(resultType);
1444+
buildElemental<hlfir::ElementalOp>(builder, odsState, shape, mold, typeparams,
1445+
isUnordered);
1446+
}
1447+
14361448
mlir::Value hlfir::ElementalOp::getElementEntity() {
14371449
return mlir::cast<hlfir::YieldElementOp>(getBody()->back()).getElementValue();
14381450
}
@@ -1681,19 +1693,11 @@ static void printYieldOpCleanup(mlir::OpAsmPrinter &p, YieldOp yieldOp,
16811693

16821694
void hlfir::ElementalAddrOp::build(mlir::OpBuilder &builder,
16831695
mlir::OperationState &odsState,
1684-
mlir::Value shape, bool isUnordered) {
1685-
odsState.addOperands(shape);
1686-
if (isUnordered)
1687-
odsState.addAttribute(getUnorderedAttrName(odsState.name),
1688-
isUnordered ? builder.getUnitAttr() : nullptr);
1689-
mlir::Region *bodyRegion = odsState.addRegion();
1690-
bodyRegion->push_back(new mlir::Block{});
1691-
if (auto shapeType = shape.getType().dyn_cast<fir::ShapeType>()) {
1692-
unsigned dim = shapeType.getRank();
1693-
mlir::Type indexType = builder.getIndexType();
1694-
for (unsigned d = 0; d < dim; ++d)
1695-
bodyRegion->front().addArgument(indexType, odsState.location);
1696-
}
1696+
mlir::Value shape, mlir::Value mold,
1697+
mlir::ValueRange typeparams,
1698+
bool isUnordered) {
1699+
buildElemental<hlfir::ElementalAddrOp>(builder, odsState, shape, mold,
1700+
typeparams, isUnordered);
16971701
// Push cleanUp region.
16981702
odsState.addRegion();
16991703
}

flang/test/HLFIR/element-addr.fir

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,3 +114,45 @@ func.func @unordered() {
114114
// CHECK: }
115115
// CHECK: return
116116
// CHECK: }
117+
118+
// "X(VECTOR) = Y" with polymorphic X and Y and user defined assignment.
119+
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>>) {
120+
hlfir.region_assign {
121+
hlfir.yield %y : !fir.class<!fir.array<?x!fir.type<t>>>
122+
} to {
123+
%c0 = arith.constant 0 : index
124+
%0:3 = fir.box_dims %vector, %c0 : (!fir.box<!fir.array<?xi64>>, index) -> (index, index, index)
125+
%1 = fir.shape %0#1 : (index) -> !fir.shape<1>
126+
hlfir.elemental_addr %1 mold %x unordered : !fir.shape<1>, !fir.class<!fir.array<?x!fir.type<t>>> {
127+
^bb0(%arg3: index):
128+
%2 = hlfir.designate %vector (%arg3) : (!fir.box<!fir.array<?xi64>>, index) -> !fir.ref<i64>
129+
%3 = fir.load %2 : !fir.ref<i64>
130+
%4 = hlfir.designate %x (%3) : (!fir.class<!fir.array<?x!fir.type<t>>>, i64) -> !fir.class<!fir.type<t>>
131+
hlfir.yield %4 : !fir.class<!fir.type<t>>
132+
}
133+
} user_defined_assign (%arg3: !fir.class<!fir.type<t>>) to (%arg4: !fir.class<!fir.type<t>>) {
134+
fir.call @user_def_assign(%arg4, %arg3) : (!fir.class<!fir.type<t>>, !fir.class<!fir.type<t>>) -> ()
135+
}
136+
return
137+
}
138+
func.func private @user_def_assign(!fir.class<!fir.type<t>>, !fir.class<!fir.type<t>>)
139+
// CHECK-LABEL: func.func @test_mold(
140+
// CHECK-SAME: %[[VAL_0:[^:]*]]: !fir.class<!fir.array<?x!fir.type<t>>>,
141+
// CHECK-SAME: %[[VAL_1:.*]]: !fir.class<!fir.array<?x!fir.type<t>>>,
142+
// CHECK-SAME: %[[VAL_2:.*]]: !fir.box<!fir.array<?xi64>>) {
143+
// CHECK: hlfir.region_assign {
144+
// CHECK: hlfir.yield %[[VAL_1]] : !fir.class<!fir.array<?x!fir.type<t>>>
145+
// CHECK: } to {
146+
// CHECK: %[[VAL_3:.*]] = arith.constant 0 : index
147+
// CHECK: %[[VAL_4:.*]]:3 = fir.box_dims %[[VAL_2]], %[[VAL_3]] : (!fir.box<!fir.array<?xi64>>, index) -> (index, index, index)
148+
// CHECK: %[[VAL_5:.*]] = fir.shape %[[VAL_4]]#1 : (index) -> !fir.shape<1>
149+
// CHECK: hlfir.elemental_addr %[[VAL_5]] mold %[[VAL_0]] unordered : !fir.shape<1>, !fir.class<!fir.array<?x!fir.type<t>>> {
150+
// CHECK: ^bb0(%[[VAL_6:.*]]: index):
151+
// CHECK: %[[VAL_7:.*]] = hlfir.designate %[[VAL_2]] (%[[VAL_6]]) : (!fir.box<!fir.array<?xi64>>, index) -> !fir.ref<i64>
152+
// CHECK: %[[VAL_8:.*]] = fir.load %[[VAL_7]] : !fir.ref<i64>
153+
// CHECK: %[[VAL_9:.*]] = hlfir.designate %[[VAL_0]] (%[[VAL_8]]) : (!fir.class<!fir.array<?x!fir.type<t>>>, i64) -> !fir.class<!fir.type<t>>
154+
// CHECK: hlfir.yield %[[VAL_9]] : !fir.class<!fir.type<t>>
155+
// CHECK: }
156+
// CHECK: } user_defined_assign (%[[VAL_10:.*]]: !fir.class<!fir.type<t>>) to (%[[VAL_11:.*]]: !fir.class<!fir.type<t>>) {
157+
// CHECK: fir.call @user_def_assign(%[[VAL_11]], %[[VAL_10]]) : (!fir.class<!fir.type<t>>, !fir.class<!fir.type<t>>) -> ()
158+
// CHECK: }

flang/test/Lower/HLFIR/vector-subscript-as-value.f90

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
! Test lowering of vector subscript designators outside of the
22
! assignment left-and side and input IO context.
3-
! RUN: bbc -emit-hlfir -o - -I nw %s 2>&1 | FileCheck %s
3+
! RUN: bbc -emit-hlfir -o - -I nw %s --polymorphic-type 2>&1 | FileCheck %s
44

55
subroutine foo(x, y)
66
integer :: x(100)
@@ -182,3 +182,37 @@ subroutine substring(c, vector, i, j)
182182
! 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>
183183
! CHECK: hlfir.yield_element %[[VAL_27]] : !fir.boxchar<1>
184184
! CHECK: }
185+
186+
subroutine test_passing_subscripted_poly(x, vector)
187+
interface
188+
subroutine do_something(x)
189+
class(*) :: x(:)
190+
end subroutine
191+
end interface
192+
class(*) :: x(:, :)
193+
integer(8) :: vector(:)
194+
call do_something(x(314, vector))
195+
end subroutine
196+
! CHECK-LABEL: func.func @_QPtest_passing_subscripted_poly(
197+
! CHECK-SAME: %[[VAL_0:.*]]: !fir.class<!fir.array<?x?xnone>>
198+
! CHECK-SAME: %[[VAL_1:.*]]: !fir.box<!fir.array<?xi64>>
199+
! 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>>)
200+
! 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>>)
201+
! CHECK: %[[VAL_4:.*]] = arith.constant 314 : index
202+
! CHECK: %[[VAL_5:.*]] = arith.constant 0 : index
203+
! CHECK: %[[VAL_6:.*]]:3 = fir.box_dims %[[VAL_2]]#0, %[[VAL_5]] : (!fir.box<!fir.array<?xi64>>, index) -> (index, index, index)
204+
! CHECK: %[[VAL_7:.*]] = fir.shape %[[VAL_6]]#1 : (index) -> !fir.shape<1>
205+
! CHECK: %[[VAL_8:.*]] = hlfir.elemental %[[VAL_7]] mold %[[VAL_3]]#0 unordered : (!fir.shape<1>, !fir.class<!fir.array<?x?xnone>>) -> !hlfir.expr<?xnone?> {
206+
! CHECK: ^bb0(%[[VAL_9:.*]]: index):
207+
! CHECK: %[[VAL_10:.*]] = hlfir.designate %[[VAL_2]]#0 (%[[VAL_9]]) : (!fir.box<!fir.array<?xi64>>, index) -> !fir.ref<i64>
208+
! CHECK: %[[VAL_11:.*]] = fir.load %[[VAL_10]] : !fir.ref<i64>
209+
! CHECK: %[[VAL_12:.*]] = hlfir.designate %[[VAL_3]]#0 (%[[VAL_4]], %[[VAL_11]]) : (!fir.class<!fir.array<?x?xnone>>, index, i64) -> !fir.class<none>
210+
! CHECK: hlfir.yield_element %[[VAL_12]] : !fir.class<none>
211+
! CHECK: }
212+
! 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)
213+
! CHECK: %[[VAL_14:.*]] = fir.rebox %[[VAL_13]]#0 : (!fir.class<!fir.heap<!fir.array<?xnone>>>) -> !fir.class<!fir.array<?xnone>>
214+
! CHECK: fir.call @_QPdo_something(%[[VAL_14]]) fastmath<contract> : (!fir.class<!fir.array<?xnone>>) -> ()
215+
! CHECK: hlfir.end_associate %[[VAL_13]]#0, %[[VAL_13]]#2 : !fir.class<!fir.heap<!fir.array<?xnone>>>, i1
216+
! CHECK: hlfir.destroy %[[VAL_8]] : !hlfir.expr<?xnone?>
217+
! CHECK: return
218+
! CHECK: }

0 commit comments

Comments
 (0)