From 914b9255f5820a1c072b660fec968f3928ef3a42 Mon Sep 17 00:00:00 2001 From: Takeshi Yoneda Date: Thu, 23 May 2024 12:15:07 +0900 Subject: [PATCH 1/2] ssa: empericially faster passRedundantPhiEliminationOpt Signed-off-by: Takeshi Yoneda --- internal/engine/wazevo/ssa/pass.go | 6 +++--- internal/engine/wazevo/ssa/pass_test.go | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/internal/engine/wazevo/ssa/pass.go b/internal/engine/wazevo/ssa/pass.go index 0dfd132cf0..5f41c01044 100644 --- a/internal/engine/wazevo/ssa/pass.go +++ b/internal/engine/wazevo/ssa/pass.go @@ -22,9 +22,9 @@ func (b *builder) RunPasses() { func (b *builder) runPreBlockLayoutPasses() { passSortSuccessors(b) passDeadBlockEliminationOpt(b) - passRedundantPhiEliminationOpt(b) // The result of passCalculateImmediateDominators will be used by various passes below. passCalculateImmediateDominators(b) + passRedundantPhiEliminationOpt(b) passNopInstElimination(b) // TODO: implement either conversion of irreducible CFG into reducible one, or irreducible CFG detection where we panic. @@ -120,9 +120,9 @@ func passRedundantPhiEliminationOpt(b *builder) { // complexity here is O(BlockNum * Iterations) at the worst case where BlockNum might be the order of thousands. for { changed := false - _ = b.blockIteratorBegin() // skip entry block! + _ = b.blockIteratorReversePostOrderBegin() // skip entry block! // Below, we intentionally use the named iteration variable name, as this comes with inevitable nested for loops! - for blk := b.blockIteratorNext(); blk != nil; blk = b.blockIteratorNext() { + for blk := b.blockIteratorReversePostOrderNext(); blk != nil; blk = b.blockIteratorReversePostOrderNext() { paramNum := len(blk.params) for paramIndex := 0; paramIndex < paramNum; paramIndex++ { diff --git a/internal/engine/wazevo/ssa/pass_test.go b/internal/engine/wazevo/ssa/pass_test.go index 83d33fbee4..755fa90f1b 100644 --- a/internal/engine/wazevo/ssa/pass_test.go +++ b/internal/engine/wazevo/ssa/pass_test.go @@ -167,6 +167,8 @@ blk3: () <-- (blk1,blk2) ret.AsReturn(ValuesNil) b.InsertInstruction(ret) } + + b.reversePostOrderedBasicBlocks = []*basicBlock{entry.(*basicBlock), loopHeader.(*basicBlock), end.(*basicBlock)} return nil }, before: ` From 9669207f459cf726d88deec46ddf20827c6d4b75 Mon Sep 17 00:00:00 2001 From: Takeshi Yoneda Date: Thu, 23 May 2024 13:26:14 +0900 Subject: [PATCH 2/2] more comments Signed-off-by: Takeshi Yoneda --- internal/engine/wazevo/ssa/pass.go | 5 +++++ internal/engine/wazevo/ssa/pass_test.go | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/internal/engine/wazevo/ssa/pass.go b/internal/engine/wazevo/ssa/pass.go index 5f41c01044..c7ebb15218 100644 --- a/internal/engine/wazevo/ssa/pass.go +++ b/internal/engine/wazevo/ssa/pass.go @@ -109,6 +109,8 @@ func passDeadBlockEliminationOpt(b *builder) { } // passRedundantPhiEliminationOpt eliminates the redundant PHIs (in our terminology, parameters of a block). +// This requires the reverse post-order traversal to be calculated before calling this function, +// hence passCalculateImmediateDominators must be called before this. func passRedundantPhiEliminationOpt(b *builder) { redundantParameterIndexes := b.ints[:0] // reuse the slice from previous iterations. @@ -118,6 +120,9 @@ func passRedundantPhiEliminationOpt(b *builder) { // relatively small. For example, sqlite speedtest binary results in the large number of redundant PHIs, // the maximum number of iteration was 22, which seems to be acceptable but not that small either since the // complexity here is O(BlockNum * Iterations) at the worst case where BlockNum might be the order of thousands. + // -- Note -- + // Currently, each iteration can run in an order of blocks, but it empirically converges quickly in practice when + // running on the reverse post-order. It might be possible to optimize this further by using the dominator tree. for { changed := false _ = b.blockIteratorReversePostOrderBegin() // skip entry block! diff --git a/internal/engine/wazevo/ssa/pass_test.go b/internal/engine/wazevo/ssa/pass_test.go index 755fa90f1b..015a10d088 100644 --- a/internal/engine/wazevo/ssa/pass_test.go +++ b/internal/engine/wazevo/ssa/pass_test.go @@ -168,7 +168,8 @@ blk3: () <-- (blk1,blk2) b.InsertInstruction(ret) } - b.reversePostOrderedBasicBlocks = []*basicBlock{entry.(*basicBlock), loopHeader.(*basicBlock), end.(*basicBlock)} + // passRedundantPhiEliminationOpt requires the reverse post-order traversal to be calculated. + passCalculateImmediateDominators(b) return nil }, before: `