# HG changeset patch # User Paul Boddie # Date 1220740483 -7200 # Node ID a36ce78d98d4a194293af34ec7d17e51e6544d01 # Parent 29103989ca365cd0f8c7d4970cb71ba5ecfe7090 Separated the optimisation methods out into a distinct class. Moved various class attributes around. diff -r 29103989ca36 -r a36ce78d98d4 micropython/__init__.py --- a/micropython/__init__.py Fri Sep 05 00:04:20 2008 +0200 +++ b/micropython/__init__.py Sun Sep 07 00:34:43 2008 +0200 @@ -50,7 +50,7 @@ class supports the generation of a program image. """ - supported_optimisations = micropython.ast.Translation.supported_optimisations + supported_optimisations = micropython.ast.Optimiser.supported_optimisations def __init__(self, path=None, verbose=0): diff -r 29103989ca36 -r a36ce78d98d4 micropython/ast.py --- a/micropython/ast.py Fri Sep 05 00:04:20 2008 +0200 +++ b/micropython/ast.py Sun Sep 07 00:34:43 2008 +0200 @@ -25,16 +25,386 @@ import compiler.ast from compiler.visitor import ASTVisitor +class Optimiser: + + "A code optimiser." + + supported_optimisations = [ + "constant_storage", "source_storage", "known_target", "self_access", + "temp_storage", "load_operations", "no_operations", "unused_results", + "superfluous_temp_operations" + ] + + def __init__(self, translation, optimisations=None): + + """ + Provide for the given 'translation' an optimiser for the desired + 'optimisations'. See the 'supported_optimisations' attribute of this + class for permitted values. + """ + + self.translation = translation + self.optimisations = set(optimisations or []) + + # Optimisation tests. + + def should_optimise_constant_storage(self): + return "constant_storage" in self.optimisations + + def should_optimise_source_storage(self): + return "source_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 + + def should_optimise_away_no_operations(self): + return "no_operations" in self.optimisations + + def should_optimise_away_superfluous_temp_operations(self): + return "superfluous_temp_operations" in self.optimisations + + def should_optimise_unused_results(self): + return "unused_results" 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 (typically a load + instruction). A simple input is something which would be represented by + a load operation from a CPU register or special memory location. + """ + + return isinstance(instruction, (LoadConst, LoadName, LoadTemp, LoadResult, LoadAddress)) + + def is_simple_input_user(self, instruction): + + """ + Return whether 'instruction' can use simple input from the current + value. Such instructions would, in a low-level implementation, be able + to have the simple input registers as operands. + """ + + return isinstance(instruction, ( + StoreTemp, StoreFrame, StoreResult, StoreException, # as the value being stored + LoadAddressContext, LoadAttr, LoadAttrIndex, # as the object being referenced + StoreAttr, StoreAttrIndex, StoreCallable, # as the object being referenced + LoadCallable, + TestIdentity, TestIdentityAddress, CheckSelf, # as one of the operands + CheckFrame, MakeObject, + LoadContext # as the object providing the result + )) + + def is_resultant_no_operation(self, instruction): + + """ + Return whether 'instruction' merely stores its input where the input + originally came from. + """ + + return ( + isinstance(instruction.input, LoadTemp) and isinstance(instruction, StoreTemp) and + instruction.input.attr == instruction.attr) or ( + isinstance(instruction.input, LoadResult) and isinstance(instruction, StoreResult) + ) + + def is_superfluous_temp_operation(self, instruction): + + """ + Return whether 'instruction' merely loads its input from a recent + temporary storage operation. + """ + + return ( + isinstance(instruction.source, LoadTemp) and isinstance(self.translation.active_source, StoreTemp) and + instruction.source.attr == self.translation.active_source.attr + ) + + def is_input(self, instruction): + + "Return whether 'instruction' provides an input." + + return isinstance(instruction, current_value_instructions) + + # Convenience tests on outputs. + + def have_constant_target(self): + + "Return whether the active instruction provides a constant target." + + return self.is_constant_target(self.translation.active) + + def have_constant_source(self): + + "Return whether the active instruction has a constant source." + + return self.is_constant_input(self.translation.active.source) + + # Convenience tests on inputs. + + def have_constant_input(self): + + "Return whether the active instruction provides a constant input." + + return self.is_constant_input(self.translation.active_value) + + have_known_target = have_constant_input + + def have_simple_input(self): + + "Return whether the active instruction provides a simple input." + + return self.is_simple_input(self.translation.active_value) + + def have_input(self): + + "Return whether the active instruction provides an input." + + return self.is_input(self.translation.active_value) + + def have_self_input(self): + + "Return whether the active instruction is a reference to self." + + return isinstance(self.translation.unit, Function) and \ + self.translation.unit.is_method() and isinstance(self.translation.active_value, LoadName) and \ + self.translation.active_value.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. + """ + + # LoadResult cannot be relied upon in general since the result register + # could be updated since first being referenced. + + return isinstance(self.translation.active_value, (LoadName, LoadTemp, LoadAddress, LoadConst)) or \ + isinstance(self.translation.active_value, LoadResult) and self.translation.active_value is self.translation.active + + def have_correct_self_for_target(self, context): + + "Return whether the 'context' is compatible with the current value." + + if context is not None and self.have_self_input(): + + parent = self.translation.unit.parent + if parent is context or parent.has_subclass(context) or context.has_subclass(parent): + return 1 + + return 0 + + # Optimisation methods. See the supported_optimisations class attribute. + + def optimise_constant_storage(self): + + """ + Where the last operation stores a constant into a target which is also + constant, optimise away both operations. + """ + + if self.should_optimise_constant_storage() and \ + self.have_constant_target() and \ + self.have_constant_source(): + + self.translation.remove_op() + return 1 + else: + return 0 + + def optimise_source_storage(self): + + """ + Where the source value in an assignment can be inserted into the + eventual target without intermediate storage, optimise away the storage + instruction. + """ + + if self.should_optimise_source_storage() and \ + self.translation.active_source is not None and \ + self.translation.active_source.source is None and \ + self.translation.active_source.input is None and \ + self.translation.active_source is self.translation.active: + + self.translation.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.translation.active_value + target = last.attr.value + context = last.attr.context + + return target, context + else: + return None + + def optimise_self_access(self, attrname, classes, node): + + """ + 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.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 + + 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(): + + removed = self.translation.active + self.translation.remove_active_value() + return removed + else: + return self.translation.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): + + self.translation.remove_active_value() + instruction.input = self.translation.active_value + + def optimise_away_no_operations(self, instruction): + + """ + Optimise away operations which just store their inputs in the place + the inputs originally came from. + """ + + if self.should_optimise_away_no_operations() and \ + self.is_resultant_no_operation(instruction): + + return 1 + else: + return 0 + + def optimise_away_superfluous_temp_operations(self, instruction): + + """ + Optimise away operations which just store temporary values for + immediate retrieval. + """ + + if self.should_optimise_away_superfluous_temp_operations() and \ + self.is_superfluous_temp_operation(instruction) and \ + self.translation.active_source == self.translation.active: + + instruction.source = self.translation.active_source.input + self.translation.remove_op() + + def optimise_unused_results(self): + + "Discard results which will not be used." + + if self.have_simple_input(): + self.translation.remove_active_value() + # Program visitors. class Translation(ASTVisitor): "A translated module." - supported_optimisations = [ - "constant_storage", "source_storage", "known_target", "self_access", - "temp_storage", "load_operations", "no_operations", "unused_results" - ] + supported_optimisations = Optimiser.supported_optimisations # Attribute access instructions, for use with the appropriate handlers. @@ -46,11 +416,6 @@ name_load_instructions = (LoadName, LoadAddress) name_store_instructions = (StoreName, StoreAddress) - # Instructions which affect the current value. - - current_value_instructions = (LoadConst, LoadName, LoadTemp, LoadAddress, LoadAddressContext, LoadAttr, LoadAttrIndex, - LoadCallable, LoadContext, LoadResult, LoadException, MakeObject) - def __init__(self, module, importer, optimisations=None): """ @@ -70,9 +435,9 @@ self.paramtable = self.importer.get_parameter_table() self.builtins = self.importer.modules.get("__builtins__") - # Desired optimisations. - - self.optimisations = set(optimisations or []) + # Optimisation. + + self.optimiser = Optimiser(self, optimisations) # The current unit being translated. @@ -289,7 +654,7 @@ # Optimise away constant storage if appropriate. - self._optimise_constant_storage() + self.optimiser.optimise_constant_storage() # Temporary storage administration. @@ -333,16 +698,17 @@ # Optimise load operations employed by this instruction. - self._optimise_load_operations(op) - if self._optimise_away_no_operations(op): + self.optimiser.optimise_load_operations(op) + if self.optimiser.optimise_away_no_operations(op): return + self.optimiser.optimise_away_superfluous_temp_operations(op) self.code.append(op) self.active = op # Record specific types of instructions for optimisation. - if isinstance(op, self.current_value_instructions): + if isinstance(op, current_value_instructions): self.active_value = op def remove_op(self): @@ -392,324 +758,6 @@ self.active_value = None self.active_source = None - # Optimisation tests. - - def _should_optimise_constant_storage(self): - return "constant_storage" in self.optimisations - - def _should_optimise_source_storage(self): - return "source_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 - - def _should_optimise_away_no_operations(self): - return "no_operations" in self.optimisations - - def _should_optimise_unused_results(self): - return "unused_results" 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 (typically a load - instruction). - """ - - return isinstance(instruction, (LoadConst, LoadName, LoadTemp, LoadResult, LoadAddress)) - - def _is_simple_input_user(self, instruction): - - "Return whether 'instruction' can use simple input from the current value." - - return isinstance(instruction, ( - StoreTemp, StoreFrame, StoreResult, StoreException, # as the value being stored - LoadAddressContext, LoadAttr, LoadAttrIndex, # as the object being referenced - StoreAttr, StoreAttrIndex, StoreCallable, # as the object being referenced - LoadCallable, - TestIdentity, TestIdentityAddress, CheckSelf, # as one of the operands - CheckFrame, MakeObject, - LoadContext # as the object providing the result - )) - - def _is_resultant_no_operation(self, instruction): - - """ - Return whether 'instruction' merely stores its input where the input - originally came from. - """ - - return ( - isinstance(instruction.input, LoadTemp) and isinstance(instruction, StoreTemp) and - instruction.input.attr == instruction.attr) or ( - isinstance(instruction.input, LoadResult) and isinstance(instruction, StoreResult) - ) - - def _is_input(self, instruction): - - "Return whether 'instruction' provides an input." - - return isinstance(instruction, self.current_value_instructions) - - # Convenience tests on outputs. - - def _have_constant_target(self): - - "Return whether the active instruction provides a constant target." - - return self._is_constant_target(self.active) - - def _have_constant_source(self): - - "Return whether the active instruction has a constant source." - - return self._is_constant_input(self.active.source) - - # Convenience tests on inputs. - - def _have_constant_input(self): - - "Return whether the active instruction provides a constant input." - - return self._is_constant_input(self.active_value) - - _have_known_target = _have_constant_input - - def _have_simple_input(self): - - "Return whether the active instruction provides a simple input." - - return self._is_simple_input(self.active_value) - - def _have_input(self): - - "Return whether the active instruction provides an input." - - return self._is_input(self.active_value) - - 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_value, LoadName) and \ - self.active_value.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. - """ - - # LoadResult cannot be relied upon in general since the result register - # could be updated since first being referenced. - - return isinstance(self.active_value, (LoadName, LoadTemp, LoadAddress, LoadConst)) or \ - isinstance(self.active_value, LoadResult) and self.active_value is self.active - - def _have_correct_self_for_target(self, context): - - "Return whether the 'context' is compatible with the current value." - - if context is not None and self._have_self_input(): - - parent = self.unit.parent - if parent is context or parent.has_subclass(context) or context.has_subclass(parent): - return 1 - - return 0 - - # Optimisation methods. See the supported_optimisations class attribute. - - def _optimise_constant_storage(self): - - """ - Where the last operation stores a constant into a target which is also - constant, optimise away both operations. - """ - - if self._should_optimise_constant_storage() and \ - self._have_constant_target() and \ - self._have_constant_source(): - - self.remove_op() - return 1 - else: - return 0 - - def _optimise_source_storage(self): - - """ - Where the source value in an assignment can be inserted into the - eventual target without intermediate storage, optimise away the storage - instruction. - """ - - if self._should_optimise_source_storage() and \ - self.active_source is not None and \ - self.active_source.source is None and \ - self.active_source.input is None and \ - self.active_source is self.active: - - 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.active_value - target = last.attr.value - context = last.attr.context - - return target, context - else: - return None - - def _optimise_self_access(self, attrname, classes, node): - - """ - 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] - - # 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 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(): - - removed = self.active - self.remove_active_value() - return removed - 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): - - self.remove_active_value() - instruction.input = self.active_value - - def _optimise_away_no_operations(self, instruction): - - """ - Optimise away operations which just store their inputs in the place - the inputs originally came from. - """ - - if self._should_optimise_away_no_operations() and \ - self._is_resultant_no_operation(instruction): - - return 1 - else: - return 0 - - def _optimise_unused_results(self): - - "Discard results which will not be used." - - if self._have_simple_input(): - self.remove_active_value() - # Visitor methods. def default(self, node, *args): @@ -741,7 +789,7 @@ # Where the last operation (defining the attribute owner) yields a # constant... - if self._have_constant_input(): + if self.optimiser.have_constant_input(): last = self.active_value # Get the details of the access. @@ -790,7 +838,7 @@ # see if the attribute is acceptably positioned and produce a direct # access to the attribute. - elif self._optimise_self_access(attrname, (AddressInstruction, AddressContextInstruction, AttrInstruction), node): + elif self.optimiser.optimise_self_access(attrname, (AddressInstruction, AddressContextInstruction, AttrInstruction), node): return # Otherwise, perform a normal operation. @@ -850,7 +898,7 @@ invocation target. """ - t = self._optimise_known_target() + t = self.optimiser.optimise_known_target() if t: target, context = t else: @@ -860,7 +908,7 @@ # NOTE: This may not be appropriate for class invocations # NOTE: (instantiation). - temp = self._optimise_temp_storage() + temp = self.optimiser.optimise_temp_storage() # Where a target or context are not known or where an instance is known # to be the context, load the context. @@ -1025,7 +1073,7 @@ # Drop any test if the target and the context are known. - if not self._have_correct_self_for_target(context): + if not self.optimiser.have_correct_self_for_target(context): continue_label = self.new_label() self.new_op(CheckSelf()) @@ -1255,7 +1303,7 @@ # Evaluate and store the operand in temporary storage. self.dispatch(node.expr) - temp = self._optimise_temp_storage() + temp = self.optimiser.optimise_temp_storage() # Produce the invocation. @@ -1265,7 +1313,7 @@ # Get the method on temp. self._generateAttr(node, method, self.attribute_load_instructions) - temp_method = self._optimise_temp_storage() + temp_method = self.optimiser.optimise_temp_storage() self._handleAttributeError(node, end_call_label) @@ -1317,12 +1365,12 @@ # Evaluate and store the left operand in temporary storage. self.dispatch(node.left) - temp1 = self._optimise_temp_storage() + temp1 = self.optimiser.optimise_temp_storage() # Evaluate and store the right operand in temporary storage. self.dispatch(node.right) - temp2 = self._optimise_temp_storage() + temp2 = self.optimiser.optimise_temp_storage() self._generateBinary(node, temp1, temp2, left_method, right_method) @@ -1378,7 +1426,7 @@ # Get method on temp1. self._generateAttr(node, method_name, self.attribute_load_instructions) - temp_method = self._optimise_temp_storage() + temp_method = self.optimiser.optimise_temp_storage() self._handleAttributeError(node, end_attempt_label) @@ -1412,7 +1460,7 @@ attribute access cannot be resolved at compile-time. """ - if not self._optimise_known_target(): + if not self.optimiser.optimise_known_target(): self.load_builtin("AttributeError", node) self.new_op(CheckException()) self.new_op(JumpIfTrue(end_call_label)) @@ -1446,7 +1494,7 @@ # NOTE: Using __bool__ instead of __nonzero__. self._generateAttr(node, "__bool__", self.attribute_load_instructions) - temp_method = self._optimise_temp_storage() + temp_method = self.optimiser.optimise_temp_storage() self._startCallFunc() self.new_op(temp) @@ -1544,7 +1592,7 @@ # Optimise away intermediate source storage. if top_level: - no_source = self._optimise_source_storage() + no_source = self.optimiser.optimise_source_storage() self._visitName(node, self.name_store_instructions) if not top_level or not no_source: self.set_source() @@ -1613,7 +1661,7 @@ temp_result = LoadTemp(temp_pos) self.dispatch(node.expr) - temp2 = self._optimise_temp_storage() + temp2 = self.optimiser.optimise_temp_storage() last_op = node.ops[-1] @@ -1623,7 +1671,7 @@ temp1 = temp2 self.dispatch(next_node) - temp2 = self._optimise_temp_storage() + temp2 = self.optimiser.optimise_temp_storage() # Use the appropriate mechanism, setting the boolean status for the # comparison. @@ -1655,7 +1703,7 @@ # Get method on temp2. self._generateAttr(node, "__contains__", self.attribute_load_instructions) - temp_method = self._optimise_temp_storage() + temp_method = self.optimiser.optimise_temp_storage() # Add arguments. # NOTE: No support for defaults. @@ -1705,7 +1753,7 @@ def visitDiscard(self, node): self.dispatch(node.expr) - self._optimise_unused_results() + self.optimiser.optimise_unused_results() def visitDiv(self, node): self._visitBinary(node, "__div__", "__rdiv__") @@ -1733,7 +1781,7 @@ self._doCallFunc(temp, target) self._endCallFunc(temp, target) - temp_iterator = self._optimise_temp_storage() + temp_iterator = self.optimiser.optimise_temp_storage() # In the loop... @@ -1934,7 +1982,7 @@ def visitNot(self, node): self.dispatch(node.expr) - temp = self._optimise_temp_storage() + temp = self.optimiser.optimise_temp_storage() self._generateTestBoolean(node.expr, temp) self.discard_temp(temp) @@ -1983,10 +2031,10 @@ self.dispatch(node.expr1) if node.expr2 is not None: - temp = self._optimise_temp_storage() + temp = self.optimiser.optimise_temp_storage() self.dispatch(node.expr2) - temp_arg = self._optimise_temp_storage() + temp_arg = self.optimiser.optimise_temp_storage() self._startCallFunc() self.new_op(temp_arg) diff -r 29103989ca36 -r a36ce78d98d4 micropython/rsvp.py --- a/micropython/rsvp.py Fri Sep 05 00:04:20 2008 +0200 +++ b/micropython/rsvp.py Sun Sep 07 00:34:43 2008 +0200 @@ -250,4 +250,12 @@ class TestIdentityAddress(Address): "Test whether the current value is identical to the given address, setting the boolean status." class InvertBoolean(Instruction): "Invert the boolean status." +# Instructions which affect the current value. + +current_value_instructions = ( + LoadConst, LoadName, LoadTemp, LoadAddress, LoadAddressContext, + LoadAttr, LoadAttrIndex, LoadCallable, LoadContext, LoadResult, + LoadException, MakeObject + ) + # vim: tabstop=4 expandtab shiftwidth=4