-
-
Notifications
You must be signed in to change notification settings - Fork 804
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat[venom]: store expansion pass (#4068)
expand `extract_literals` pass (introduced in bb9129a) to also extract variables and rename it to `store_expansion`, allowing for the dft pass to reorder variable uses more effectively. since this also gives us the guarantee that each variable is used exactly once (besides by store instructions), this allows us to make some simplifications in `venom_to_assembly.py`, since we no longer need to account for the same variable occurring on the stack more than one time (cf. for example 5d8280f). this results in a stack scheduler improvement. for example: - examples/tokens/ERC20.vy has a 20 byte codesize improvement - examples/auctions/blind_auction.vy has a 145 byte codesize improvement - examples/voting/ballot.vy has a 28 byte codesize improvement across a range of contracts, the improvement seems to be between 1-2%, but sometimes as high as 5% since stack operands are now guaranteed to be unique, the old rule to avoid swapping if two stack operands are the same no longer works. to address this, this commit adds an equivalence analysis. this creates equivalence sets of equivalent variables based on store chains, and then generalizes the rule from "don't swap if two stack operands are the same" to "don't swap if two stack operands are equivalent".
- Loading branch information
1 parent
c7669bd
commit 0e29db0
Showing
8 changed files
with
133 additions
and
78 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
from vyper.venom.analysis.analysis import IRAnalysis | ||
from vyper.venom.analysis.dfg import DFGAnalysis | ||
from vyper.venom.basicblock import IRVariable | ||
|
||
|
||
class VarEquivalenceAnalysis(IRAnalysis): | ||
""" | ||
Generate equivalence sets of variables. This is used to avoid swapping | ||
variables which are the same during venom_to_assembly. Theoretically, | ||
the DFTPass should order variable declarations optimally, but, it is | ||
not aware of the "pickaxe" heuristic in venom_to_assembly, so they can | ||
interfere. | ||
""" | ||
|
||
def analyze(self): | ||
dfg = self.analyses_cache.request_analysis(DFGAnalysis) | ||
|
||
equivalence_set: dict[IRVariable, int] = {} | ||
|
||
for bag, (var, inst) in enumerate(dfg._dfg_outputs.items()): | ||
if inst.opcode != "store": | ||
continue | ||
|
||
source = inst.operands[0] | ||
|
||
assert var not in equivalence_set # invariant | ||
if source in equivalence_set: | ||
equivalence_set[var] = equivalence_set[source] | ||
continue | ||
else: | ||
equivalence_set[var] = bag | ||
equivalence_set[source] = bag | ||
|
||
self._equivalence_set = equivalence_set | ||
|
||
def equivalent(self, var1, var2): | ||
if var1 not in self._equivalence_set: | ||
return False | ||
if var2 not in self._equivalence_set: | ||
return False | ||
return self._equivalence_set[var1] == self._equivalence_set[var2] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.