Skip to content

Commit e16f603

Browse files
authored
[flang] Relax conflicts detection in ElementalAssignBufferization. (#143045)
If there is a read-effect operation inside `hlfir.elemental`, there is no reason to block moving it to the assignment point unless there are write-effect operations between the elemental and the assignment. The previous code was disallowing the optimization even if there were only read-effect operations in between. This case is from 465.tonto, though this change does not improve performance at all.
1 parent ede9555 commit e16f603

File tree

2 files changed

+80
-9
lines changed

2 files changed

+80
-9
lines changed

flang/lib/Optimizer/HLFIR/Transforms/OptimizedBufferization.cpp

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -572,13 +572,11 @@ ElementalAssignBufferization::findMatch(hlfir::ElementalOp elemental) {
572572
// hlfir.assign, check there are no effects which make this unsafe
573573

574574
// keep track of any values written to in the elemental, as these can't be
575-
// read from between the elemental and the assignment
575+
// read from or written to between the elemental and the assignment
576+
mlir::SmallVector<mlir::Value, 1> notToBeAccessedBeforeAssign;
576577
// likewise, values read in the elemental cannot be written to between the
577578
// elemental and the assign
578-
mlir::SmallVector<mlir::Value, 1> notToBeAccessedBeforeAssign;
579-
// any accesses to the array between the array and the assignment means it
580-
// would be unsafe to move the elemental to the assignment
581-
notToBeAccessedBeforeAssign.push_back(match.array);
579+
mlir::SmallVector<mlir::Value, 1> notToBeWrittenBeforeAssign;
582580

583581
// 1) side effects in the elemental body - it isn't sufficient to just look
584582
// for ordered elementals because we also cannot support out of order reads
@@ -593,10 +591,12 @@ ElementalAssignBufferization::findMatch(hlfir::ElementalOp elemental) {
593591
for (const mlir::MemoryEffects::EffectInstance &effect : *effects) {
594592
mlir::AliasResult res = containsReadOrWriteEffectOn(effect, match.array);
595593
if (res.isNo()) {
596-
if (mlir::isa<mlir::MemoryEffects::Write, mlir::MemoryEffects::Read>(
597-
effect.getEffect()))
598-
if (effect.getValue())
594+
if (effect.getValue()) {
595+
if (mlir::isa<mlir::MemoryEffects::Write>(effect.getEffect()))
599596
notToBeAccessedBeforeAssign.push_back(effect.getValue());
597+
else if (mlir::isa<mlir::MemoryEffects::Read>(effect.getEffect()))
598+
notToBeWrittenBeforeAssign.push_back(effect.getValue());
599+
}
600600

601601
// this is safe in the elemental
602602
continue;
@@ -669,11 +669,23 @@ ElementalAssignBufferization::findMatch(hlfir::ElementalOp elemental) {
669669
mlir::AliasResult res = containsReadOrWriteEffectOn(effect, val);
670670
if (!res.isNo()) {
671671
LLVM_DEBUG(llvm::dbgs()
672-
<< "diasllowed side-effect: " << effect.getValue() << " for "
672+
<< "disallowed side-effect: " << effect.getValue() << " for "
673673
<< elemental.getLoc() << "\n");
674674
return std::nullopt;
675675
}
676676
}
677+
// Anything that is read inside the elemental can only be safely read
678+
// between the elemental and the assignment.
679+
for (mlir::Value val : notToBeWrittenBeforeAssign) {
680+
mlir::AliasResult res = containsReadOrWriteEffectOn(effect, val);
681+
if (!res.isNo() &&
682+
!mlir::isa<mlir::MemoryEffects::Read>(effect.getEffect())) {
683+
LLVM_DEBUG(llvm::dbgs()
684+
<< "disallowed non-read side-effect: " << effect.getValue()
685+
<< " for " << elemental.getLoc() << "\n");
686+
return std::nullopt;
687+
}
688+
}
677689
}
678690

679691
return match;
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// RUN: fir-opt --opt-bufferization %s | FileCheck %s
2+
3+
// tonto case where optimized bufferization conservatively
4+
// did not pull elemental into the assignment due to
5+
// the designate op in between:
6+
// module test
7+
// type my_type
8+
// real, dimension(:,:), pointer :: p => null()
9+
// end type my_type
10+
// contains
11+
// subroutine assign1(self, i)
12+
// type(my_type) :: self
13+
// real, dimension(3) :: ct, q
14+
// integer :: i
15+
// self%p(:,i) = q - ct
16+
// end subroutine assign1
17+
// end module test
18+
19+
// CHECK-LABEL: func.func @_QMtestPassign1(
20+
// CHECK-NOT: hlfir.elemental
21+
// CHECK-NOT: hlfir.assign{{.*}}array
22+
func.func @_QMtestPassign1(%arg0: !fir.ref<!fir.type<_QMtestTmy_type{p:!fir.box<!fir.ptr<!fir.array<?x?xf32>>>}>> {fir.bindc_name = "self"}, %arg1: !fir.ref<i32> {fir.bindc_name = "i"}) {
23+
%c1 = arith.constant 1 : index
24+
%c0 = arith.constant 0 : index
25+
%c3 = arith.constant 3 : index
26+
%0 = fir.dummy_scope : !fir.dscope
27+
%1 = fir.alloca !fir.array<3xf32> {bindc_name = "ct", uniq_name = "_QMtestFassign1Ect"}
28+
%2 = fir.shape %c3 : (index) -> !fir.shape<1>
29+
%3:2 = hlfir.declare %1(%2) {uniq_name = "_QMtestFassign1Ect"} : (!fir.ref<!fir.array<3xf32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<3xf32>>, !fir.ref<!fir.array<3xf32>>)
30+
%4:2 = hlfir.declare %arg1 dummy_scope %0 {uniq_name = "_QMtestFassign1Ei"} : (!fir.ref<i32>, !fir.dscope) -> (!fir.ref<i32>, !fir.ref<i32>)
31+
%5 = fir.alloca !fir.array<3xf32> {bindc_name = "q", uniq_name = "_QMtestFassign1Eq"}
32+
%6:2 = hlfir.declare %5(%2) {uniq_name = "_QMtestFassign1Eq"} : (!fir.ref<!fir.array<3xf32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<3xf32>>, !fir.ref<!fir.array<3xf32>>)
33+
%7:2 = hlfir.declare %arg0 dummy_scope %0 {uniq_name = "_QMtestFassign1Eself"} : (!fir.ref<!fir.type<_QMtestTmy_type{p:!fir.box<!fir.ptr<!fir.array<?x?xf32>>>}>>, !fir.dscope) -> (!fir.ref<!fir.type<_QMtestTmy_type{p:!fir.box<!fir.ptr<!fir.array<?x?xf32>>>}>>, !fir.ref<!fir.type<_QMtestTmy_type{p:!fir.box<!fir.ptr<!fir.array<?x?xf32>>>}>>)
34+
%8 = hlfir.elemental %2 unordered : (!fir.shape<1>) -> !hlfir.expr<3xf32> {
35+
^bb0(%arg2: index):
36+
%22 = hlfir.designate %6#0 (%arg2) : (!fir.ref<!fir.array<3xf32>>, index) -> !fir.ref<f32>
37+
%23 = hlfir.designate %3#0 (%arg2) : (!fir.ref<!fir.array<3xf32>>, index) -> !fir.ref<f32>
38+
%24 = fir.load %22 : !fir.ref<f32>
39+
%25 = fir.load %23 : !fir.ref<f32>
40+
%26 = arith.subf %24, %25 fastmath<contract> : f32
41+
hlfir.yield_element %26 : f32
42+
}
43+
%9 = hlfir.designate %7#0{"p"} {fortran_attrs = #fir.var_attrs<pointer>} : (!fir.ref<!fir.type<_QMtestTmy_type{p:!fir.box<!fir.ptr<!fir.array<?x?xf32>>>}>>) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?x?xf32>>>>
44+
%10 = fir.load %9 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?x?xf32>>>>
45+
%11:3 = fir.box_dims %10, %c0 : (!fir.box<!fir.ptr<!fir.array<?x?xf32>>>, index) -> (index, index, index)
46+
%12 = arith.addi %11#0, %11#1 : index
47+
%13 = arith.subi %12, %c1 : index
48+
%14 = arith.subi %13, %11#0 : index
49+
%15 = arith.addi %14, %c1 : index
50+
%16 = arith.cmpi sgt, %15, %c0 : index
51+
%17 = arith.select %16, %15, %c0 : index
52+
%18 = fir.load %4#0 : !fir.ref<i32>
53+
%19 = fir.convert %18 : (i32) -> i64
54+
%20 = fir.shape %17 : (index) -> !fir.shape<1>
55+
%21 = hlfir.designate %10 (%11#0:%13:%c1, %19) shape %20 : (!fir.box<!fir.ptr<!fir.array<?x?xf32>>>, index, index, index, i64, !fir.shape<1>) -> !fir.box<!fir.array<?xf32>>
56+
hlfir.assign %8 to %21 : !hlfir.expr<3xf32>, !fir.box<!fir.array<?xf32>>
57+
hlfir.destroy %8 : !hlfir.expr<3xf32>
58+
return
59+
}

0 commit comments

Comments
 (0)