Skip to content

Commit

Permalink
[flang][hlfir] Lower ordered elemental subroutine calls.
Browse files Browse the repository at this point in the history
This patch sets `unordered` `fir.do_loop` attribute during lowering
of elemental subroutine calls to HLFIR, when it is safe to do so.
Proper handling of `hlfir.elemental` will be done in a separate patch.

Reviewed By: jeanPerier, tblah

Differential Revision: https://reviews.llvm.org/D154031
  • Loading branch information
vzakhari committed Jun 29, 2023
1 parent 2348902 commit 5983b8b
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 17 deletions.
9 changes: 6 additions & 3 deletions flang/include/flang/Optimizer/Builder/HLFIRTools.h
Original file line number Diff line number Diff line change
Expand Up @@ -385,11 +385,14 @@ struct LoopNest {
};

/// Generate a fir.do_loop nest looping from 1 to extents[i].
/// \p isUnordered specifies whether the loops in the loop nest
/// are unordered.
LoopNest genLoopNest(mlir::Location loc, fir::FirOpBuilder &builder,
mlir::ValueRange extents);
mlir::ValueRange extents, bool isUnordered = false);
inline LoopNest genLoopNest(mlir::Location loc, fir::FirOpBuilder &builder,
mlir::Value shape) {
return genLoopNest(loc, builder, getIndexExtents(loc, builder, shape));
mlir::Value shape, bool isUnordered = false) {
return genLoopNest(loc, builder, getIndexExtents(loc, builder, shape),
isUnordered);
}

/// Inline the body of an hlfir.elemental at the current insertion point
Expand Down
7 changes: 4 additions & 3 deletions flang/lib/Lower/ConvertCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1593,13 +1593,12 @@ class ElementalCallBuilder {
}
assert(shape &&
"elemental array calls must have at least one array arguments");
if (mustBeOrdered)
TODO(loc, "ordered elemental calls in HLFIR");
// Push a new local scope so that any temps made inside the elemental
// iterations are cleaned up inside the iterations.
if (!callContext.resultType) {
// Subroutine case. Generate call inside loop nest.
hlfir::LoopNest loopNest = hlfir::genLoopNest(loc, builder, shape);
hlfir::LoopNest loopNest =
hlfir::genLoopNest(loc, builder, shape, !mustBeOrdered);
mlir::ValueRange oneBasedIndices = loopNest.oneBasedIndices;
auto insPt = builder.saveInsertionPoint();
builder.setInsertionPointToStart(loopNest.innerLoop.getBody());
Expand All @@ -1613,6 +1612,8 @@ class ElementalCallBuilder {
return std::nullopt;
}
// Function case: generate call inside hlfir.elemental
if (mustBeOrdered)
TODO(loc, "ordered elemental calls in HLFIR");
mlir::Type elementType =
hlfir::getFortranElementType(*callContext.resultType);
// Get result length parameters.
Expand Down
5 changes: 3 additions & 2 deletions flang/lib/Optimizer/Builder/HLFIRTools.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -807,7 +807,7 @@ mlir::Value hlfir::inlineElementalOp(

hlfir::LoopNest hlfir::genLoopNest(mlir::Location loc,
fir::FirOpBuilder &builder,
mlir::ValueRange extents) {
mlir::ValueRange extents, bool isUnordered) {
hlfir::LoopNest loopNest;
assert(!extents.empty() && "must have at least one extent");
auto insPt = builder.saveInsertionPoint();
Expand All @@ -818,7 +818,8 @@ hlfir::LoopNest hlfir::genLoopNest(mlir::Location loc,
unsigned dim = extents.size() - 1;
for (auto extent : llvm::reverse(extents)) {
auto ub = builder.createConvert(loc, indexType, extent);
loopNest.innerLoop = builder.create<fir::DoLoopOp>(loc, one, ub, one);
loopNest.innerLoop =
builder.create<fir::DoLoopOp>(loc, one, ub, one, isUnordered);
builder.setInsertionPointToStart(loopNest.innerLoop.getBody());
// Reverse the indices so they are in column-major order.
loopNest.oneBasedIndices[dim--] = loopNest.innerLoop.getInductionVar();
Expand Down
8 changes: 4 additions & 4 deletions flang/test/HLFIR/extents-of-shape-of.f90
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ elemental subroutine elem_sub(x)
! CHECK-HLFIR-NEXT: %[[EXT0:.*]] = arith.constant 2 : index
! CHECK-HLFIR-NEXT: %[[EXT1:.*]] = hlfir.get_extent %[[SHAPE]] {dim = 1 : index} : (!fir.shape<2>) -> index
! CHECK-HLFIR-NEXT: %[[C1:.*]] = arith.constant 1 : index
! CHECK-HLFIR-NEXT: fir.do_loop %[[ARG2:.*]] = %[[C1]] to %[[EXT1]] step %[[C1]] {
! CHECK-HLFIR-NEXT: fir.do_loop %[[ARG3:.*]] = %[[C1]] to %[[EXT0]] step %[[C1]] {
! CHECK-HLFIR-NEXT: fir.do_loop %[[ARG2:.*]] = %[[C1]] to %[[EXT1]] step %[[C1]] unordered {
! CHECK-HLFIR-NEXT: fir.do_loop %[[ARG3:.*]] = %[[C1]] to %[[EXT0]] step %[[C1]] unordered {
! CHECK-HLFIR-NEXT: %[[ELE:.*]] = hlfir.apply %[[MUL]], %[[ARG3]], %[[ARG2]] : (!hlfir.expr<2x?xf32>, index, index) -> f32
! CHECK-HLFIR-NEXT: %[[ASSOC:.*]]:3 = hlfir.associate %[[ELE]] {uniq_name = "adapt.valuebyref"} : (f32) -> (!fir.ref<f32>, !fir.ref<f32>, i1)
! CHECK-HLFIR-NEXT: fir.call
Expand All @@ -41,8 +41,8 @@ elemental subroutine elem_sub(x)
! CHECK-FIR: %[[SHAPE:.*]] = fir.shape %[[DIMS0]]#1, %[[DIMS1]]#1
! CHECK-FIR-NEXT: %[[C2:.*]] = arith.constant 2 : index
! CHECK-FIR-NEXT: %[[C1_1:.*]] = arith.constant 1 : index
! CHECK-FIR-NEXT: fir.do_loop %[[ARG2:.*]] = %[[C1_1]] to %[[DIMS1]]#1 step %[[C1_1]] {
! CHECK-FIR-NEXT: fir.do_loop %[[ARG3:.*]] = %[[C1_1]] to %[[C2]] step %[[C1_1]] {
! CHECK-FIR-NEXT: fir.do_loop %[[ARG2:.*]] = %[[C1_1]] to %[[DIMS1]]#1 step %[[C1_1]] unordered {
! CHECK-FIR-NEXT: fir.do_loop %[[ARG3:.*]] = %[[C1_1]] to %[[C2]] step %[[C1_1]] unordered {
! ...

! CHECK-ALL: return
Expand Down
6 changes: 3 additions & 3 deletions flang/test/Lower/HLFIR/calls-optional.f90
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ elemental subroutine elem_takes_two_optional(x, y)
! CHECK: %[[VAL_10:.*]]:3 = fir.box_dims %[[VAL_2]]#0, %[[VAL_9]] : (!fir.box<!fir.array<?xf32>>, index) -> (index, index, index)
! CHECK: %[[VAL_11:.*]] = fir.load %[[VAL_3]]#0 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>
! CHECK: %[[VAL_12:.*]] = arith.constant 1 : index
! CHECK: fir.do_loop %[[VAL_13:.*]] = %[[VAL_12]] to %[[VAL_10]]#1 step %[[VAL_12]] {
! CHECK: fir.do_loop %[[VAL_13:.*]] = %[[VAL_12]] to %[[VAL_10]]#1 step %[[VAL_12]] unordered {
! CHECK: %[[VAL_14:.*]] = hlfir.designate %[[VAL_2]]#0 (%[[VAL_13]]) : (!fir.box<!fir.array<?xf32>>, index) -> !fir.ref<f32>
! CHECK: %[[VAL_15:.*]] = fir.if %[[VAL_8]] -> (!fir.ref<f32>) {
! CHECK: %[[VAL_16:.*]] = arith.constant 0 : index
Expand Down Expand Up @@ -109,7 +109,7 @@ elemental subroutine elem_takes_one_optional(x)
! CHECK: %[[VAL_2:.*]] = arith.constant 0 : index
! CHECK: %[[VAL_3:.*]]:3 = fir.box_dims %[[VAL_1]]#0, %[[VAL_2]] : (!fir.box<!fir.array<?xf32>>, index) -> (index, index, index)
! CHECK: %[[VAL_4:.*]] = arith.constant 1 : index
! CHECK: fir.do_loop %[[VAL_5:.*]] = %[[VAL_4]] to %[[VAL_3]]#1 step %[[VAL_4]] {
! CHECK: fir.do_loop %[[VAL_5:.*]] = %[[VAL_4]] to %[[VAL_3]]#1 step %[[VAL_4]] unordered {
! CHECK: %[[VAL_6:.*]] = hlfir.designate %[[VAL_1]]#0 (%[[VAL_5]]) : (!fir.box<!fir.array<?xf32>>, index) -> !fir.ref<f32>
! CHECK: fir.call @_QPelem_takes_one_optional(%[[VAL_6]]) {{.*}} : (!fir.ref<f32>) -> ()
! CHECK: }
Expand All @@ -131,7 +131,7 @@ elemental subroutine elem_optional_poly(x, y)
! CHECK: %[[VAL_5:.*]] = arith.constant 0 : index
! CHECK: %[[VAL_6:.*]]:3 = fir.box_dims %[[VAL_2]]#0, %[[VAL_5]] : (!fir.box<!fir.array<?xf32>>, index) -> (index, index, index)
! CHECK: %[[VAL_7:.*]] = arith.constant 1 : index
! CHECK: fir.do_loop %[[VAL_8:.*]] = %[[VAL_7]] to %[[VAL_6]]#1 step %[[VAL_7]] {
! CHECK: fir.do_loop %[[VAL_8:.*]] = %[[VAL_7]] to %[[VAL_6]]#1 step %[[VAL_7]] unordered {
! CHECK: %[[VAL_9:.*]] = hlfir.designate %[[VAL_2]]#0 (%[[VAL_8]]) : (!fir.box<!fir.array<?xf32>>, index) -> !fir.ref<f32>
! CHECK: %[[VAL_10:.*]] = fir.embox %[[VAL_9]] : (!fir.ref<f32>) -> !fir.box<f32>
! CHECK: %[[VAL_11:.*]] = fir.rebox %[[VAL_10]] : (!fir.box<f32>) -> !fir.class<none>
Expand Down
54 changes: 52 additions & 2 deletions flang/test/Lower/HLFIR/elemental-user-procedure-ref.f90
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,59 @@ elemental subroutine elem_sub(a, b)
! CHECK: %[[VAL_4:.*]] = arith.constant 20 : index
! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_1:.*]](%[[VAL_5:[^)]*]]) {{.*}}y
! CHECK: %[[VAL_7:.*]] = arith.constant 1 : index
! CHECK: fir.do_loop %[[VAL_8:.*]] = %[[VAL_7]] to %[[VAL_4]] step %[[VAL_7]] {
! CHECK: fir.do_loop %[[VAL_9:.*]] = %[[VAL_7]] to %[[VAL_3]] step %[[VAL_7]] {
! CHECK: fir.do_loop %[[VAL_8:.*]] = %[[VAL_7]] to %[[VAL_4]] step %[[VAL_7]] unordered {
! CHECK: fir.do_loop %[[VAL_9:.*]] = %[[VAL_7]] to %[[VAL_3]] step %[[VAL_7]] unordered {
! CHECK: %[[VAL_10:.*]] = hlfir.designate %[[VAL_6]]#0 (%[[VAL_9]], %[[VAL_8]]) : (!fir.ref<!fir.array<10x20xf32>>, index, index) -> !fir.ref<f32>
! CHECK: fir.call @_QPelem_sub(%[[VAL_2]]#1, %[[VAL_10]]) fastmath<contract> : (!fir.ref<i32>, !fir.ref<f32>) -> ()
! CHECK: }
! CHECK: }

subroutine impure_elemental(x)
real :: x(10, 20)
interface
impure elemental subroutine impure_elem(a)
real, intent(in) :: a
end subroutine
end interface
call impure_elem(x)
end subroutine
! CHECK-LABEL: func.func @_QPimpure_elemental(
! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.array<10x20xf32>> {fir.bindc_name = "x"}) {
! CHECK: %[[VAL_1:.*]] = arith.constant 10 : index
! CHECK: %[[VAL_2:.*]] = arith.constant 20 : index
! CHECK: %[[VAL_3:.*]] = fir.shape %[[VAL_1]], %[[VAL_2]] : (index, index) -> !fir.shape<2>
! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[VAL_0]](%[[VAL_3]]) {uniq_name = "_QFimpure_elementalEx"} : (!fir.ref<!fir.array<10x20xf32>>, !fir.shape<2>) -> (!fir.ref<!fir.array<10x20xf32>>, !fir.ref<!fir.array<10x20xf32>>)
! CHECK: %[[VAL_5:.*]] = arith.constant 1 : index
! CHECK: fir.do_loop %[[VAL_6:.*]] = %[[VAL_5]] to %[[VAL_2]] step %[[VAL_5]] {
! CHECK: fir.do_loop %[[VAL_7:.*]] = %[[VAL_5]] to %[[VAL_1]] step %[[VAL_5]] {
! CHECK: %[[VAL_8:.*]] = hlfir.designate %[[VAL_4]]#0 (%[[VAL_7]], %[[VAL_6]]) : (!fir.ref<!fir.array<10x20xf32>>, index, index) -> !fir.ref<f32>
! CHECK: fir.call @_QPimpure_elem(%[[VAL_8]]) fastmath<contract> : (!fir.ref<f32>) -> ()
! CHECK: }
! CHECK: }
! CHECK: return
! CHECK: }

subroutine ordered_elemental(x)
real :: x(10, 20)
interface
elemental subroutine ordered_elem(a)
real, intent(inout) :: a
end subroutine
end interface
call ordered_elem(x)
end subroutine
! CHECK-LABEL: func.func @_QPordered_elemental(
! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.array<10x20xf32>> {fir.bindc_name = "x"}) {
! CHECK: %[[VAL_1:.*]] = arith.constant 10 : index
! CHECK: %[[VAL_2:.*]] = arith.constant 20 : index
! CHECK: %[[VAL_3:.*]] = fir.shape %[[VAL_1]], %[[VAL_2]] : (index, index) -> !fir.shape<2>
! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[VAL_0]](%[[VAL_3]]) {uniq_name = "_QFordered_elementalEx"} : (!fir.ref<!fir.array<10x20xf32>>, !fir.shape<2>) -> (!fir.ref<!fir.array<10x20xf32>>, !fir.ref<!fir.array<10x20xf32>>)
! CHECK: %[[VAL_5:.*]] = arith.constant 1 : index
! CHECK: fir.do_loop %[[VAL_6:.*]] = %[[VAL_5]] to %[[VAL_2]] step %[[VAL_5]] {
! CHECK: fir.do_loop %[[VAL_7:.*]] = %[[VAL_5]] to %[[VAL_1]] step %[[VAL_5]] {
! CHECK: %[[VAL_8:.*]] = hlfir.designate %[[VAL_4]]#0 (%[[VAL_7]], %[[VAL_6]]) : (!fir.ref<!fir.array<10x20xf32>>, index, index) -> !fir.ref<f32>
! CHECK: fir.call @_QPordered_elem(%[[VAL_8]]) fastmath<contract> : (!fir.ref<f32>) -> ()
! CHECK: }
! CHECK: }
! CHECK: return
! CHECK: }

0 comments on commit 5983b8b

Please sign in to comment.