# HG changeset patch # User Paul Boddie # Date 1222630021 -7200 # Node ID 2c1ad8c1697d7035f801a1bac9c88b00cfe35b72 # Parent 4ca9aa7a4cc3c950bf5255dd7ce4a2c1e58db126 Tidied the optimisations, moving the work done in the self access optimisation back into the translator. Made a reset method in the translator, performing a reset on the optimiser before processing each unit. Added an optimiser reset after each statement. diff -r 4ca9aa7a4cc3 -r 2c1ad8c1697d docs/optimisations.txt --- a/docs/optimisations.txt Sun Sep 28 19:59:32 2008 +0200 +++ b/docs/optimisations.txt Sun Sep 28 21:27:01 2008 +0200 @@ -2,40 +2,44 @@ ------------ ------------------------ constant_storage value instruction references a constant; -(elimination) storage instruction references a constant; - remove both instructions (currently a single - merged instruction) +(guidance) storage instruction references a constant; + | indicate whether both instructions satisfy the + | preconditions and should be removed (although + | this currently involves just a single merged + | instruction) constant_accessor value instruction references a constant; -(guidance) target name provided (for use in producing an - address access instruction) +(guidance) | target name provided (for use in producing an + | address access instruction) known_target value instruction references a constant; -(guidance) target and context are provided (no instructions - removed) +(guidance) | target and context are provided (no instructions + | are removed) self_access value instruction references "self" in a method; (guidance) specified attribute name always has the same position; - appropriate instruction generated + | indicate whether an appropriate instruction can + | be generated for the access temp_storage value instruction is a simple input operation; (elimination) value instruction is the last instruction; -(guidance) remove the value instruction, provide the value - instruction in place of a temporary storage - reference +(guidance) | remove the value instruction, provide the value + | instruction in place of a temporary storage + | reference load_operations value instruction is a simple input operation; (merge) value instruction is the last instruction; current instruction uses simple input; - remove the value instruction, make the value - instruction the input to the current instruction + | remove the value instruction, make the value + | instruction the input to the current instruction no_operations input to the current instruction loads from the -(elimination) destination of the current instruction; - omit the current instruction +(guidance) destination of the current instruction; + | indicate that the current instruction should be + | omitted unused_results value instruction is a simple input operation; (elimination) value instruction is the final instruction of a discarded expression; - remove the value instruction + | remove the value instruction diff -r 4ca9aa7a4cc3 -r 2c1ad8c1697d micropython/ast.py --- a/micropython/ast.py Sun Sep 28 19:59:32 2008 +0200 +++ b/micropython/ast.py Sun Sep 28 21:27:01 2008 +0200 @@ -79,18 +79,33 @@ self.loop_labels = [] self.exception_labels = [] - # The code itself. This is limited to the code for a particular block - # being processed. Also retained is information about temporary values - # and instructions which construct frames. - - self.code = None - self.temp_positions = set() - self.max_temp_position = -1 - self.frame_makers = [] + self.reset() def __repr__(self): return "Translation(%r)" % self.module + def reset(self): + + "Reset the state of the translator." + + # The code itself. This is limited to the code for a particular block + # being processed. + + self.code = [] + + # Information about temporary values. + + self.temp_positions = set() + self.max_temp_position = -1 + + # Information about instructions which construct frames. + + self.frame_makers = [] + + # Optimiser state must be reset for each unit. + + self.optimiser.reset() + def get_module_code(self, final=0): """ @@ -99,9 +114,7 @@ """ self.unit = self.module - self.code = [] - self.temp_positions = set() - self.max_temp_position = -1 + self.reset() if self.module.module is not None: self.dispatch(self.module.module) @@ -119,9 +132,7 @@ "Return the code for the given 'unit'." self.unit = unit - self.code = [] - self.temp_positions = set() - self.max_temp_position = -1 + self.reset() if unit.astnode is not None: self.dispatch(unit.astnode) @@ -134,9 +145,7 @@ "Return the code for the given class 'cls'." self.unit = cls.get_instantiator() - self.code = [] - self.temp_positions = set() - self.max_temp_position = -1 + self.reset() init_method = cls.get_init_method() @@ -200,6 +209,9 @@ self.new_op(LoadAddress(self.get_builtin(name, node))) def get_builtin_class(self, name, node): + + "Return the built-in class with the given 'name' for the given 'node'." + return self.get_builtin(name, node).value def get_builtin(self, name, node): @@ -259,6 +271,15 @@ # Assignment expression values. def record_value(self, immediate=1): + + """ + Record the current active value for an assignment. If the optional + 'immediate' parameter if set to a false value always allocates new + temporary storage to hold the recorded value; otherwise, the + value-providing instruction may be replicated in order to provide the + active value later on. + """ + if immediate: temp = self.optimiser.optimise_temp_storage() else: @@ -266,14 +287,21 @@ self.expr_temp.append(temp) def discard_value(self): + + "Discard any temporary storage in use for the current assignment value." + self.discard_temp(self.expr_temp.pop()) def set_source(self): + + "Set the source of an assignment using the current assignment value." + self.optimiser.set_source(self.expr_temp[-1]) # Optimise away constant storage if appropriate. - self.optimiser.optimise_constant_storage() + if self.optimiser.optimise_constant_storage(): + self.remove_op() # Temporary storage administration. @@ -429,13 +457,49 @@ # see if the attribute is acceptably positioned and produce a direct # access to the attribute. - elif self.optimiser.optimise_self_access(attrname, (AddressInstruction, AddressContextInstruction, AttrInstruction), node): + elif self.optimiser.optimise_self_access(self.unit, attrname): + + # Either generate an instruction operating on an instance attribute. + + try: + attr = self.unit.parent.instance_attributes()[attrname] + self.new_op(AttrInstruction(attr)) + + # Or generate an instruction operating on a class attribute. + + except KeyError: + attr = self.unit.parent.all_attributes()[attrname] + + # Switch the context if the class attribute is compatible with + # the instance. + + if attr.defined_within_hierarchy(): + + # Only permit loading (not storing) of class attributes via self. + + if AddressContextInstruction is not None: + self.new_op(AddressContextInstruction(attr)) + else: + raise TranslateError(self.module.full_name(), node, + "Storing of class attribute %r via self not permitted." % attrname) + + # Preserve the context if the class attribute comes from an + # incompatible class. + + else: + if AddressInstruction is not None: + self.new_op(AddressInstruction(attr)) + else: + raise TranslateError(self.module.full_name(), node, + "Storing of class attribute %r via self not permitted." % attrname) + return # Otherwise, perform a normal operation. try: index = self.objtable.get_index(attrname) + except self.objtable.TableError: raise TranslateError(self.module.full_name(), node, "No attribute entry exists for name %r." % attrname) @@ -1749,12 +1813,26 @@ def visitSlice(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Slice") def visitStmt(self, node): + + "Process the collection of statements provided by 'node'." + for n in node.nodes: + + # Process the statement. + self.dispatch(n) + + # Discard temporary storage. + if self.temp_positions: #print "Had temp", self.temp_positions self.temp_positions = set() + # Prevent incorrect optimisation by resetting the optimiser after + # each statement. + + self.optimiser.reset() + def visitSub(self, node): self._visitBinary(node, "__sub__", "__rsub__") @@ -1856,10 +1934,6 @@ self.set_label(exit_label) self.drop_loop_labels() - # Prevent incorrect optimisation. - - self.optimiser.reset() - def visitWith(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "With") def visitYield(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Yield") diff -r 4ca9aa7a4cc3 -r 2c1ad8c1697d micropython/opt.py --- a/micropython/opt.py Sun Sep 28 19:59:32 2008 +0200 +++ b/micropython/opt.py Sun Sep 28 21:27:01 2008 +0200 @@ -82,7 +82,10 @@ def remove_active_value(self): - "Remove the value-providing active instruction if appropriate." + """ + Remove the value-providing active instruction from the generated code, + if appropriate, but keep a record of the active instruction itself. + """ if self.active_value is self.active: removed = self.active @@ -275,17 +278,12 @@ """ Where the last operation stores a constant into a target which is also - constant, optimise away both operations. + constant, indicate that both operations should be optimised away. """ - if self.should_optimise_constant_storage() and \ + return self.should_optimise_constant_storage() and \ self.have_constant_target() and \ - self.have_constant_source(): - - self.translation.remove_op() - return 1 - else: - return 0 + self.have_constant_source() def optimise_constant_accessor(self): @@ -331,57 +329,16 @@ else: return None - def optimise_self_access(self, attrname, classes, node): + def optimise_self_access(self, unit, attrname): """ - Where the provided 'attrname' accesses an attribute which occupies the - same position in all possible objects which can be accessed, generate an - instruction using one of the given 'classes', accessing the attribute - directly. + Return whether code in the given 'unit' is able to access the given + 'attrname' through the same position in all possible objects which might + be accessed. """ - AddressInstruction, AddressContextInstruction, AttrInstruction = classes - - if self.should_optimise_self_access() and self.have_self_input() and \ - not self.translation.unit.is_relocated(attrname): - - # Either generate an instruction operating on an instance attribute. - - try: - attr = self.translation.unit.parent.instance_attributes()[attrname] - self.translation.new_op(AttrInstruction(attr)) - - # Or generate an instruction operating on a class attribute. - - except KeyError: - attr = self.translation.unit.parent.all_attributes()[attrname] - - # Switch the context if the class attribute is compatible with - # the instance. - - if attr.defined_within_hierarchy(): - - # Only permit loading (not storing) of class attributes via self. - - if AddressContextInstruction is not None: - self.translation.new_op(AddressContextInstruction(attr)) - else: - raise TranslateError(self.translation.module.full_name(), node, - "Storing of class attribute %r via self not permitted." % attrname) - - # Preserve the context if the class attribute comes from an - # incompatible class. - - else: - if AddressInstruction is not None: - self.translation.new_op(AddressInstruction(attr)) - else: - raise TranslateError(self.translation.module.full_name(), node, - "Storing of class attribute %r via self not permitted." % attrname) - - return 1 - else: - return 0 + return self.should_optimise_self_access() and \ + self.have_self_input() and not unit.is_relocated(attrname) def optimise_temp_storage(self): @@ -433,12 +390,8 @@ the inputs originally came from. """ - if self.should_optimise_away_no_operations() and \ - self.is_resultant_no_operation(instruction): - - return 1 - else: - return 0 + return self.should_optimise_away_no_operations() and \ + self.is_resultant_no_operation(instruction) def optimise_unused_results(self):