1.1 --- a/docs/optimisations.txt Sun Sep 28 19:59:32 2008 +0200
1.2 +++ b/docs/optimisations.txt Sun Sep 28 21:27:01 2008 +0200
1.3 @@ -2,40 +2,44 @@
1.4 ------------ ------------------------
1.5
1.6 constant_storage value instruction references a constant;
1.7 -(elimination) storage instruction references a constant;
1.8 - remove both instructions (currently a single
1.9 - merged instruction)
1.10 +(guidance) storage instruction references a constant;
1.11 + | indicate whether both instructions satisfy the
1.12 + | preconditions and should be removed (although
1.13 + | this currently involves just a single merged
1.14 + | instruction)
1.15
1.16 constant_accessor value instruction references a constant;
1.17 -(guidance) target name provided (for use in producing an
1.18 - address access instruction)
1.19 +(guidance) | target name provided (for use in producing an
1.20 + | address access instruction)
1.21
1.22 known_target value instruction references a constant;
1.23 -(guidance) target and context are provided (no instructions
1.24 - removed)
1.25 +(guidance) | target and context are provided (no instructions
1.26 + | are removed)
1.27
1.28 self_access value instruction references "self" in a method;
1.29 (guidance) specified attribute name always has the same
1.30 position;
1.31 - appropriate instruction generated
1.32 + | indicate whether an appropriate instruction can
1.33 + | be generated for the access
1.34
1.35 temp_storage value instruction is a simple input operation;
1.36 (elimination) value instruction is the last instruction;
1.37 -(guidance) remove the value instruction, provide the value
1.38 - instruction in place of a temporary storage
1.39 - reference
1.40 +(guidance) | remove the value instruction, provide the value
1.41 + | instruction in place of a temporary storage
1.42 + | reference
1.43
1.44 load_operations value instruction is a simple input operation;
1.45 (merge) value instruction is the last instruction;
1.46 current instruction uses simple input;
1.47 - remove the value instruction, make the value
1.48 - instruction the input to the current instruction
1.49 + | remove the value instruction, make the value
1.50 + | instruction the input to the current instruction
1.51
1.52 no_operations input to the current instruction loads from the
1.53 -(elimination) destination of the current instruction;
1.54 - omit the current instruction
1.55 +(guidance) destination of the current instruction;
1.56 + | indicate that the current instruction should be
1.57 + | omitted
1.58
1.59 unused_results value instruction is a simple input operation;
1.60 (elimination) value instruction is the final instruction of a
1.61 discarded expression;
1.62 - remove the value instruction
1.63 + | remove the value instruction
2.1 --- a/micropython/ast.py Sun Sep 28 19:59:32 2008 +0200
2.2 +++ b/micropython/ast.py Sun Sep 28 21:27:01 2008 +0200
2.3 @@ -79,18 +79,33 @@
2.4 self.loop_labels = []
2.5 self.exception_labels = []
2.6
2.7 - # The code itself. This is limited to the code for a particular block
2.8 - # being processed. Also retained is information about temporary values
2.9 - # and instructions which construct frames.
2.10 -
2.11 - self.code = None
2.12 - self.temp_positions = set()
2.13 - self.max_temp_position = -1
2.14 - self.frame_makers = []
2.15 + self.reset()
2.16
2.17 def __repr__(self):
2.18 return "Translation(%r)" % self.module
2.19
2.20 + def reset(self):
2.21 +
2.22 + "Reset the state of the translator."
2.23 +
2.24 + # The code itself. This is limited to the code for a particular block
2.25 + # being processed.
2.26 +
2.27 + self.code = []
2.28 +
2.29 + # Information about temporary values.
2.30 +
2.31 + self.temp_positions = set()
2.32 + self.max_temp_position = -1
2.33 +
2.34 + # Information about instructions which construct frames.
2.35 +
2.36 + self.frame_makers = []
2.37 +
2.38 + # Optimiser state must be reset for each unit.
2.39 +
2.40 + self.optimiser.reset()
2.41 +
2.42 def get_module_code(self, final=0):
2.43
2.44 """
2.45 @@ -99,9 +114,7 @@
2.46 """
2.47
2.48 self.unit = self.module
2.49 - self.code = []
2.50 - self.temp_positions = set()
2.51 - self.max_temp_position = -1
2.52 + self.reset()
2.53
2.54 if self.module.module is not None:
2.55 self.dispatch(self.module.module)
2.56 @@ -119,9 +132,7 @@
2.57 "Return the code for the given 'unit'."
2.58
2.59 self.unit = unit
2.60 - self.code = []
2.61 - self.temp_positions = set()
2.62 - self.max_temp_position = -1
2.63 + self.reset()
2.64
2.65 if unit.astnode is not None:
2.66 self.dispatch(unit.astnode)
2.67 @@ -134,9 +145,7 @@
2.68 "Return the code for the given class 'cls'."
2.69
2.70 self.unit = cls.get_instantiator()
2.71 - self.code = []
2.72 - self.temp_positions = set()
2.73 - self.max_temp_position = -1
2.74 + self.reset()
2.75
2.76 init_method = cls.get_init_method()
2.77
2.78 @@ -200,6 +209,9 @@
2.79 self.new_op(LoadAddress(self.get_builtin(name, node)))
2.80
2.81 def get_builtin_class(self, name, node):
2.82 +
2.83 + "Return the built-in class with the given 'name' for the given 'node'."
2.84 +
2.85 return self.get_builtin(name, node).value
2.86
2.87 def get_builtin(self, name, node):
2.88 @@ -259,6 +271,15 @@
2.89 # Assignment expression values.
2.90
2.91 def record_value(self, immediate=1):
2.92 +
2.93 + """
2.94 + Record the current active value for an assignment. If the optional
2.95 + 'immediate' parameter if set to a false value always allocates new
2.96 + temporary storage to hold the recorded value; otherwise, the
2.97 + value-providing instruction may be replicated in order to provide the
2.98 + active value later on.
2.99 + """
2.100 +
2.101 if immediate:
2.102 temp = self.optimiser.optimise_temp_storage()
2.103 else:
2.104 @@ -266,14 +287,21 @@
2.105 self.expr_temp.append(temp)
2.106
2.107 def discard_value(self):
2.108 +
2.109 + "Discard any temporary storage in use for the current assignment value."
2.110 +
2.111 self.discard_temp(self.expr_temp.pop())
2.112
2.113 def set_source(self):
2.114 +
2.115 + "Set the source of an assignment using the current assignment value."
2.116 +
2.117 self.optimiser.set_source(self.expr_temp[-1])
2.118
2.119 # Optimise away constant storage if appropriate.
2.120
2.121 - self.optimiser.optimise_constant_storage()
2.122 + if self.optimiser.optimise_constant_storage():
2.123 + self.remove_op()
2.124
2.125 # Temporary storage administration.
2.126
2.127 @@ -429,13 +457,49 @@
2.128 # see if the attribute is acceptably positioned and produce a direct
2.129 # access to the attribute.
2.130
2.131 - elif self.optimiser.optimise_self_access(attrname, (AddressInstruction, AddressContextInstruction, AttrInstruction), node):
2.132 + elif self.optimiser.optimise_self_access(self.unit, attrname):
2.133 +
2.134 + # Either generate an instruction operating on an instance attribute.
2.135 +
2.136 + try:
2.137 + attr = self.unit.parent.instance_attributes()[attrname]
2.138 + self.new_op(AttrInstruction(attr))
2.139 +
2.140 + # Or generate an instruction operating on a class attribute.
2.141 +
2.142 + except KeyError:
2.143 + attr = self.unit.parent.all_attributes()[attrname]
2.144 +
2.145 + # Switch the context if the class attribute is compatible with
2.146 + # the instance.
2.147 +
2.148 + if attr.defined_within_hierarchy():
2.149 +
2.150 + # Only permit loading (not storing) of class attributes via self.
2.151 +
2.152 + if AddressContextInstruction is not None:
2.153 + self.new_op(AddressContextInstruction(attr))
2.154 + else:
2.155 + raise TranslateError(self.module.full_name(), node,
2.156 + "Storing of class attribute %r via self not permitted." % attrname)
2.157 +
2.158 + # Preserve the context if the class attribute comes from an
2.159 + # incompatible class.
2.160 +
2.161 + else:
2.162 + if AddressInstruction is not None:
2.163 + self.new_op(AddressInstruction(attr))
2.164 + else:
2.165 + raise TranslateError(self.module.full_name(), node,
2.166 + "Storing of class attribute %r via self not permitted." % attrname)
2.167 +
2.168 return
2.169
2.170 # Otherwise, perform a normal operation.
2.171
2.172 try:
2.173 index = self.objtable.get_index(attrname)
2.174 +
2.175 except self.objtable.TableError:
2.176 raise TranslateError(self.module.full_name(), node,
2.177 "No attribute entry exists for name %r." % attrname)
2.178 @@ -1749,12 +1813,26 @@
2.179 def visitSlice(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Slice")
2.180
2.181 def visitStmt(self, node):
2.182 +
2.183 + "Process the collection of statements provided by 'node'."
2.184 +
2.185 for n in node.nodes:
2.186 +
2.187 + # Process the statement.
2.188 +
2.189 self.dispatch(n)
2.190 +
2.191 + # Discard temporary storage.
2.192 +
2.193 if self.temp_positions:
2.194 #print "Had temp", self.temp_positions
2.195 self.temp_positions = set()
2.196
2.197 + # Prevent incorrect optimisation by resetting the optimiser after
2.198 + # each statement.
2.199 +
2.200 + self.optimiser.reset()
2.201 +
2.202 def visitSub(self, node):
2.203 self._visitBinary(node, "__sub__", "__rsub__")
2.204
2.205 @@ -1856,10 +1934,6 @@
2.206 self.set_label(exit_label)
2.207 self.drop_loop_labels()
2.208
2.209 - # Prevent incorrect optimisation.
2.210 -
2.211 - self.optimiser.reset()
2.212 -
2.213 def visitWith(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "With")
2.214
2.215 def visitYield(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Yield")
3.1 --- a/micropython/opt.py Sun Sep 28 19:59:32 2008 +0200
3.2 +++ b/micropython/opt.py Sun Sep 28 21:27:01 2008 +0200
3.3 @@ -82,7 +82,10 @@
3.4
3.5 def remove_active_value(self):
3.6
3.7 - "Remove the value-providing active instruction if appropriate."
3.8 + """
3.9 + Remove the value-providing active instruction from the generated code,
3.10 + if appropriate, but keep a record of the active instruction itself.
3.11 + """
3.12
3.13 if self.active_value is self.active:
3.14 removed = self.active
3.15 @@ -275,17 +278,12 @@
3.16
3.17 """
3.18 Where the last operation stores a constant into a target which is also
3.19 - constant, optimise away both operations.
3.20 + constant, indicate that both operations should be optimised away.
3.21 """
3.22
3.23 - if self.should_optimise_constant_storage() and \
3.24 + return self.should_optimise_constant_storage() and \
3.25 self.have_constant_target() and \
3.26 - self.have_constant_source():
3.27 -
3.28 - self.translation.remove_op()
3.29 - return 1
3.30 - else:
3.31 - return 0
3.32 + self.have_constant_source()
3.33
3.34 def optimise_constant_accessor(self):
3.35
3.36 @@ -331,57 +329,16 @@
3.37 else:
3.38 return None
3.39
3.40 - def optimise_self_access(self, attrname, classes, node):
3.41 + def optimise_self_access(self, unit, attrname):
3.42
3.43 """
3.44 - Where the provided 'attrname' accesses an attribute which occupies the
3.45 - same position in all possible objects which can be accessed, generate an
3.46 - instruction using one of the given 'classes', accessing the attribute
3.47 - directly.
3.48 + Return whether code in the given 'unit' is able to access the given
3.49 + 'attrname' through the same position in all possible objects which might
3.50 + be accessed.
3.51 """
3.52
3.53 - AddressInstruction, AddressContextInstruction, AttrInstruction = classes
3.54 -
3.55 - if self.should_optimise_self_access() and self.have_self_input() and \
3.56 - not self.translation.unit.is_relocated(attrname):
3.57 -
3.58 - # Either generate an instruction operating on an instance attribute.
3.59 -
3.60 - try:
3.61 - attr = self.translation.unit.parent.instance_attributes()[attrname]
3.62 - self.translation.new_op(AttrInstruction(attr))
3.63 -
3.64 - # Or generate an instruction operating on a class attribute.
3.65 -
3.66 - except KeyError:
3.67 - attr = self.translation.unit.parent.all_attributes()[attrname]
3.68 -
3.69 - # Switch the context if the class attribute is compatible with
3.70 - # the instance.
3.71 -
3.72 - if attr.defined_within_hierarchy():
3.73 -
3.74 - # Only permit loading (not storing) of class attributes via self.
3.75 -
3.76 - if AddressContextInstruction is not None:
3.77 - self.translation.new_op(AddressContextInstruction(attr))
3.78 - else:
3.79 - raise TranslateError(self.translation.module.full_name(), node,
3.80 - "Storing of class attribute %r via self not permitted." % attrname)
3.81 -
3.82 - # Preserve the context if the class attribute comes from an
3.83 - # incompatible class.
3.84 -
3.85 - else:
3.86 - if AddressInstruction is not None:
3.87 - self.translation.new_op(AddressInstruction(attr))
3.88 - else:
3.89 - raise TranslateError(self.translation.module.full_name(), node,
3.90 - "Storing of class attribute %r via self not permitted." % attrname)
3.91 -
3.92 - return 1
3.93 - else:
3.94 - return 0
3.95 + return self.should_optimise_self_access() and \
3.96 + self.have_self_input() and not unit.is_relocated(attrname)
3.97
3.98 def optimise_temp_storage(self):
3.99
3.100 @@ -433,12 +390,8 @@
3.101 the inputs originally came from.
3.102 """
3.103
3.104 - if self.should_optimise_away_no_operations() and \
3.105 - self.is_resultant_no_operation(instruction):
3.106 -
3.107 - return 1
3.108 - else:
3.109 - return 0
3.110 + return self.should_optimise_away_no_operations() and \
3.111 + self.is_resultant_no_operation(instruction)
3.112
3.113 def optimise_unused_results(self):
3.114