[Arc] Don't sink ops with nested writes in MergeIfs (#8584)

This commit is contained in:
Bea Healy 2025-06-19 18:43:31 +01:00 committed by GitHub
parent b6b1ced097
commit f4995a322c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 34 additions and 3 deletions

View File

@ -133,13 +133,19 @@ void MergeIfsPass::sinkOps(Block &rootBlock) {
// Assign an order to this op.
auto order = OpOrder{opOrder.size() + 1, 0};
opOrder[&op] = order;
// Track whether the op is, or contains, any writes (and thus can't
// generally be moved into a block)
bool opContainsWrites = false;
// Analyze the side effects in the op.
op.walk([&](Operation *subOp) {
if (auto ptr = getPointerWrittenByOp(subOp))
if (auto ptr = getPointerWrittenByOp(subOp)) {
nextWrite[ptr] = &op;
else if (!isa<StateReadOp, MemoryReadOp>(subOp) && hasSideEffects(subOp))
opContainsWrites = true;
} else if (!isa<StateReadOp, MemoryReadOp>(subOp) &&
hasSideEffects(subOp)) {
nextSideEffect = &op;
}
});
// Determine how much the op can be moved.
@ -151,7 +157,7 @@ void MergeIfsPass::sinkOps(Block &rootBlock) {
// Don't move across general side-effecting ops.
if (nextSideEffect)
moveLimit.maximize({nextSideEffect, opOrder.lookup(nextSideEffect)});
} else if (isa<StateWriteOp, MemoryWriteOp>(&op) || nextSideEffect == &op) {
} else if (opContainsWrites || nextSideEffect == &op) {
// Don't move writes or side-effecting ops.
continue;
}

View File

@ -281,3 +281,28 @@ func.func @MergeNestedIfs(%arg0: i42, %arg1: i1, %arg2: i1) {
}
return
}
// Check that ops containing a write aren't sunk
// CHECK-LABEL: func.func @DontNestWrites
func.func @DontNestWrites(%arg0: !arc.state<i1>, %arg1: i1, %arg2: i1) {
// We just want to check that the first if hasn't been moved into the second
// CHECK-NEXT: {{%.+}} = scf.if %arg1 -> (i1) {
// CHECK: } else {
// CHECK: }
// CHECK-NEXT: scf.if %arg2 {
// CHECK: }
// CHECK-NEXT: return
%1 = scf.if %arg1 -> (i1) {
%0 = hw.constant true
arc.state_write %arg0 = %0 : <i1>
scf.yield %0 : i1
} else {
%0 = hw.constant false
scf.yield %0 : i1
}
scf.if %arg2 {
%0 = comb.or %1, %1 : i1
}
return
}