Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat[venom]: common subexpression elimination pass #4241

Open
wants to merge 72 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 64 commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
33ef4db
start cse
HodanPlodky Sep 4, 2024
52a3470
cse start
HodanPlodky Sep 4, 2024
c2d60ed
only one inst handling
HodanPlodky Sep 9, 2024
3087650
cleanup + fix
HodanPlodky Sep 10, 2024
bad3f69
effects start
HodanPlodky Sep 12, 2024
9798a39
correct compare for joins
HodanPlodky Sep 13, 2024
ea92aa0
fix for calls and instruction without output (i.e. stores)
HodanPlodky Sep 13, 2024
c754574
small cleanup
HodanPlodky Sep 16, 2024
e6a8551
small cleanup
HodanPlodky Sep 16, 2024
6136f83
basic test created and fix small fix
HodanPlodky Sep 16, 2024
2d7e1a4
clean up of the debug
HodanPlodky Sep 16, 2024
4b62958
Update vyper/venom/analysis/available_expression.py - better hash method
HodanPlodky Sep 16, 2024
fbf2964
Update vyper/venom/analysis/available_expression.py - Incorrect gramm…
HodanPlodky Sep 16, 2024
86977f5
fix for some error in cancun version of experimental codegen test
HodanPlodky Sep 17, 2024
49e6949
fix for log opcode and lint
HodanPlodky Sep 17, 2024
de3c602
handling the different size of the expressions
HodanPlodky Sep 18, 2024
ae98b46
Merge branch 'vyperlang:master' into feat/cse
HodanPlodky Sep 22, 2024
b286eee
fixes in handling effects + bigger expression
HodanPlodky Sep 23, 2024
14b8963
fixes in handling effects
HodanPlodky Sep 24, 2024
e957b04
fixes (to better version) and style changes
HodanPlodky Sep 25, 2024
63f27fe
perf fixes + better order
HodanPlodky Sep 26, 2024
9ce9dd8
quick fix just for dft but since it is being rework it is just hot fix
HodanPlodky Sep 26, 2024
a3585ed
Merge branch 'master' into feat/cse
HodanPlodky Sep 30, 2024
775f0a9
created possibility to change size of the expression at pass level
HodanPlodky Sep 30, 2024
ea944e6
created possibility to change size of the expression at pass level (l…
HodanPlodky Sep 30, 2024
ca23cde
Merge branch 'master' into feat/cse
HodanPlodky Oct 5, 2024
018b6a9
fixes after merge
HodanPlodky Oct 5, 2024
94a9a6e
better results this order
HodanPlodky Oct 6, 2024
7d5b6aa
used new effects data structure to reduce duplication of code
HodanPlodky Oct 6, 2024
2de7731
add test for commutative instructions
harkal Oct 10, 2024
9efaea1
simplification of `same()` and replacement by `__eq__`
harkal Oct 10, 2024
22e0627
Merge branch 'master' into feat/cse
harkal Oct 10, 2024
4339697
different branches test
HodanPlodky Oct 10, 2024
8f76730
cleanup tests
harkal Oct 10, 2024
30ed887
add `same()` to `IROperand`
harkal Oct 10, 2024
2d33dc7
fix equality of expressions
harkal Oct 10, 2024
866ee62
Merge branch 'master' into feat/cse
harkal Oct 10, 2024
145ee31
comments and fix of the hash function so it should hold that if x and…
HodanPlodky Oct 10, 2024
f3c66d0
Merge branch 'master' into feat/cse
harkal Oct 10, 2024
6f9800f
bit more comments
HodanPlodky Oct 10, 2024
c6a825a
lint
HodanPlodky Oct 10, 2024
674577a
comments and removed some unnecessery code
HodanPlodky Oct 11, 2024
479271e
lint
HodanPlodky Oct 11, 2024
47e0a0e
added test for sanity check on effects and removed the change in the …
HodanPlodky Oct 14, 2024
4c9288e
Merge branch 'master' into feat/cse
HodanPlodky Oct 14, 2024
6e70e6e
fix after merge
HodanPlodky Oct 14, 2024
f244a13
fix after merge
HodanPlodky Oct 14, 2024
f3b709b
fixed circular import from commutative instruction
HodanPlodky Oct 14, 2024
b9caf57
idempotent instruction better support and test for the logs
HodanPlodky Oct 15, 2024
ee7a293
test cleanup and lint
HodanPlodky Oct 15, 2024
b462bdc
Merge branch 'master' into feat/cse
HodanPlodky Oct 15, 2024
7ca27b6
used commutative
HodanPlodky Oct 15, 2024
74aab92
caching of read and writes effects
HodanPlodky Oct 16, 2024
994ab14
Merge branch 'master' into feat/cse
HodanPlodky Oct 17, 2024
00b5e9e
better same compare and caching of exprs and depth
HodanPlodky Oct 18, 2024
1b576f3
more caching
HodanPlodky Oct 18, 2024
c99341f
should be better reevaluating
HodanPlodky Oct 18, 2024
3b3a546
idempotent rename and small clean
HodanPlodky Oct 18, 2024
3e45b31
replaced lattice structure by just dicts to make it more explicit
HodanPlodky Oct 18, 2024
73bd8ee
lint
HodanPlodky Oct 18, 2024
b6e0048
added small heuristic for small expressions
HodanPlodky Oct 21, 2024
44fb876
Merge branch 'master' into feat/cse
HodanPlodky Oct 28, 2024
45c3612
add some review
charles-cooper Nov 10, 2024
5e7f603
basic refactors and bit of improvement
HodanPlodky Nov 11, 2024
2434789
Merge branch 'master' into feat/cse
HodanPlodky Nov 11, 2024
709dc4d
Merge branch 'master' into feat/cse
HodanPlodky Nov 12, 2024
33f3dae
weird patch
HodanPlodky Nov 13, 2024
4e36a9c
different way of same fuction implementation
HodanPlodky Nov 18, 2024
dc07dff
small cleanup and more unintresting instruction
HodanPlodky Nov 18, 2024
4d57171
removed depth
HodanPlodky Nov 18, 2024
1a9c9ab
lint
HodanPlodky Nov 18, 2024
639d70b
removed forgoten comment
HodanPlodky Nov 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
220 changes: 220 additions & 0 deletions tests/unit/compiler/venom/test_common_subexpression_elimination.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
import pytest

from vyper.venom.analysis.analysis import IRAnalysesCache
from vyper.venom.basicblock import IRBasicBlock, IRLabel
from vyper.venom.context import IRContext
from vyper.venom.passes.common_subexpression_elimination import CSE
from vyper.venom.passes.store_expansion import StoreExpansionPass


def test_common_subexpression_elimination():
ctx = IRContext()
fn = ctx.create_function("test")
bb = fn.get_basic_block()
op = bb.append_instruction("store", 10)
sum_1 = bb.append_instruction("add", op, 10)
bb.append_instruction("mul", sum_1, 10)
sum_2 = bb.append_instruction("add", op, 10)
bb.append_instruction("mul", sum_2, 10)
bb.append_instruction("stop")

ac = IRAnalysesCache(fn)

CSE(ac, fn).run_pass(1, 5)

assert sum(1 for inst in bb.instructions if inst.opcode == "add") == 1, "wrong number of adds"
assert sum(1 for inst in bb.instructions if inst.opcode == "mul") == 1, "wrong number of muls"


def test_common_subexpression_elimination_commutative():
ctx = IRContext()
fn = ctx.create_function("test")
bb = fn.get_basic_block()
op = bb.append_instruction("store", 10)
sum_1 = bb.append_instruction("add", 10, op)
bb.append_instruction("mul", sum_1, 10)
sum_2 = bb.append_instruction("add", op, 10)
bb.append_instruction("mul", sum_2, 10)
bb.append_instruction("stop")

ac = IRAnalysesCache(fn)

CSE(ac, fn).run_pass(1, 5)

assert sum(1 for inst in bb.instructions if inst.opcode == "add") == 1, "wrong number of adds"
assert sum(1 for inst in bb.instructions if inst.opcode == "mul") == 1, "wrong number of muls"


def test_common_subexpression_elimination_effects_1():
ctx = IRContext()
fn = ctx.create_function("test")
bb = fn.get_basic_block()
mload_1 = bb.append_instruction("mload", 0)
op = bb.append_instruction("store", 10)
bb.append_instruction("mstore", op, 0)
mload_2 = bb.append_instruction("mload", 0)
bb.append_instruction("add", mload_1, 10)
bb.append_instruction("add", mload_2, 10)
bb.append_instruction("stop")

ac = IRAnalysesCache(fn)

CSE(ac, fn).run_pass()

assert sum(1 for inst in bb.instructions if inst.opcode == "add") == 2, "wrong number of adds"


# This is a limitation of current implementation
@pytest.mark.xfail
def test_common_subexpression_elimination_effects_2():
ctx = IRContext()
fn = ctx.create_function("test")
bb = fn.get_basic_block()
mload_1 = bb.append_instruction("mload", 0)
bb.append_instruction("add", mload_1, 10)
op = bb.append_instruction("store", 10)
bb.append_instruction("mstore", op, 0)
mload_2 = bb.append_instruction("mload", 0)
bb.append_instruction("add", mload_1, 10)
bb.append_instruction("add", mload_2, 10)
bb.append_instruction("stop")

ac = IRAnalysesCache(fn)
CSE(ac, fn).run_pass()

assert sum(1 for inst in bb.instructions if inst.opcode == "add") == 2, "wrong number of adds"


def test_common_subexpression_elimination_logs():
ctx = IRContext()
fn = ctx.create_function("test")
bb = fn.get_basic_block()
num2 = bb.append_instruction("store", 10)
num1 = bb.append_instruction("store", 20)
num3 = bb.append_instruction("store", 20)
bb.append_instruction("log", num1)
bb.append_instruction("log", num2)
bb.append_instruction("log", num1)
bb.append_instruction("log", num3)
bb.append_instruction("stop")

ac = IRAnalysesCache(fn)

CSE(ac, fn).run_pass()

assert sum(1 for inst in bb.instructions if inst.opcode == "log") == 4, "wrong number of log"


def test_common_subexpression_elimination_effects_3():
ctx = IRContext()
fn = ctx.create_function("test")
bb = fn.get_basic_block()
addr1 = bb.append_instruction("store", 10)
addr2 = bb.append_instruction("store", 10)
bb.append_instruction("mstore", 0, addr1)
bb.append_instruction("mstore", 2, addr2)
bb.append_instruction("mstore", 0, addr1)
bb.append_instruction("stop")

ac = IRAnalysesCache(fn)

CSE(ac, fn).run_pass()

assert (
sum(1 for inst in bb.instructions if inst.opcode == "mstore") == 3
), "wrong number of mstores"


def test_common_subexpression_elimination_effect_mstore():
ctx = IRContext()
fn = ctx.create_function("test")
bb = fn.get_basic_block()
op = bb.append_instruction("store", 10)
bb.append_instruction("mstore", op, 0)
mload_1 = bb.append_instruction("mload", 0)
op = bb.append_instruction("store", 10)
bb.append_instruction("mstore", op, 0)
mload_2 = bb.append_instruction("mload", 0)
bb.append_instruction("add", mload_1, mload_2)
bb.append_instruction("stop")

ac = IRAnalysesCache(fn)

StoreExpansionPass(ac, fn).run_pass()
CSE(ac, fn).run_pass(1, 5)

assert (
sum(1 for inst in bb.instructions if inst.opcode == "mstore") == 1
), "wrong number of mstores"
assert (
sum(1 for inst in bb.instructions if inst.opcode == "mload") == 1
), "wrong number of mloads"


def test_common_subexpression_elimination_effect_mstore_with_msize():
ctx = IRContext()
fn = ctx.create_function("test")
bb = fn.get_basic_block()
op = bb.append_instruction("store", 10)
bb.append_instruction("mstore", op, 0)
mload_1 = bb.append_instruction("mload", 0)
op = bb.append_instruction("store", 10)
bb.append_instruction("mstore", op, 0)
mload_2 = bb.append_instruction("mload", 0)
msize_read = bb.append_instruction("msize")
bb.append_instruction("add", mload_1, msize_read)
bb.append_instruction("add", mload_2, msize_read)
bb.append_instruction("stop")

ac = IRAnalysesCache(fn)

StoreExpansionPass(ac, fn).run_pass()
CSE(ac, fn).run_pass(1, 5)

assert (
sum(1 for inst in bb.instructions if inst.opcode == "mstore") == 2
), "wrong number of mstores"
assert (
sum(1 for inst in bb.instructions if inst.opcode == "mload") == 2
), "wrong number of mloads"


def test_common_subexpression_elimination_different_branches():
ctx = IRContext()
fn = ctx.create_function("test")
bb = fn.get_basic_block()
addr = bb.append_instruction("store", 10)
rand_cond = bb.append_instruction("mload", addr)

br1 = IRBasicBlock(IRLabel("br1"), fn)
fn.append_basic_block(br1)
br2 = IRBasicBlock(IRLabel("br2"), fn)
fn.append_basic_block(br2)
join_bb = IRBasicBlock(IRLabel("join_bb"), fn)
fn.append_basic_block(join_bb)

bb.append_instruction("jnz", rand_cond, br1.label, br2.label)

def do_same(bb: IRBasicBlock, rand: int):
a = bb.append_instruction("store", 10)
b = bb.append_instruction("store", 20)
c = bb.append_instruction("add", a, b)
bb.append_instruction("mul", c, rand)

do_same(br1, 1)
br1.append_instruction("jmp", join_bb.label)
do_same(br2, 2)
br2.append_instruction("jmp", join_bb.label)
do_same(join_bb, 3)
join_bb.append_instruction("stop")

ac = IRAnalysesCache(fn)

StoreExpansionPass(ac, fn).run_pass()
CSE(ac, fn).run_pass(1, 5)

assert sum(1 for inst in br1.instructions if inst.opcode == "add") == 1, "wrong number of adds"
assert sum(1 for inst in br2.instructions if inst.opcode == "add") == 1, "wrong number of adds"
assert (
sum(1 for inst in join_bb.instructions if inst.opcode == "add") == 1
), "wrong number of adds"
4 changes: 4 additions & 0 deletions vyper/venom/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from vyper.venom.function import IRFunction
from vyper.venom.ir_node_to_venom import ir_node_to_venom
from vyper.venom.passes import (
CSE,
SCCP,
AlgebraicOptimizationPass,
BranchOptimizationPass,
Expand Down Expand Up @@ -63,9 +64,12 @@ def _run_passes(fn: IRFunction, optimize: OptimizationLevel) -> None:
# MakeSSA again.
MakeSSA(ac, fn).run_pass()
BranchOptimizationPass(ac, fn).run_pass()

RemoveUnusedVariablesPass(ac, fn).run_pass()

StoreExpansionPass(ac, fn).run_pass()
CSE(ac, fn).run_pass(2, 10)
RemoveUnusedVariablesPass(ac, fn).run_pass()
DFTPass(ac, fn).run_pass()


Expand Down
Loading
Loading