1.1 --- a/micropython/ast.py Fri Sep 05 00:04:20 2008 +0200
1.2 +++ b/micropython/ast.py Sun Sep 07 00:34:43 2008 +0200
1.3 @@ -25,16 +25,386 @@
1.4 import compiler.ast
1.5 from compiler.visitor import ASTVisitor
1.6
1.7 +class Optimiser:
1.8 +
1.9 + "A code optimiser."
1.10 +
1.11 + supported_optimisations = [
1.12 + "constant_storage", "source_storage", "known_target", "self_access",
1.13 + "temp_storage", "load_operations", "no_operations", "unused_results",
1.14 + "superfluous_temp_operations"
1.15 + ]
1.16 +
1.17 + def __init__(self, translation, optimisations=None):
1.18 +
1.19 + """
1.20 + Provide for the given 'translation' an optimiser for the desired
1.21 + 'optimisations'. See the 'supported_optimisations' attribute of this
1.22 + class for permitted values.
1.23 + """
1.24 +
1.25 + self.translation = translation
1.26 + self.optimisations = set(optimisations or [])
1.27 +
1.28 + # Optimisation tests.
1.29 +
1.30 + def should_optimise_constant_storage(self):
1.31 + return "constant_storage" in self.optimisations
1.32 +
1.33 + def should_optimise_source_storage(self):
1.34 + return "source_storage" in self.optimisations
1.35 +
1.36 + def should_optimise_known_target(self):
1.37 + return "known_target" in self.optimisations
1.38 +
1.39 + def should_optimise_self_access(self):
1.40 + return "self_access" in self.optimisations
1.41 +
1.42 + def should_optimise_temp_storage(self):
1.43 + return "temp_storage" in self.optimisations
1.44 +
1.45 + def should_optimise_load_operations(self):
1.46 + return "load_operations" in self.optimisations
1.47 +
1.48 + def should_optimise_away_no_operations(self):
1.49 + return "no_operations" in self.optimisations
1.50 +
1.51 + def should_optimise_away_superfluous_temp_operations(self):
1.52 + return "superfluous_temp_operations" in self.optimisations
1.53 +
1.54 + def should_optimise_unused_results(self):
1.55 + return "unused_results" in self.optimisations
1.56 +
1.57 + # Simple tests.
1.58 +
1.59 + def is_constant_input(self, instruction):
1.60 +
1.61 + "Return whether 'instruction' provides a constant input."
1.62 +
1.63 + return isinstance(instruction, LoadAddress) and instruction.attr.assignments == 1 or \
1.64 + isinstance(instruction, LoadConst)
1.65 +
1.66 + def is_constant_target(self, instruction):
1.67 +
1.68 + "Return whether 'instruction' provides a constant target."
1.69 +
1.70 + return isinstance(instruction, (StoreName, StoreAddress)) and \
1.71 + instruction.attr.assignments == 1
1.72 +
1.73 + def is_simple_input(self, instruction):
1.74 +
1.75 + """
1.76 + Return whether 'instruction' provides a simple input (typically a load
1.77 + instruction). A simple input is something which would be represented by
1.78 + a load operation from a CPU register or special memory location.
1.79 + """
1.80 +
1.81 + return isinstance(instruction, (LoadConst, LoadName, LoadTemp, LoadResult, LoadAddress))
1.82 +
1.83 + def is_simple_input_user(self, instruction):
1.84 +
1.85 + """
1.86 + Return whether 'instruction' can use simple input from the current
1.87 + value. Such instructions would, in a low-level implementation, be able
1.88 + to have the simple input registers as operands.
1.89 + """
1.90 +
1.91 + return isinstance(instruction, (
1.92 + StoreTemp, StoreFrame, StoreResult, StoreException, # as the value being stored
1.93 + LoadAddressContext, LoadAttr, LoadAttrIndex, # as the object being referenced
1.94 + StoreAttr, StoreAttrIndex, StoreCallable, # as the object being referenced
1.95 + LoadCallable,
1.96 + TestIdentity, TestIdentityAddress, CheckSelf, # as one of the operands
1.97 + CheckFrame, MakeObject,
1.98 + LoadContext # as the object providing the result
1.99 + ))
1.100 +
1.101 + def is_resultant_no_operation(self, instruction):
1.102 +
1.103 + """
1.104 + Return whether 'instruction' merely stores its input where the input
1.105 + originally came from.
1.106 + """
1.107 +
1.108 + return (
1.109 + isinstance(instruction.input, LoadTemp) and isinstance(instruction, StoreTemp) and
1.110 + instruction.input.attr == instruction.attr) or (
1.111 + isinstance(instruction.input, LoadResult) and isinstance(instruction, StoreResult)
1.112 + )
1.113 +
1.114 + def is_superfluous_temp_operation(self, instruction):
1.115 +
1.116 + """
1.117 + Return whether 'instruction' merely loads its input from a recent
1.118 + temporary storage operation.
1.119 + """
1.120 +
1.121 + return (
1.122 + isinstance(instruction.source, LoadTemp) and isinstance(self.translation.active_source, StoreTemp) and
1.123 + instruction.source.attr == self.translation.active_source.attr
1.124 + )
1.125 +
1.126 + def is_input(self, instruction):
1.127 +
1.128 + "Return whether 'instruction' provides an input."
1.129 +
1.130 + return isinstance(instruction, current_value_instructions)
1.131 +
1.132 + # Convenience tests on outputs.
1.133 +
1.134 + def have_constant_target(self):
1.135 +
1.136 + "Return whether the active instruction provides a constant target."
1.137 +
1.138 + return self.is_constant_target(self.translation.active)
1.139 +
1.140 + def have_constant_source(self):
1.141 +
1.142 + "Return whether the active instruction has a constant source."
1.143 +
1.144 + return self.is_constant_input(self.translation.active.source)
1.145 +
1.146 + # Convenience tests on inputs.
1.147 +
1.148 + def have_constant_input(self):
1.149 +
1.150 + "Return whether the active instruction provides a constant input."
1.151 +
1.152 + return self.is_constant_input(self.translation.active_value)
1.153 +
1.154 + have_known_target = have_constant_input
1.155 +
1.156 + def have_simple_input(self):
1.157 +
1.158 + "Return whether the active instruction provides a simple input."
1.159 +
1.160 + return self.is_simple_input(self.translation.active_value)
1.161 +
1.162 + def have_input(self):
1.163 +
1.164 + "Return whether the active instruction provides an input."
1.165 +
1.166 + return self.is_input(self.translation.active_value)
1.167 +
1.168 + def have_self_input(self):
1.169 +
1.170 + "Return whether the active instruction is a reference to self."
1.171 +
1.172 + return isinstance(self.translation.unit, Function) and \
1.173 + self.translation.unit.is_method() and isinstance(self.translation.active_value, LoadName) and \
1.174 + self.translation.active_value.attr.name == "self"
1.175 +
1.176 + def have_temp_compatible_access(self):
1.177 +
1.178 + """
1.179 + Indicate whether the active instruction can be used in place of access
1.180 + to a temporary variable retaining the result of the last instruction.
1.181 + """
1.182 +
1.183 + # LoadResult cannot be relied upon in general since the result register
1.184 + # could be updated since first being referenced.
1.185 +
1.186 + return isinstance(self.translation.active_value, (LoadName, LoadTemp, LoadAddress, LoadConst)) or \
1.187 + isinstance(self.translation.active_value, LoadResult) and self.translation.active_value is self.translation.active
1.188 +
1.189 + def have_correct_self_for_target(self, context):
1.190 +
1.191 + "Return whether the 'context' is compatible with the current value."
1.192 +
1.193 + if context is not None and self.have_self_input():
1.194 +
1.195 + parent = self.translation.unit.parent
1.196 + if parent is context or parent.has_subclass(context) or context.has_subclass(parent):
1.197 + return 1
1.198 +
1.199 + return 0
1.200 +
1.201 + # Optimisation methods. See the supported_optimisations class attribute.
1.202 +
1.203 + def optimise_constant_storage(self):
1.204 +
1.205 + """
1.206 + Where the last operation stores a constant into a target which is also
1.207 + constant, optimise away both operations.
1.208 + """
1.209 +
1.210 + if self.should_optimise_constant_storage() and \
1.211 + self.have_constant_target() and \
1.212 + self.have_constant_source():
1.213 +
1.214 + self.translation.remove_op()
1.215 + return 1
1.216 + else:
1.217 + return 0
1.218 +
1.219 + def optimise_source_storage(self):
1.220 +
1.221 + """
1.222 + Where the source value in an assignment can be inserted into the
1.223 + eventual target without intermediate storage, optimise away the storage
1.224 + instruction.
1.225 + """
1.226 +
1.227 + if self.should_optimise_source_storage() and \
1.228 + self.translation.active_source is not None and \
1.229 + self.translation.active_source.source is None and \
1.230 + self.translation.active_source.input is None and \
1.231 + self.translation.active_source is self.translation.active:
1.232 +
1.233 + self.translation.remove_op()
1.234 + return 1
1.235 + else:
1.236 + return 0
1.237 +
1.238 + def optimise_known_target(self):
1.239 +
1.240 + """
1.241 + Where the target of an invocation is known, provide information about it
1.242 + and its context. If a class is being invoked and the conditions are
1.243 + appropriate, get information about the specific initialiser.
1.244 + """
1.245 +
1.246 + if self.should_optimise_known_target() and self.have_known_target():
1.247 + last = self.translation.active_value
1.248 + target = last.attr.value
1.249 + context = last.attr.context
1.250 +
1.251 + return target, context
1.252 + else:
1.253 + return None
1.254 +
1.255 + def optimise_self_access(self, attrname, classes, node):
1.256 +
1.257 + """
1.258 + Where the provided 'attrname' accesses an attribute which occupies the
1.259 + same position in all possible objects which can be accessed, generate an
1.260 + instruction using one of the given 'classes', accessing the attribute
1.261 + directly.
1.262 + """
1.263 +
1.264 + AddressInstruction, AddressContextInstruction, AttrInstruction = classes
1.265 +
1.266 + if self.should_optimise_self_access() and self.have_self_input() and \
1.267 + not self.translation.unit.is_relocated(attrname):
1.268 +
1.269 + # Either generate an instruction operating on an instance attribute.
1.270 +
1.271 + try:
1.272 + attr = self.translation.unit.parent.instance_attributes()[attrname]
1.273 + self.translation.new_op(AttrInstruction(attr))
1.274 +
1.275 + # Or generate an instruction operating on a class attribute.
1.276 +
1.277 + except KeyError:
1.278 + attr = self.translation.unit.parent.all_attributes()[attrname]
1.279 +
1.280 + # Switch the context if the class attribute is compatible with
1.281 + # the instance.
1.282 +
1.283 + if attr.defined_within_hierarchy():
1.284 +
1.285 + # Only permit loading (not storing) of class attributes via self.
1.286 +
1.287 + if AddressContextInstruction is not None:
1.288 + self.translation.new_op(AddressContextInstruction(attr))
1.289 + else:
1.290 + raise TranslateError(self.translation.module.full_name(), node,
1.291 + "Storing of class attribute %r via self not permitted." % attrname)
1.292 +
1.293 + # Preserve the context if the class attribute comes from an
1.294 + # incompatible class.
1.295 +
1.296 + else:
1.297 + if AddressInstruction is not None:
1.298 + self.translation.new_op(AddressInstruction(attr))
1.299 + else:
1.300 + raise TranslateError(self.translation.module.full_name(), node,
1.301 + "Storing of class attribute %r via self not permitted." % attrname)
1.302 +
1.303 + return 1
1.304 + else:
1.305 + return 0
1.306 +
1.307 + def optimise_temp_storage(self):
1.308 +
1.309 + """
1.310 + Where the next operation would involve storing a value into temporary
1.311 + storage at 'temp_position', record and remove any simple instruction
1.312 + which produced the value to be stored such that instead of subsequently
1.313 + accessing the temporary storage, that instruction is substituted.
1.314 +
1.315 + If no optimisation can be achieved, a StoreTemp instruction is produced
1.316 + and the appropriate LoadTemp instruction is returned.
1.317 +
1.318 + Restriction: for use only in situations where the source of the
1.319 + temporary data will not be disturbed between its first access and its
1.320 + subsequent use.
1.321 + """
1.322 +
1.323 + if self.should_optimise_temp_storage() and \
1.324 + self.have_temp_compatible_access():
1.325 +
1.326 + removed = self.translation.active
1.327 + self.translation.remove_active_value()
1.328 + return removed
1.329 + else:
1.330 + return self.translation.get_temp()
1.331 +
1.332 + def optimise_load_operations(self, instruction):
1.333 +
1.334 + """
1.335 + Incorporate previous load operations into other operations.
1.336 + """
1.337 +
1.338 + if self.should_optimise_load_operations() and \
1.339 + self.have_simple_input() and \
1.340 + self.is_simple_input_user(instruction):
1.341 +
1.342 + self.translation.remove_active_value()
1.343 + instruction.input = self.translation.active_value
1.344 +
1.345 + def optimise_away_no_operations(self, instruction):
1.346 +
1.347 + """
1.348 + Optimise away operations which just store their inputs in the place
1.349 + the inputs originally came from.
1.350 + """
1.351 +
1.352 + if self.should_optimise_away_no_operations() and \
1.353 + self.is_resultant_no_operation(instruction):
1.354 +
1.355 + return 1
1.356 + else:
1.357 + return 0
1.358 +
1.359 + def optimise_away_superfluous_temp_operations(self, instruction):
1.360 +
1.361 + """
1.362 + Optimise away operations which just store temporary values for
1.363 + immediate retrieval.
1.364 + """
1.365 +
1.366 + if self.should_optimise_away_superfluous_temp_operations() and \
1.367 + self.is_superfluous_temp_operation(instruction) and \
1.368 + self.translation.active_source == self.translation.active:
1.369 +
1.370 + instruction.source = self.translation.active_source.input
1.371 + self.translation.remove_op()
1.372 +
1.373 + def optimise_unused_results(self):
1.374 +
1.375 + "Discard results which will not be used."
1.376 +
1.377 + if self.have_simple_input():
1.378 + self.translation.remove_active_value()
1.379 +
1.380 # Program visitors.
1.381
1.382 class Translation(ASTVisitor):
1.383
1.384 "A translated module."
1.385
1.386 - supported_optimisations = [
1.387 - "constant_storage", "source_storage", "known_target", "self_access",
1.388 - "temp_storage", "load_operations", "no_operations", "unused_results"
1.389 - ]
1.390 + supported_optimisations = Optimiser.supported_optimisations
1.391
1.392 # Attribute access instructions, for use with the appropriate handlers.
1.393
1.394 @@ -46,11 +416,6 @@
1.395 name_load_instructions = (LoadName, LoadAddress)
1.396 name_store_instructions = (StoreName, StoreAddress)
1.397
1.398 - # Instructions which affect the current value.
1.399 -
1.400 - current_value_instructions = (LoadConst, LoadName, LoadTemp, LoadAddress, LoadAddressContext, LoadAttr, LoadAttrIndex,
1.401 - LoadCallable, LoadContext, LoadResult, LoadException, MakeObject)
1.402 -
1.403 def __init__(self, module, importer, optimisations=None):
1.404
1.405 """
1.406 @@ -70,9 +435,9 @@
1.407 self.paramtable = self.importer.get_parameter_table()
1.408 self.builtins = self.importer.modules.get("__builtins__")
1.409
1.410 - # Desired optimisations.
1.411 -
1.412 - self.optimisations = set(optimisations or [])
1.413 + # Optimisation.
1.414 +
1.415 + self.optimiser = Optimiser(self, optimisations)
1.416
1.417 # The current unit being translated.
1.418
1.419 @@ -289,7 +654,7 @@
1.420
1.421 # Optimise away constant storage if appropriate.
1.422
1.423 - self._optimise_constant_storage()
1.424 + self.optimiser.optimise_constant_storage()
1.425
1.426 # Temporary storage administration.
1.427
1.428 @@ -333,16 +698,17 @@
1.429
1.430 # Optimise load operations employed by this instruction.
1.431
1.432 - self._optimise_load_operations(op)
1.433 - if self._optimise_away_no_operations(op):
1.434 + self.optimiser.optimise_load_operations(op)
1.435 + if self.optimiser.optimise_away_no_operations(op):
1.436 return
1.437 + self.optimiser.optimise_away_superfluous_temp_operations(op)
1.438
1.439 self.code.append(op)
1.440 self.active = op
1.441
1.442 # Record specific types of instructions for optimisation.
1.443
1.444 - if isinstance(op, self.current_value_instructions):
1.445 + if isinstance(op, current_value_instructions):
1.446 self.active_value = op
1.447
1.448 def remove_op(self):
1.449 @@ -392,324 +758,6 @@
1.450 self.active_value = None
1.451 self.active_source = None
1.452
1.453 - # Optimisation tests.
1.454 -
1.455 - def _should_optimise_constant_storage(self):
1.456 - return "constant_storage" in self.optimisations
1.457 -
1.458 - def _should_optimise_source_storage(self):
1.459 - return "source_storage" in self.optimisations
1.460 -
1.461 - def _should_optimise_known_target(self):
1.462 - return "known_target" in self.optimisations
1.463 -
1.464 - def _should_optimise_self_access(self):
1.465 - return "self_access" in self.optimisations
1.466 -
1.467 - def _should_optimise_temp_storage(self):
1.468 - return "temp_storage" in self.optimisations
1.469 -
1.470 - def _should_optimise_load_operations(self):
1.471 - return "load_operations" in self.optimisations
1.472 -
1.473 - def _should_optimise_away_no_operations(self):
1.474 - return "no_operations" in self.optimisations
1.475 -
1.476 - def _should_optimise_unused_results(self):
1.477 - return "unused_results" in self.optimisations
1.478 -
1.479 - # Simple tests.
1.480 -
1.481 - def _is_constant_input(self, instruction):
1.482 -
1.483 - "Return whether 'instruction' provides a constant input."
1.484 -
1.485 - return isinstance(instruction, LoadAddress) and instruction.attr.assignments == 1 or \
1.486 - isinstance(instruction, LoadConst)
1.487 -
1.488 - def _is_constant_target(self, instruction):
1.489 -
1.490 - "Return whether 'instruction' provides a constant target."
1.491 -
1.492 - return isinstance(instruction, (StoreName, StoreAddress)) and \
1.493 - instruction.attr.assignments == 1
1.494 -
1.495 - def _is_simple_input(self, instruction):
1.496 -
1.497 - """
1.498 - Return whether 'instruction' provides a simple input (typically a load
1.499 - instruction).
1.500 - """
1.501 -
1.502 - return isinstance(instruction, (LoadConst, LoadName, LoadTemp, LoadResult, LoadAddress))
1.503 -
1.504 - def _is_simple_input_user(self, instruction):
1.505 -
1.506 - "Return whether 'instruction' can use simple input from the current value."
1.507 -
1.508 - return isinstance(instruction, (
1.509 - StoreTemp, StoreFrame, StoreResult, StoreException, # as the value being stored
1.510 - LoadAddressContext, LoadAttr, LoadAttrIndex, # as the object being referenced
1.511 - StoreAttr, StoreAttrIndex, StoreCallable, # as the object being referenced
1.512 - LoadCallable,
1.513 - TestIdentity, TestIdentityAddress, CheckSelf, # as one of the operands
1.514 - CheckFrame, MakeObject,
1.515 - LoadContext # as the object providing the result
1.516 - ))
1.517 -
1.518 - def _is_resultant_no_operation(self, instruction):
1.519 -
1.520 - """
1.521 - Return whether 'instruction' merely stores its input where the input
1.522 - originally came from.
1.523 - """
1.524 -
1.525 - return (
1.526 - isinstance(instruction.input, LoadTemp) and isinstance(instruction, StoreTemp) and
1.527 - instruction.input.attr == instruction.attr) or (
1.528 - isinstance(instruction.input, LoadResult) and isinstance(instruction, StoreResult)
1.529 - )
1.530 -
1.531 - def _is_input(self, instruction):
1.532 -
1.533 - "Return whether 'instruction' provides an input."
1.534 -
1.535 - return isinstance(instruction, self.current_value_instructions)
1.536 -
1.537 - # Convenience tests on outputs.
1.538 -
1.539 - def _have_constant_target(self):
1.540 -
1.541 - "Return whether the active instruction provides a constant target."
1.542 -
1.543 - return self._is_constant_target(self.active)
1.544 -
1.545 - def _have_constant_source(self):
1.546 -
1.547 - "Return whether the active instruction has a constant source."
1.548 -
1.549 - return self._is_constant_input(self.active.source)
1.550 -
1.551 - # Convenience tests on inputs.
1.552 -
1.553 - def _have_constant_input(self):
1.554 -
1.555 - "Return whether the active instruction provides a constant input."
1.556 -
1.557 - return self._is_constant_input(self.active_value)
1.558 -
1.559 - _have_known_target = _have_constant_input
1.560 -
1.561 - def _have_simple_input(self):
1.562 -
1.563 - "Return whether the active instruction provides a simple input."
1.564 -
1.565 - return self._is_simple_input(self.active_value)
1.566 -
1.567 - def _have_input(self):
1.568 -
1.569 - "Return whether the active instruction provides an input."
1.570 -
1.571 - return self._is_input(self.active_value)
1.572 -
1.573 - def _have_self_input(self):
1.574 -
1.575 - "Return whether the active instruction is a reference to self."
1.576 -
1.577 - return isinstance(self.unit, Function) and \
1.578 - self.unit.is_method() and isinstance(self.active_value, LoadName) and \
1.579 - self.active_value.attr.name == "self"
1.580 -
1.581 - def _have_temp_compatible_access(self):
1.582 -
1.583 - """
1.584 - Indicate whether the active instruction can be used in place of access
1.585 - to a temporary variable retaining the result of the last instruction.
1.586 - """
1.587 -
1.588 - # LoadResult cannot be relied upon in general since the result register
1.589 - # could be updated since first being referenced.
1.590 -
1.591 - return isinstance(self.active_value, (LoadName, LoadTemp, LoadAddress, LoadConst)) or \
1.592 - isinstance(self.active_value, LoadResult) and self.active_value is self.active
1.593 -
1.594 - def _have_correct_self_for_target(self, context):
1.595 -
1.596 - "Return whether the 'context' is compatible with the current value."
1.597 -
1.598 - if context is not None and self._have_self_input():
1.599 -
1.600 - parent = self.unit.parent
1.601 - if parent is context or parent.has_subclass(context) or context.has_subclass(parent):
1.602 - return 1
1.603 -
1.604 - return 0
1.605 -
1.606 - # Optimisation methods. See the supported_optimisations class attribute.
1.607 -
1.608 - def _optimise_constant_storage(self):
1.609 -
1.610 - """
1.611 - Where the last operation stores a constant into a target which is also
1.612 - constant, optimise away both operations.
1.613 - """
1.614 -
1.615 - if self._should_optimise_constant_storage() and \
1.616 - self._have_constant_target() and \
1.617 - self._have_constant_source():
1.618 -
1.619 - self.remove_op()
1.620 - return 1
1.621 - else:
1.622 - return 0
1.623 -
1.624 - def _optimise_source_storage(self):
1.625 -
1.626 - """
1.627 - Where the source value in an assignment can be inserted into the
1.628 - eventual target without intermediate storage, optimise away the storage
1.629 - instruction.
1.630 - """
1.631 -
1.632 - if self._should_optimise_source_storage() and \
1.633 - self.active_source is not None and \
1.634 - self.active_source.source is None and \
1.635 - self.active_source.input is None and \
1.636 - self.active_source is self.active:
1.637 -
1.638 - self.remove_op()
1.639 - return 1
1.640 - else:
1.641 - return 0
1.642 -
1.643 - def _optimise_known_target(self):
1.644 -
1.645 - """
1.646 - Where the target of an invocation is known, provide information about it
1.647 - and its context. If a class is being invoked and the conditions are
1.648 - appropriate, get information about the specific initialiser.
1.649 - """
1.650 -
1.651 - if self._should_optimise_known_target() and self._have_known_target():
1.652 - last = self.active_value
1.653 - target = last.attr.value
1.654 - context = last.attr.context
1.655 -
1.656 - return target, context
1.657 - else:
1.658 - return None
1.659 -
1.660 - def _optimise_self_access(self, attrname, classes, node):
1.661 -
1.662 - """
1.663 - Where the provided 'attrname' accesses an attribute which occupies the
1.664 - same position in all possible objects which can be accessed, generate an
1.665 - instruction using one of the given 'classes', accessing the attribute
1.666 - directly.
1.667 - """
1.668 -
1.669 - AddressInstruction, AddressContextInstruction, AttrInstruction = classes
1.670 -
1.671 - if self._should_optimise_self_access() and self._have_self_input() and \
1.672 - not self.unit.is_relocated(attrname):
1.673 -
1.674 - # Either generate an instruction operating on an instance attribute.
1.675 -
1.676 - try:
1.677 - attr = self.unit.parent.instance_attributes()[attrname]
1.678 - self.new_op(AttrInstruction(attr))
1.679 -
1.680 - # Or generate an instruction operating on a class attribute.
1.681 -
1.682 - except KeyError:
1.683 - attr = self.unit.parent.all_attributes()[attrname]
1.684 -
1.685 - # Switch the context if the class attribute is compatible with
1.686 - # the instance.
1.687 -
1.688 - if attr.defined_within_hierarchy():
1.689 -
1.690 - # Only permit loading (not storing) of class attributes via self.
1.691 -
1.692 - if AddressContextInstruction is not None:
1.693 - self.new_op(AddressContextInstruction(attr))
1.694 - else:
1.695 - raise TranslateError(self.module.full_name(), node,
1.696 - "Storing of class attribute %r via self not permitted." % attrname)
1.697 -
1.698 - # Preserve the context if the class attribute comes from an
1.699 - # incompatible class.
1.700 -
1.701 - else:
1.702 - if AddressInstruction is not None:
1.703 - self.new_op(AddressInstruction(attr))
1.704 - else:
1.705 - raise TranslateError(self.module.full_name(), node,
1.706 - "Storing of class attribute %r via self not permitted." % attrname)
1.707 -
1.708 - return 1
1.709 - else:
1.710 - return 0
1.711 -
1.712 - def _optimise_temp_storage(self):
1.713 -
1.714 - """
1.715 - Where the next operation would involve storing a value into temporary
1.716 - storage at 'temp_position', record and remove any simple instruction
1.717 - which produced the value to be stored such that instead of subsequently
1.718 - accessing the temporary storage, that instruction is substituted.
1.719 -
1.720 - If no optimisation can be achieved, a StoreTemp instruction is produced
1.721 - and the appropriate LoadTemp instruction is returned.
1.722 -
1.723 - Restriction: for use only in situations where the source of the
1.724 - temporary data will not be disturbed between its first access and its
1.725 - subsequent use.
1.726 - """
1.727 -
1.728 - if self._should_optimise_temp_storage() and \
1.729 - self._have_temp_compatible_access():
1.730 -
1.731 - removed = self.active
1.732 - self.remove_active_value()
1.733 - return removed
1.734 - else:
1.735 - return self.get_temp()
1.736 -
1.737 - def _optimise_load_operations(self, instruction):
1.738 -
1.739 - """
1.740 - Incorporate previous load operations into other operations.
1.741 - """
1.742 -
1.743 - if self._should_optimise_load_operations() and \
1.744 - self._have_simple_input() and \
1.745 - self._is_simple_input_user(instruction):
1.746 -
1.747 - self.remove_active_value()
1.748 - instruction.input = self.active_value
1.749 -
1.750 - def _optimise_away_no_operations(self, instruction):
1.751 -
1.752 - """
1.753 - Optimise away operations which just store their inputs in the place
1.754 - the inputs originally came from.
1.755 - """
1.756 -
1.757 - if self._should_optimise_away_no_operations() and \
1.758 - self._is_resultant_no_operation(instruction):
1.759 -
1.760 - return 1
1.761 - else:
1.762 - return 0
1.763 -
1.764 - def _optimise_unused_results(self):
1.765 -
1.766 - "Discard results which will not be used."
1.767 -
1.768 - if self._have_simple_input():
1.769 - self.remove_active_value()
1.770 -
1.771 # Visitor methods.
1.772
1.773 def default(self, node, *args):
1.774 @@ -741,7 +789,7 @@
1.775 # Where the last operation (defining the attribute owner) yields a
1.776 # constant...
1.777
1.778 - if self._have_constant_input():
1.779 + if self.optimiser.have_constant_input():
1.780 last = self.active_value
1.781
1.782 # Get the details of the access.
1.783 @@ -790,7 +838,7 @@
1.784 # see if the attribute is acceptably positioned and produce a direct
1.785 # access to the attribute.
1.786
1.787 - elif self._optimise_self_access(attrname, (AddressInstruction, AddressContextInstruction, AttrInstruction), node):
1.788 + elif self.optimiser.optimise_self_access(attrname, (AddressInstruction, AddressContextInstruction, AttrInstruction), node):
1.789 return
1.790
1.791 # Otherwise, perform a normal operation.
1.792 @@ -850,7 +898,7 @@
1.793 invocation target.
1.794 """
1.795
1.796 - t = self._optimise_known_target()
1.797 + t = self.optimiser.optimise_known_target()
1.798 if t:
1.799 target, context = t
1.800 else:
1.801 @@ -860,7 +908,7 @@
1.802 # NOTE: This may not be appropriate for class invocations
1.803 # NOTE: (instantiation).
1.804
1.805 - temp = self._optimise_temp_storage()
1.806 + temp = self.optimiser.optimise_temp_storage()
1.807
1.808 # Where a target or context are not known or where an instance is known
1.809 # to be the context, load the context.
1.810 @@ -1025,7 +1073,7 @@
1.811
1.812 # Drop any test if the target and the context are known.
1.813
1.814 - if not self._have_correct_self_for_target(context):
1.815 + if not self.optimiser.have_correct_self_for_target(context):
1.816
1.817 continue_label = self.new_label()
1.818 self.new_op(CheckSelf())
1.819 @@ -1255,7 +1303,7 @@
1.820 # Evaluate and store the operand in temporary storage.
1.821
1.822 self.dispatch(node.expr)
1.823 - temp = self._optimise_temp_storage()
1.824 + temp = self.optimiser.optimise_temp_storage()
1.825
1.826 # Produce the invocation.
1.827
1.828 @@ -1265,7 +1313,7 @@
1.829 # Get the method on temp.
1.830
1.831 self._generateAttr(node, method, self.attribute_load_instructions)
1.832 - temp_method = self._optimise_temp_storage()
1.833 + temp_method = self.optimiser.optimise_temp_storage()
1.834
1.835 self._handleAttributeError(node, end_call_label)
1.836
1.837 @@ -1317,12 +1365,12 @@
1.838 # Evaluate and store the left operand in temporary storage.
1.839
1.840 self.dispatch(node.left)
1.841 - temp1 = self._optimise_temp_storage()
1.842 + temp1 = self.optimiser.optimise_temp_storage()
1.843
1.844 # Evaluate and store the right operand in temporary storage.
1.845
1.846 self.dispatch(node.right)
1.847 - temp2 = self._optimise_temp_storage()
1.848 + temp2 = self.optimiser.optimise_temp_storage()
1.849
1.850 self._generateBinary(node, temp1, temp2, left_method, right_method)
1.851
1.852 @@ -1378,7 +1426,7 @@
1.853 # Get method on temp1.
1.854
1.855 self._generateAttr(node, method_name, self.attribute_load_instructions)
1.856 - temp_method = self._optimise_temp_storage()
1.857 + temp_method = self.optimiser.optimise_temp_storage()
1.858
1.859 self._handleAttributeError(node, end_attempt_label)
1.860
1.861 @@ -1412,7 +1460,7 @@
1.862 attribute access cannot be resolved at compile-time.
1.863 """
1.864
1.865 - if not self._optimise_known_target():
1.866 + if not self.optimiser.optimise_known_target():
1.867 self.load_builtin("AttributeError", node)
1.868 self.new_op(CheckException())
1.869 self.new_op(JumpIfTrue(end_call_label))
1.870 @@ -1446,7 +1494,7 @@
1.871 # NOTE: Using __bool__ instead of __nonzero__.
1.872
1.873 self._generateAttr(node, "__bool__", self.attribute_load_instructions)
1.874 - temp_method = self._optimise_temp_storage()
1.875 + temp_method = self.optimiser.optimise_temp_storage()
1.876
1.877 self._startCallFunc()
1.878 self.new_op(temp)
1.879 @@ -1544,7 +1592,7 @@
1.880 # Optimise away intermediate source storage.
1.881
1.882 if top_level:
1.883 - no_source = self._optimise_source_storage()
1.884 + no_source = self.optimiser.optimise_source_storage()
1.885 self._visitName(node, self.name_store_instructions)
1.886 if not top_level or not no_source:
1.887 self.set_source()
1.888 @@ -1613,7 +1661,7 @@
1.889 temp_result = LoadTemp(temp_pos)
1.890
1.891 self.dispatch(node.expr)
1.892 - temp2 = self._optimise_temp_storage()
1.893 + temp2 = self.optimiser.optimise_temp_storage()
1.894
1.895 last_op = node.ops[-1]
1.896
1.897 @@ -1623,7 +1671,7 @@
1.898
1.899 temp1 = temp2
1.900 self.dispatch(next_node)
1.901 - temp2 = self._optimise_temp_storage()
1.902 + temp2 = self.optimiser.optimise_temp_storage()
1.903
1.904 # Use the appropriate mechanism, setting the boolean status for the
1.905 # comparison.
1.906 @@ -1655,7 +1703,7 @@
1.907 # Get method on temp2.
1.908
1.909 self._generateAttr(node, "__contains__", self.attribute_load_instructions)
1.910 - temp_method = self._optimise_temp_storage()
1.911 + temp_method = self.optimiser.optimise_temp_storage()
1.912
1.913 # Add arguments.
1.914 # NOTE: No support for defaults.
1.915 @@ -1705,7 +1753,7 @@
1.916
1.917 def visitDiscard(self, node):
1.918 self.dispatch(node.expr)
1.919 - self._optimise_unused_results()
1.920 + self.optimiser.optimise_unused_results()
1.921
1.922 def visitDiv(self, node):
1.923 self._visitBinary(node, "__div__", "__rdiv__")
1.924 @@ -1733,7 +1781,7 @@
1.925 self._doCallFunc(temp, target)
1.926 self._endCallFunc(temp, target)
1.927
1.928 - temp_iterator = self._optimise_temp_storage()
1.929 + temp_iterator = self.optimiser.optimise_temp_storage()
1.930
1.931 # In the loop...
1.932
1.933 @@ -1934,7 +1982,7 @@
1.934 def visitNot(self, node):
1.935 self.dispatch(node.expr)
1.936
1.937 - temp = self._optimise_temp_storage()
1.938 + temp = self.optimiser.optimise_temp_storage()
1.939 self._generateTestBoolean(node.expr, temp)
1.940 self.discard_temp(temp)
1.941
1.942 @@ -1983,10 +2031,10 @@
1.943 self.dispatch(node.expr1)
1.944
1.945 if node.expr2 is not None:
1.946 - temp = self._optimise_temp_storage()
1.947 + temp = self.optimiser.optimise_temp_storage()
1.948
1.949 self.dispatch(node.expr2)
1.950 - temp_arg = self._optimise_temp_storage()
1.951 + temp_arg = self.optimiser.optimise_temp_storage()
1.952
1.953 self._startCallFunc()
1.954 self.new_op(temp_arg)