# HG changeset patch # User Paul Boddie # Date 1256513016 -3600 # Node ID 066ed6e92f1e57df820464d08ba944029d574ff0 # Parent 28161d2a2e1935b729a0da6e2dff140b4b19f930 Added experimental (and not fully correct) attribute access optimisation through attribute usage observations. Added an access method to the Table class. Added a simple help mode for the test program. diff -r 28161d2a2e19 -r 066ed6e92f1e micropython/cmd.py --- a/micropython/cmd.py Sun Oct 25 18:35:53 2009 +0100 +++ b/micropython/cmd.py Mon Oct 26 00:23:36 2009 +0100 @@ -37,6 +37,12 @@ return requested_optimisations +def show_optimisations(): + + "Show available optimisation flags." + + return ",".join(micropython.Program.supported_optimisations) + def program(filename, path, requested_optimisations, verbose=0): """ diff -r 28161d2a2e19 -r 066ed6e92f1e micropython/data.py --- a/micropython/data.py Sun Oct 25 18:35:53 2009 +0100 +++ b/micropython/data.py Mon Oct 26 00:23:36 2009 +0100 @@ -286,12 +286,26 @@ self.parent = parent self.name = name + # Attribute usage. + + self.attributes_used = set() + + # Possible values. + self.context_values = set() # Number of assignments per name. self.assignments = None + # Attribute usage methods. + + def use_attribute(self, attrname): + self.attributes_used.add(attrname) + return self.attributes_used + + # Value-related methods. + def get_contexts(self): return [c for (c, v) in self.context_values] diff -r 28161d2a2e19 -r 066ed6e92f1e micropython/inspect.py --- a/micropython/inspect.py Sun Oct 25 18:35:53 2009 +0100 +++ b/micropython/inspect.py Mon Oct 26 00:23:36 2009 +0100 @@ -417,6 +417,9 @@ def visitAssAttr(self, node): expr = self.dispatch(node.expr) + + # Record the attribute on the presumed target. + if isinstance(expr, Attr): if expr.name == "self": if not self.store_class_attr(node.attrname): @@ -424,6 +427,11 @@ elif isinstance(expr.get_value(), Module): self.store_module_attr(node.attrname, expr.get_value()) print "Warning: attribute %r of module %r set outside the module." % (node.attrname, expr.get_value().name) + + # Note usage of the attribute. + + node._attrnames = expr.use_attribute(node.attrname) + return None def visitAssList(self, node): @@ -633,6 +641,8 @@ expr = self.dispatch(node.expr) attrname = node.attrname + # Attempt to identify the nature of the attribute. + if isinstance(expr, Attr): value = expr.get_value() if isinstance(value, (Class, Module)): @@ -641,6 +651,11 @@ attr = UnresolvedName(attrname, value.full_name(), self) else: attr = None + + # Note usage of the attribute. + + node._attrnames = expr.use_attribute(node.attrname) + elif self.builtins is not None: attr = self.builtins.get(attrname) else: diff -r 28161d2a2e19 -r 066ed6e92f1e micropython/opt.py --- a/micropython/opt.py Sun Oct 25 18:35:53 2009 +0100 +++ b/micropython/opt.py Mon Oct 26 00:23:36 2009 +0100 @@ -31,7 +31,7 @@ # Code generation optimisations: "constant_storage", "constant_accessor", "known_target", "self_access", "temp_storage", "load_operations", "no_operations", "unused_results", - "unused_handlers", + "unused_handlers", "accesses_by_usage", # Inspection optimisations: "unused_objects" ] @@ -146,6 +146,9 @@ def should_optimise_unused_handlers(self): return "unused_handlers" in self.optimisations + def should_optimise_accesses_by_attribute_usage(self): + return "accesses_by_usage" in self.optimisations + # Simple tests. def is_constant_input(self, instruction): diff -r 28161d2a2e19 -r 066ed6e92f1e micropython/table.py --- a/micropython/table.py Sun Oct 25 18:35:53 2009 +0100 +++ b/micropython/table.py Mon Oct 26 00:23:36 2009 +0100 @@ -211,6 +211,20 @@ self.displaced_list = None self.raw = None + def access(self, objname, attrname): + + "Return the attribute entry for the given 'objname' and 'attrname'." + + try: + entry = self.table[objname] + except KeyError: + raise TableError, "Name %r is not registered as an object in the table." % objname + + try: + return entry[attrname] + except KeyError: + raise TableError, "Name %r is not registered as an attribute in the table." % attrname + def add(self, objname, attributes): "For the given 'objname' add the given 'attributes' to the table." diff -r 28161d2a2e19 -r 066ed6e92f1e micropython/trans.py --- a/micropython/trans.py Sun Oct 25 18:35:53 2009 +0100 +++ b/micropython/trans.py Mon Oct 26 00:23:36 2009 +0100 @@ -336,24 +336,17 @@ if target_name is not None: - # Access the object table to get the attribute position. + # Access the object table to get the attribute. try: - table_entry = self.objtable.table[target_name] - except KeyError: - raise TranslateError(self.module.full_name(), node, - "No object entry exists for target %r." % target_name) - - try: - pos = table_entry[attrname] - except KeyError: - raise TranslateError(self.module.full_name(), node, - "No attribute entry exists for name %r in target %r." % (attrname, target_name)) + attr = self.objtable.access(target_name, attrname) + except TableError, exc: + raise TranslateError(self.module.full_name(), node, exc.args[0]) # Produce a suitable instruction. if AddressInstruction is not None: - self.replace_active_value(AddressInstruction(pos)) + self.replace_active_value(AddressInstruction(attr)) else: raise TranslateError(self.module.full_name(), node, "Storing of class or module attribute %r via an object is not permitted." % attrname) @@ -431,6 +424,34 @@ except KeyError: pass + elif self.optimiser.should_optimise_accesses_by_attribute_usage(): + + if hasattr(node, "_attrnames"): + target_names = self.objtable.all_possible_objects(node._attrnames) + print self.expr_temp, node._attrnames, "->", target_names + + if len(target_names) == 1: + target_name = target_names[0] + + # Access the object table to get the attribute. + + try: + attr = self.objtable.access(target_name, attrname) + except TableError, exc: + raise TranslateError(self.module.full_name(), node, exc.args[0]) + + # Produce a suitable instruction. + + if AddressContextCondInstruction is not None and attr.is_static_attribute(): + self.new_op(AddressContextCondInstruction(attr)) + elif AttrInstruction is not None and not attr.is_static_attribute(): + self.new_op(AttrInstruction(attr)) + else: + raise TranslateError(self.module.full_name(), node, + "Storing of class or module attribute %r via an object is not permitted." % attrname) + + return + # Otherwise, perform a normal operation. try: diff -r 28161d2a2e19 -r 066ed6e92f1e test.py --- a/test.py Sun Oct 25 18:35:53 2009 +0100 +++ b/test.py Mon Oct 26 00:23:36 2009 +0100 @@ -26,6 +26,11 @@ args = sys.argv[2:] path = sys.path[:] + if "--help" in sys.argv: + print "Optimisations:" + print micropython.cmd.show_optimisations() + sys.exit(1) + if len(sys.argv) > 1: filename = os.path.abspath(sys.argv[1]) path.append(os.path.split(filename)[0])