From 6ac82e14399eba0e38fda9455f769cf10540ed99 Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 7 Oct 2015 22:21:29 +0300 Subject: [PATCH] transforms.devirtualizer.FunctionResolver: implement. --- artiq/compiler/module.py | 4 + artiq/compiler/transforms/__init__.py | 1 + artiq/compiler/transforms/devirtualizer.py | 92 ++++++++++++++++++++++ 3 files changed, 97 insertions(+) create mode 100644 artiq/compiler/transforms/devirtualizer.py diff --git a/artiq/compiler/module.py b/artiq/compiler/module.py index cc1f26032..a7f773225 100644 --- a/artiq/compiler/module.py +++ b/artiq/compiler/module.py @@ -57,6 +57,7 @@ class Module: ref_period=ref_period) dead_code_eliminator = transforms.DeadCodeEliminator(engine=self.engine) local_access_validator = validators.LocalAccessValidator(engine=self.engine) + devirtualizer = transforms.Devirtualizer() self.name = src.name self.globals = src.globals @@ -65,9 +66,12 @@ class Module: monomorphism_validator.visit(src.typedtree) escape_validator.visit(src.typedtree) iodelay_estimator.visit_fixpoint(src.typedtree) + devirtualizer.visit(src.typedtree) self.artiq_ir = artiq_ir_generator.visit(src.typedtree) dead_code_eliminator.process(self.artiq_ir) local_access_validator.process(self.artiq_ir) + # for f in self.artiq_ir: + # print(f) def build_llvm_ir(self, target): """Compile the module to LLVM IR for the specified target.""" diff --git a/artiq/compiler/transforms/__init__.py b/artiq/compiler/transforms/__init__.py index 39831fea3..fed1c6648 100644 --- a/artiq/compiler/transforms/__init__.py +++ b/artiq/compiler/transforms/__init__.py @@ -3,5 +3,6 @@ from .inferencer import Inferencer from .int_monomorphizer import IntMonomorphizer from .iodelay_estimator import IODelayEstimator from .artiq_ir_generator import ARTIQIRGenerator +from .devirtualizer import Devirtualizer from .dead_code_eliminator import DeadCodeEliminator from .llvm_ir_generator import LLVMIRGenerator diff --git a/artiq/compiler/transforms/devirtualizer.py b/artiq/compiler/transforms/devirtualizer.py new file mode 100644 index 000000000..71000e36d --- /dev/null +++ b/artiq/compiler/transforms/devirtualizer.py @@ -0,0 +1,92 @@ +""" +:class:`Devirtualizer` performs method resolution at +compile time. + +Devirtualization is implemented using a lattice +with three states: unknown → assigned once → diverges. +The lattice is computed individually for every +variable in scope as well as every +(constructor type, field name) pair. +""" + +from pythonparser import algorithm +from .. import ir, types + +def _advance(target_map, key, value): + if key not in target_map: + target_map[key] = value # unknown → assigned once + else: + target_map[key] = None # assigned once → diverges + +class FunctionResolver(algorithm.Visitor): + def __init__(self, variable_map): + self.variable_map = variable_map + + self.in_assign = False + self.scope_map = dict() + self.scope = None + self.queue = [] + + def finalize(self): + for thunk in self.queue: + thunk() + + def visit_scope(self, node): + old_scope, self.scope = self.scope, node + self.generic_visit(node) + self.scope = old_scope + + def visit_in_assign(self, node): + self.in_assign = True + self.visit(node) + self.in_assign = False + + def visit_Assign(self, node): + self.visit(node.value) + self.visit_in_assign(node.targets) + + def visit_For(self, node): + self.visit(node.iter) + self.visit_in_assign(node.target) + self.visit(node.body) + self.visit(node.orelse) + + def visit_withitem(self, node): + self.visit(node.context_expr) + self.visit_in_assign(node.optional_vars) + + def visit_comprehension(self, node): + self.visit(node.iter) + self.visit_in_assign(node.target) + self.visit(node.ifs) + + def visit_ModuleT(self, node): + self.visit_scope(node) + + def visit_FunctionDefT(self, node): + _advance(self.scope_map, (self.scope, node.name), node) + self.visit_scope(node) + + def visit_NameT(self, node): + if self.in_assign: + # Just give up if we assign anything at all to a variable, and + # assume it diverges. + _advance(self.scope_map, (self.scope, node.id), None) + else: + # Copy the final value in scope_map into variable_map. + key = (self.scope, node.id) + def thunk(): + if key in self.scope_map: + self.variable_map[node] = self.scope_map[key] + self.queue.append(thunk) + +class Devirtualizer: + def __init__(self): + self.variable_map = dict() + self.method_map = dict() + + def visit(self, node): + resolver = FunctionResolver(self.variable_map) + resolver.visit(node) + resolver.finalize() + # print(self.variable_map)