# HG changeset patch # User Paul Boddie # Date 1216420790 -7200 # Node ID bc2c5bb980a8be78f9011f7189d9cbfe3e8619c3 # Parent 160e3ccc7dd681d649eec861642df6d85d808e02 Moved various methods around in the Translation class. Removed the label from PopHandler. Added load operation optimisations (similar to the previous stack access optimisations). Added explicit source attributes to store operations. diff -r 160e3ccc7dd6 -r bc2c5bb980a8 micropython/ast.py --- a/micropython/ast.py Fri Jul 18 01:18:22 2008 +0200 +++ b/micropython/ast.py Sat Jul 19 00:39:50 2008 +0200 @@ -31,7 +31,7 @@ "A translated module." - supported_optimisations = ["constant_storage", "known_target", "self_access", "temp_storage"] + supported_optimisations = ["constant_storage", "known_target", "self_access", "temp_storage", "load_operations"] attribute_load_instructions = (LoadAddress, LoadAddressContext, LoadAttr, LoadAttrIndex) attribute_store_instructions = (StoreAddress, StoreAddressContext, StoreAttr, StoreAttrIndex) @@ -69,6 +69,10 @@ self.active = None + # The temporary storage used by the current assignment expression. + + self.expr_temp = None + # Wiring within the code. self.labels = {} @@ -216,6 +220,10 @@ if self._optimise_constant_storage(op): return + # Optimise load operations employed by this instruction. + + self._optimise_load_operations(op) + self.code.append(op) self.active = op @@ -242,6 +250,207 @@ except IndexError: return None + # Optimisation tests. + + def _should_optimise_constant_storage(self): + return "constant_storage" in self.optimisations + + def _should_optimise_known_target(self): + return "known_target" in self.optimisations + + def _should_optimise_self_access(self): + return "self_access" in self.optimisations + + def _should_optimise_temp_storage(self): + return "temp_storage" in self.optimisations + + def _should_optimise_load_operations(self): + return "load_operations" in self.optimisations + + # Simple tests. + + def _is_constant_input(self, instruction): + + "Return whether 'instruction' provides a constant input." + + return isinstance(instruction, LoadAddress) and instruction.attr.assignments == 1 or \ + isinstance(instruction, LoadConst) + + def _is_constant_target(self, instruction): + + "Return whether 'instruction' provides a constant target." + + return isinstance(instruction, (StoreName, StoreAddress)) and \ + instruction.attr.assignments == 1 + + def _is_simple_input(self, instruction): + + "Return whether 'instruction' provides a simple input." + + return isinstance(instruction, (LoadName, LoadTemp, LoadResult, LoadAddress)) + + def _is_simple_input_user(self, instruction): + + "Return whether 'instruction' can use simple input." + + return isinstance(instruction, + (StoreName, StoreTemp, StoreFrame, StoreAddress, RaiseException) + self.attribute_store_instructions) + + # Convenience tests. + + def _have_constant_input(self): + + "Return whether the active instruction provides a constant input." + + return self._is_constant_input(self.active) + + _have_known_target = _have_constant_input + + def _have_simple_input(self): + + "Return whether the active instruction provides a local input." + + return self._is_simple_input(self.active) + + def _have_self_input(self): + + "Return whether the active instruction is a reference to self." + + return isinstance(self.unit, Function) and \ + self.unit.is_method() and isinstance(self.active, LoadName) and \ + self.active.attr.name == "self" + + def _have_temp_compatible_access(self): + + """ + Indicate whether the active instruction can be used in place of access + to a temporary variable retaining the result of the last instruction. + """ + + return isinstance(self.active, (LoadName, LoadTemp, LoadAddress, LoadConst)) + + # Optimisation methods. See the supported_optimisations class attribute. + + def _optimise_constant_storage(self, instruction): + + """ + Where this operation should store a constant into a target which is + also constant, optimise away both operations. + """ + + if self._should_optimise_constant_storage() and \ + self._is_constant_target(instruction) and \ + self._have_constant_input(): + + self.remove_op() + return 1 + else: + return 0 + + def _optimise_known_target(self): + + """ + Where the target of an invocation is known, provide information about it + and its context. If a class is being invoked and the conditions are + appropriate, get information about the specific initialiser. + """ + + if self._should_optimise_known_target() and self._have_known_target(): + last = self.last_op() + target = last.attr.value + context = last.attr.context + + # Handle calls to classes. + + if isinstance(target, Class): + target = target.get_instantiator() + context = Instance() + + # A special context is chosen to avoid generating unnecessary + # context loading and checking instructions. + + return target, context + else: + return None + + def _optimise_self_access(self, attrname, classes): + + """ + 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. + """ + + AddressInstruction, AddressContextInstruction, AttrInstruction = classes + + if self._should_optimise_self_access() and self._have_self_input() and \ + not self.unit.is_relocated(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] + new_attr = attr.via_instance() + self.new_op(AddressContextInstruction(new_attr)) + + return 1 + else: + return 0 + + def _optimise_temp_storage(self): + + """ + Where the next operation would involve storing a value into temporary + storage at 'temp_position', record and remove any simple instruction + which produced the value to be stored such that instead of subsequently + accessing the temporary storage, that instruction is substituted. + + If no optimisation can be achieved, a StoreTemp instruction is produced + and the appropriate LoadTemp instruction is returned. + + Restriction: for use only in situations where the source of the + temporary data will not be disturbed between its first access and its + subsequent use. + """ + + if self._should_optimise_temp_storage() and \ + self._have_temp_compatible_access(): + + last = self.last_op() + self.remove_op() + return last + else: + return self.get_temp() + + def _optimise_load_operations(self, instruction): + + """ + Incorporate previous load operations into other operations. + """ + + if self._should_optimise_load_operations() and \ + self._have_simple_input() and \ + self._is_simple_input_user(instruction): + + last = self.last_op() + self.remove_op() + instruction.input = last + + # Visitor methods. + + def default(self, node, *args): + raise TranslateError(self.module.full_name(), node, "Node class %r is not supported." % node.__class__) + + def dispatch(self, node, *args): + return ASTVisitor.dispatch(self, node, *args) + # Internal helper methods. def _visitAttr(self, node, classes): @@ -623,177 +832,6 @@ else: self.new_op(AddressInstruction(self.get_builtin(name, node))) - # Optimisation tests. - - def _should_optimise_constant_storage(self): - return "constant_storage" in self.optimisations - - def _should_optimise_known_target(self): - return "known_target" in self.optimisations - - def _should_optimise_self_access(self): - return "self_access" in self.optimisations - - def _should_optimise_temp_storage(self): - return "temp_storage" in self.optimisations - - # Simple tests. - - def _is_constant_input(self, instruction): - - "Return whether 'instruction' provides a constant input." - - return isinstance(instruction, LoadAddress) and instruction.attr.assignments == 1 or \ - isinstance(instruction, LoadConst) - - def _is_constant_target(self, instruction): - - "Return whether 'instruction' provides a constant target." - - return isinstance(instruction, (StoreName, StoreAddress)) and \ - instruction.attr.assignments == 1 - - def _is_local_input(self, instruction): - - "Return whether 'instruction' provides a local input." - - return isinstance(instruction, (LoadName, LoadTemp)) - - # Convenience tests. - - def _have_constant_input(self): - - "Return whether the active instruction provides a constant input." - - return self._is_constant_input(self.active) - - _have_known_target = _have_constant_input - - def _have_self_input(self): - - "Return whether the active instruction is a reference to self." - - return isinstance(self.unit, Function) and \ - self.unit.is_method() and isinstance(self.active, LoadName) and \ - self.active.attr.name == "self" - - def _have_temp_compatible_access(self): - - """ - Indicate whether the active instruction can be used in place of access - to a temporary variable retaining the result of the last instruction. - """ - - return isinstance(self.active, (LoadName, LoadTemp, LoadAddress, LoadConst)) - - # Optimisation methods. See the supported_optimisations class attribute. - - def _optimise_temp_storage(self): - - """ - Where the next operation would involve storing a value into temporary - storage at 'temp_position', record and remove any simple instruction - which produced the value to be stored such that instead of subsequently - accessing the temporary storage, that instruction is substituted. - - If no optimisation can be achieved, a StoreTemp instruction is produced - and the appropriate LoadTemp instruction is returned. - - Restriction: for use only in situations where the source of the - temporary data will not be disturbed between its first access and its - subsequent use. - """ - - if self._should_optimise_temp_storage() and \ - self._have_temp_compatible_access(): - - last = self.last_op() - self.remove_op() - return last - else: - return self.get_temp() - - def _optimise_constant_storage(self, instruction): - - """ - Where this operation should store a constant into a target which is - also constant, optimise away both operations. - """ - - if self._should_optimise_constant_storage() and \ - self._is_constant_target(instruction) and \ - self._have_constant_input(): - - self.remove_op() - return 1 - else: - return 0 - - def _optimise_known_target(self): - - """ - Where the target of an invocation is known, provide information about it - and its context. If a class is being invoked and the conditions are - appropriate, get information about the specific initialiser. - """ - - if self._should_optimise_known_target() and self._have_known_target(): - last = self.last_op() - target = last.attr.value - context = last.attr.context - - # Handle calls to classes. - - if isinstance(target, Class): - target = target.get_instantiator() - context = Instance() - - # A special context is chosen to avoid generating unnecessary - # context loading and checking instructions. - - return target, context - else: - return None - - def _optimise_self_access(self, attrname, classes): - - """ - 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. - """ - - AddressInstruction, AddressContextInstruction, AttrInstruction = classes - - if self._should_optimise_self_access() and self._have_self_input() and \ - not self.unit.is_relocated(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] - new_attr = attr.via_instance() - self.new_op(AddressContextInstruction(new_attr)) - - return 1 - else: - return 0 - - # Visitor methods. - - def default(self, node, *args): - raise TranslateError(self.module.full_name(), node, "Node class %r is not supported." % node.__class__) - - def dispatch(self, node, *args): - return ASTVisitor.dispatch(self, node, *args) - def _visitUnary(self, node, method): """ @@ -981,6 +1019,8 @@ self.discard_temp(temp1) self.discard_temp(temp2) + # Concrete visitor methods. + def visitAdd(self, node): self._visitBinary(node, "__add__", "__radd__") @@ -1003,20 +1043,25 @@ def visitAssign(self, node): self.dispatch(node.expr) - temp = self.get_temp() + self.expr_temp = self._optimise_temp_storage() for n in node.nodes: self.dispatch(n) - self.discard_temp(temp) + self.discard_temp(self.expr_temp) + self.expr_temp = None def visitAssAttr(self, node): self._visitAttr(node, self.attribute_store_instructions) + if self.active is not None: + self.active.source = self.expr_temp def visitAssList(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "AssList") def visitAssName(self, node): self._visitName(node, (StoreName, StoreAddress)) + if self.active is not None: + self.active.source = self.expr_temp visitAssTuple = visitAssList @@ -1360,13 +1405,13 @@ self.new_op(PushHandler(handler_label)) self.dispatch(node.body) - self.new_op(PopHandler(handler_label)) + self.new_op(PopHandler()) self.new_op(Jump(exit_label)) # Start of handlers. self.set_label(handler_label) - self.new_op(PopHandler(handler_label)) + self.new_op(PopHandler()) for name, assignment, handler in node.handlers: next_label = self.new_label() diff -r 160e3ccc7dd6 -r bc2c5bb980a8 micropython/rsvp.py --- a/micropython/rsvp.py Fri Jul 18 01:18:22 2008 +0200 +++ b/micropython/rsvp.py Sat Jul 19 00:39:50 2008 +0200 @@ -43,22 +43,33 @@ def __init__(self, attr=None): self.attr = attr + self.input = None + self.source = None # for storage instructions def copy(self): return self.__class__(self.attr) def __repr__(self): if self.attr is not None: - return "%s(%r)" % (self.__class__.__name__, self.attr) + return "%s(%r)%s" % (self.__class__.__name__, self.attr, self.show_input()) else: - return "%s()" % (self.__class__.__name__) + return "%s()%s" % (self.__class__.__name__, self.show_input()) + + def show_input(self): + if self.input is not None: + if self.source is not None: + return " <- (%r, %r)" % (self.input, self.source) + else: + return " <- %r" % self.input + else: + return "" class FrameRelativeInstruction(Instruction): "An instruction operating on the current frame." def __repr__(self): - return "%s(%r)" % (self.__class__.__name__, self.get_operand()) + return "%s(%r)%s" % (self.__class__.__name__, self.get_operand(), self.show_input()) def get_operand(self): return self.attr.position @@ -72,9 +83,9 @@ def __repr__(self): position = self.get_operand() if position is not None: - return "%s(%r) # %s" % (self.__class__.__name__, position, name(self.attr)) + return "%s(%r)%s # %s" % (self.__class__.__name__, position, self.show_input(), name(self.attr)) else: - return "%s(%r)" % (self.__class__.__name__, name(self.attr)) + return "%s(%r)%s" % (self.__class__.__name__, name(self.attr), self.show_input()) def get_operand(self): return self.attr.position @@ -88,14 +99,14 @@ def __repr__(self): location, position, result = self.get_operands() if location is not None: - return "%s(%r) # %r, %r (%s)" % ( - self.__class__.__name__, result, location, position, name(self.attr)) + return "%s(%r)%s # %r, %r (%s)" % ( + self.__class__.__name__, result, self.show_input(), location, position, name(self.attr)) elif result is not None: - return "%s(%r) # %s" % ( - self.__class__.__name__, result, name(self.attr)) + return "%s(%r)%s # %s" % ( + self.__class__.__name__, result, self.show_input(), name(self.attr)) else: - return "%s(...) # %s" % ( - self.__class__.__name__, name(self.attr)) + return "%s(...)%s # %s" % ( + self.__class__.__name__, self.show_input(), name(self.attr)) def get_operands(self): if isinstance(self.attr, Attr): @@ -126,7 +137,7 @@ "An instruction employing a constant." def __repr__(self): - return "%s(%r)" % (self.__class__.__name__, self.attr) + return "%s(%r)%s" % (self.__class__.__name__, self.attr, self.show_input()) def get_operand(self): return self.attr @@ -188,7 +199,7 @@ class RaiseException(Instruction): "Raise an exception." class CheckException(Instruction): "Check the raised exception against another." class PushHandler(Address): "Push an exception handler onto the handler stack." -class PopHandler(Address): "Pop an exception handler from the handler stack." +class PopHandler(Instruction): "Pop an exception handler from the handler stack." # General instructions.