forked from M-Labs/artiq
52 lines
1.7 KiB
Python
52 lines
1.7 KiB
Python
"""
|
|
:class:`LocalDemoter` is a constant propagation transform:
|
|
it replaces reads of any local variable with only one write
|
|
in a function without closures with the value that was written.
|
|
|
|
:class:`LocalAccessValidator` must be run before this transform
|
|
to ensure that the transformation it performs is sound.
|
|
"""
|
|
|
|
from collections import defaultdict
|
|
from .. import ir
|
|
|
|
class LocalDemoter:
|
|
def process(self, functions):
|
|
for func in functions:
|
|
self.process_function(func)
|
|
|
|
def process_function(self, func):
|
|
env_safe = {}
|
|
env_gets = defaultdict(lambda: set())
|
|
env_sets = defaultdict(lambda: set())
|
|
|
|
for insn in func.instructions():
|
|
if isinstance(insn, (ir.GetLocal, ir.SetLocal)):
|
|
if "$" in insn.var_name:
|
|
continue
|
|
|
|
env = insn.environment()
|
|
|
|
if env not in env_safe:
|
|
for use in env.uses:
|
|
if not isinstance(use, (ir.GetLocal, ir.SetLocal)):
|
|
env_safe[env] = False
|
|
break
|
|
else:
|
|
env_safe[env] = True
|
|
|
|
if not env_safe[env]:
|
|
continue
|
|
|
|
if isinstance(insn, ir.SetLocal):
|
|
env_sets[(env, insn.var_name)].add(insn)
|
|
else:
|
|
env_gets[(env, insn.var_name)].add(insn)
|
|
|
|
for (env, var_name) in env_sets:
|
|
if len(env_sets[(env, var_name)]) == 1:
|
|
set_insn = next(iter(env_sets[(env, var_name)]))
|
|
for get_insn in env_gets[(env, var_name)]:
|
|
get_insn.replace_all_uses_with(set_insn.value())
|
|
get_insn.erase()
|