2.1 --- a/micropython/ast.py Fri Sep 05 00:04:20 2008 +0200
2.2 +++ b/micropython/ast.py Sun Sep 07 00:34:43 2008 +0200
2.3 @@ -25,16 +25,386 @@
2.4 import compiler.ast
2.5 from compiler.visitor import ASTVisitor
2.6
2.7 +class Optimiser:
2.8 +
2.9 + "A code optimiser."
2.10 +
2.11 + supported_optimisations = [
2.12 + "constant_storage", "source_storage", "known_target", "self_access",
2.13 + "temp_storage", "load_operations", "no_operations", "unused_results",
2.14 + "superfluous_temp_operations"
2.15 + ]
2.16 +
2.17 + def __init__(self, translation, optimisations=None):
2.18 +
2.19 + """
2.20 + Provide for the given 'translation' an optimiser for the desired
2.21 + 'optimisations'. See the 'supported_optimisations' attribute of this
2.22 + class for permitted values.
2.23 + """
2.24 +
2.25 + self.translation = translation
2.26 + self.optimisations = set(optimisations or [])
2.27 +
2.28 + # Optimisation tests.
2.29 +
2.30 + def should_optimise_constant_storage(self):
2.31 + return "constant_storage" in self.optimisations
2.32 +
2.33 + def should_optimise_source_storage(self):
2.34 + return "source_storage" in self.optimisations
2.35 +
2.36 + def should_optimise_known_target(self):
2.37 + return "known_target" in self.optimisations
2.38 +
2.39 + def should_optimise_self_access(self):
2.40 + return "self_access" in self.optimisations
2.41 +
2.42 + def should_optimise_temp_storage(self):
2.43 + return "temp_storage" in self.optimisations
2.44 +
2.45 + def should_optimise_load_operations(self):
2.46 + return "load_operations" in self.optimisations
2.47 +
2.48 + def should_optimise_away_no_operations(self):
2.49 + return "no_operations" in self.optimisations
2.50 +
2.51 + def should_optimise_away_superfluous_temp_operations(self):
2.52 + return "superfluous_temp_operations" in self.optimisations
2.53 +
2.54 + def should_optimise_unused_results(self):
2.55 + return "unused_results" in self.optimisations
2.56 +
2.57 + # Simple tests.
2.58 +
2.59 + def is_constant_input(self, instruction):
2.60 +
2.61 + "Return whether 'instruction' provides a constant input."
2.62 +
2.63 + return isinstance(instruction, LoadAddress) and instruction.attr.assignments == 1 or \
2.64 + isinstance(instruction, LoadConst)
2.65 +
2.66 + def is_constant_target(self, instruction):
2.67 +
2.68 + "Return whether 'instruction' provides a constant target."
2.69 +
2.70 + return isinstance(instruction, (StoreName, StoreAddress)) and \
2.71 + instruction.attr.assignments == 1
2.72 +
2.73 + def is_simple_input(self, instruction):
2.74 +
2.75 + """
2.76 + Return whether 'instruction' provides a simple input (typically a load
2.77 + instruction). A simple input is something which would be represented by
2.78 + a load operation from a CPU register or special memory location.
2.79 + """
2.80 +
2.81 + return isinstance(instruction, (LoadConst, LoadName, LoadTemp, LoadResult, LoadAddress))
2.82 +
2.83 + def is_simple_input_user(self, instruction):
2.84 +
2.85 + """
2.86 + Return whether 'instruction' can use simple input from the current
2.87 + value. Such instructions would, in a low-level implementation, be able
2.88 + to have the simple input registers as operands.
2.89 + """
2.90 +
2.91 + return isinstance(instruction, (
2.92 + StoreTemp, StoreFrame, StoreResult, StoreException, # as the value being stored
2.93 + LoadAddressContext, LoadAttr, LoadAttrIndex, # as the object being referenced
2.94 + StoreAttr, StoreAttrIndex, StoreCallable, # as the object being referenced
2.95 + LoadCallable,
2.96 + TestIdentity, TestIdentityAddress, CheckSelf, # as one of the operands
2.97 + CheckFrame, MakeObject,
2.98 + LoadContext # as the object providing the result
2.99 + ))
2.100 +
2.101 + def is_resultant_no_operation(self, instruction):
2.102 +
2.103 + """
2.104 + Return whether 'instruction' merely stores its input where the input
2.105 + originally came from.
2.106 + """
2.107 +
2.108 + return (
2.109 + isinstance(instruction.input, LoadTemp) and isinstance(instruction, StoreTemp) and
2.110 + instruction.input.attr == instruction.attr) or (
2.111 + isinstance(instruction.input, LoadResult) and isinstance(instruction, StoreResult)
2.112 + )
2.113 +
2.114 + def is_superfluous_temp_operation(self, instruction):
2.115 +
2.116 + """
2.117 + Return whether 'instruction' merely loads its input from a recent
2.118 + temporary storage operation.
2.119 + """
2.120 +
2.121 + return (
2.122 + isinstance(instruction.source, LoadTemp) and isinstance(self.translation.active_source, StoreTemp) and
2.123 + instruction.source.attr == self.translation.active_source.attr
2.124 + )
2.125 +
2.126 + def is_input(self, instruction):
2.127 +
2.128 + "Return whether 'instruction' provides an input."
2.129 +
2.130 + return isinstance(instruction, current_value_instructions)
2.131 +
2.132 + # Convenience tests on outputs.
2.133 +
2.134 + def have_constant_target(self):
2.135 +
2.136 + "Return whether the active instruction provides a constant target."
2.137 +
2.138 + return self.is_constant_target(self.translation.active)
2.139 +
2.140 + def have_constant_source(self):
2.141 +
2.142 + "Return whether the active instruction has a constant source."
2.143 +
2.144 + return self.is_constant_input(self.translation.active.source)
2.145 +
2.146 + # Convenience tests on inputs.
2.147 +
2.148 + def have_constant_input(self):
2.149 +
2.150 + "Return whether the active instruction provides a constant input."
2.151 +
2.152 + return self.is_constant_input(self.translation.active_value)
2.153 +
2.154 + have_known_target = have_constant_input
2.155 +
2.156 + def have_simple_input(self):
2.157 +
2.158 + "Return whether the active instruction provides a simple input."
2.159 +
2.160 + return self.is_simple_input(self.translation.active_value)
2.161 +
2.162 + def have_input(self):
2.163 +
2.164 + "Return whether the active instruction provides an input."
2.165 +
2.166 + return self.is_input(self.translation.active_value)
2.167 +
2.168 + def have_self_input(self):
2.169 +
2.170 + "Return whether the active instruction is a reference to self."
2.171 +
2.172 + return isinstance(self.translation.unit, Function) and \
2.173 + self.translation.unit.is_method() and isinstance(self.translation.active_value, LoadName) and \
2.174 + self.translation.active_value.attr.name == "self"
2.175 +
2.176 + def have_temp_compatible_access(self):
2.177 +
2.178 + """
2.179 + Indicate whether the active instruction can be used in place of access
2.180 + to a temporary variable retaining the result of the last instruction.
2.181 + """
2.182 +
2.183 + # LoadResult cannot be relied upon in general since the result register
2.184 + # could be updated since first being referenced.
2.185 +
2.186 + return isinstance(self.translation.active_value, (LoadName, LoadTemp, LoadAddress, LoadConst)) or \
2.187 + isinstance(self.translation.active_value, LoadResult) and self.translation.active_value is self.translation.active
2.188 +
2.189 + def have_correct_self_for_target(self, context):
2.190 +
2.191 + "Return whether the 'context' is compatible with the current value."
2.192 +
2.193 + if context is not None and self.have_self_input():
2.194 +
2.195 + parent = self.translation.unit.parent
2.196 + if parent is context or parent.has_subclass(context) or context.has_subclass(parent):
2.197 + return 1
2.198 +
2.199 + return 0
2.200 +
2.201 + # Optimisation methods. See the supported_optimisations class attribute.
2.202 +
2.203 + def optimise_constant_storage(self):
2.204 +
2.205 + """
2.206 + Where the last operation stores a constant into a target which is also
2.207 + constant, optimise away both operations.
2.208 + """
2.209 +
2.210 + if self.should_optimise_constant_storage() and \
2.211 + self.have_constant_target() and \
2.212 + self.have_constant_source():
2.213 +
2.214 + self.translation.remove_op()
2.215 + return 1
2.216 + else:
2.217 + return 0
2.218 +
2.219 + def optimise_source_storage(self):
2.220 +
2.221 + """
2.222 + Where the source value in an assignment can be inserted into the
2.223 + eventual target without intermediate storage, optimise away the storage
2.224 + instruction.
2.225 + """
2.226 +
2.227 + if self.should_optimise_source_storage() and \
2.228 + self.translation.active_source is not None and \
2.229 + self.translation.active_source.source is None and \
2.230 + self.translation.active_source.input is None and \
2.231 + self.translation.active_source is self.translation.active:
2.232 +
2.233 + self.translation.remove_op()
2.234 + return 1
2.235 + else:
2.236 + return 0
2.237 +
2.238 + def optimise_known_target(self):
2.239 +
2.240 + """
2.241 + Where the target of an invocation is known, provide information about it
2.242 + and its context. If a class is being invoked and the conditions are
2.243 + appropriate, get information about the specific initialiser.
2.244 + """
2.245 +
2.246 + if self.should_optimise_known_target() and self.have_known_target():
2.247 + last = self.translation.active_value
2.248 + target = last.attr.value
2.249 + context = last.attr.context
2.250 +
2.251 + return target, context
2.252 + else:
2.253 + return None
2.254 +
2.255 + def optimise_self_access(self, attrname, classes, node):
2.256 +
2.257 + """
2.258 + Where the provided 'attrname' accesses an attribute which occupies the
2.259 + same position in all possible objects which can be accessed, generate an
2.260 + instruction using one of the given 'classes', accessing the attribute
2.261 + directly.
2.262 + """
2.263 +
2.264 + AddressInstruction, AddressContextInstruction, AttrInstruction = classes
2.265 +
2.266 + if self.should_optimise_self_access() and self.have_self_input() and \
2.267 + not self.translation.unit.is_relocated(attrname):
2.268 +
2.269 + # Either generate an instruction operating on an instance attribute.
2.270 +
2.271 + try:
2.272 + attr = self.translation.unit.parent.instance_attributes()[attrname]
2.273 + self.translation.new_op(AttrInstruction(attr))
2.274 +
2.275 + # Or generate an instruction operating on a class attribute.
2.276 +
2.277 + except KeyError:
2.278 + attr = self.translation.unit.parent.all_attributes()[attrname]
2.279 +
2.280 + # Switch the context if the class attribute is compatible with
2.281 + # the instance.
2.282 +
2.283 + if attr.defined_within_hierarchy():
2.284 +
2.285 + # Only permit loading (not storing) of class attributes via self.
2.286 +
2.287 + if AddressContextInstruction is not None:
2.288 + self.translation.new_op(AddressContextInstruction(attr))
2.289 + else:
2.290 + raise TranslateError(self.translation.module.full_name(), node,
2.291 + "Storing of class attribute %r via self not permitted." % attrname)
2.292 +
2.293 + # Preserve the context if the class attribute comes from an
2.294 + # incompatible class.
2.295 +
2.296 + else:
2.297 + if AddressInstruction is not None:
2.298 + self.translation.new_op(AddressInstruction(attr))
2.299 + else:
2.300 + raise TranslateError(self.translation.module.full_name(), node,
2.301 + "Storing of class attribute %r via self not permitted." % attrname)
2.302 +
2.303 + return 1
2.304 + else:
2.305 + return 0
2.306 +
2.307 + def optimise_temp_storage(self):
2.308 +
2.309 + """
2.310 + Where the next operation would involve storing a value into temporary
2.311 + storage at 'temp_position', record and remove any simple instruction
2.312 + which produced the value to be stored such that instead of subsequently
2.313 + accessing the temporary storage, that instruction is substituted.
2.314 +
2.315 + If no optimisation can be achieved, a StoreTemp instruction is produced
2.316 + and the appropriate LoadTemp instruction is returned.
2.317 +
2.318 + Restriction: for use only in situations where the source of the
2.319 + temporary data will not be disturbed between its first access and its
2.320 + subsequent use.
2.321 + """
2.322 +
2.323 + if self.should_optimise_temp_storage() and \
2.324 + self.have_temp_compatible_access():
2.325 +
2.326 + removed = self.translation.active
2.327 + self.translation.remove_active_value()
2.328 + return removed
2.329 + else:
2.330 + return self.translation.get_temp()
2.331 +
2.332 + def optimise_load_operations(self, instruction):
2.333 +
2.334 + """
2.335 + Incorporate previous load operations into other operations.
2.336 + """
2.337 +
2.338 + if self.should_optimise_load_operations() and \
2.339 + self.have_simple_input() and \
2.340 + self.is_simple_input_user(instruction):
2.341 +
2.342 + self.translation.remove_active_value()
2.343 + instruction.input = self.translation.active_value
2.344 +
2.345 + def optimise_away_no_operations(self, instruction):
2.346 +
2.347 + """
2.348 + Optimise away operations which just store their inputs in the place
2.349 + the inputs originally came from.
2.350 + """
2.351 +
2.352 + if self.should_optimise_away_no_operations() and \
2.353 + self.is_resultant_no_operation(instruction):
2.354 +
2.355 + return 1
2.356 + else:
2.357 + return 0
2.358 +
2.359 + def optimise_away_superfluous_temp_operations(self, instruction):
2.360 +
2.361 + """
2.362 + Optimise away operations which just store temporary values for
2.363 + immediate retrieval.
2.364 + """
2.365 +
2.366 + if self.should_optimise_away_superfluous_temp_operations() and \
2.367 + self.is_superfluous_temp_operation(instruction) and \
2.368 + self.translation.active_source == self.translation.active:
2.369 +
2.370 + instruction.source = self.translation.active_source.input
2.371 + self.translation.remove_op()
2.372 +
2.373 + def optimise_unused_results(self):
2.374 +
2.375 + "Discard results which will not be used."
2.376 +
2.377 + if self.have_simple_input():
2.378 + self.translation.remove_active_value()
2.379 +
2.380 # Program visitors.
2.381
2.382 class Translation(ASTVisitor):
2.383
2.384 "A translated module."
2.385
2.386 - supported_optimisations = [
2.387 - "constant_storage", "source_storage", "known_target", "self_access",
2.388 - "temp_storage", "load_operations", "no_operations", "unused_results"
2.389 - ]
2.390 + supported_optimisations = Optimiser.supported_optimisations
2.391
2.392 # Attribute access instructions, for use with the appropriate handlers.
2.393
2.394 @@ -46,11 +416,6 @@
2.395 name_load_instructions = (LoadName, LoadAddress)
2.396 name_store_instructions = (StoreName, StoreAddress)
2.397
2.398 - # Instructions which affect the current value.
2.399 -
2.400 - current_value_instructions = (LoadConst, LoadName, LoadTemp, LoadAddress, LoadAddressContext, LoadAttr, LoadAttrIndex,
2.401 - LoadCallable, LoadContext, LoadResult, LoadException, MakeObject)
2.402 -
2.403 def __init__(self, module, importer, optimisations=None):
2.404
2.405 """
2.406 @@ -70,9 +435,9 @@
2.407 self.paramtable = self.importer.get_parameter_table()
2.408 self.builtins = self.importer.modules.get("__builtins__")
2.409
2.410 - # Desired optimisations.
2.411 -
2.412 - self.optimisations = set(optimisations or [])
2.413 + # Optimisation.
2.414 +
2.415 + self.optimiser = Optimiser(self, optimisations)
2.416
2.417 # The current unit being translated.
2.418
2.419 @@ -289,7 +654,7 @@
2.420
2.421 # Optimise away constant storage if appropriate.
2.422
2.423 - self._optimise_constant_storage()
2.424 + self.optimiser.optimise_constant_storage()
2.425
2.426 # Temporary storage administration.
2.427
2.428 @@ -333,16 +698,17 @@
2.429
2.430 # Optimise load operations employed by this instruction.
2.431
2.432 - self._optimise_load_operations(op)
2.433 - if self._optimise_away_no_operations(op):
2.434 + self.optimiser.optimise_load_operations(op)
2.435 + if self.optimiser.optimise_away_no_operations(op):
2.436 return
2.437 + self.optimiser.optimise_away_superfluous_temp_operations(op)
2.438
2.439 self.code.append(op)
2.440 self.active = op
2.441
2.442 # Record specific types of instructions for optimisation.
2.443
2.444 - if isinstance(op, self.current_value_instructions):
2.445 + if isinstance(op, current_value_instructions):
2.446 self.active_value = op
2.447
2.448 def remove_op(self):
2.449 @@ -392,324 +758,6 @@
2.450 self.active_value = None
2.451 self.active_source = None
2.452
2.453 - # Optimisation tests.
2.454 -
2.455 - def _should_optimise_constant_storage(self):
2.456 - return "constant_storage" in self.optimisations
2.457 -
2.458 - def _should_optimise_source_storage(self):
2.459 - return "source_storage" in self.optimisations
2.460 -
2.461 - def _should_optimise_known_target(self):
2.462 - return "known_target" in self.optimisations
2.463 -
2.464 - def _should_optimise_self_access(self):
2.465 - return "self_access" in self.optimisations
2.466 -
2.467 - def _should_optimise_temp_storage(self):
2.468 - return "temp_storage" in self.optimisations
2.469 -
2.470 - def _should_optimise_load_operations(self):
2.471 - return "load_operations" in self.optimisations
2.472 -
2.473 - def _should_optimise_away_no_operations(self):
2.474 - return "no_operations" in self.optimisations
2.475 -
2.476 - def _should_optimise_unused_results(self):
2.477 - return "unused_results" in self.optimisations
2.478 -
2.479 - # Simple tests.
2.480 -
2.481 - def _is_constant_input(self, instruction):
2.482 -
2.483 - "Return whether 'instruction' provides a constant input."
2.484 -
2.485 - return isinstance(instruction, LoadAddress) and instruction.attr.assignments == 1 or \
2.486 - isinstance(instruction, LoadConst)
2.487 -
2.488 - def _is_constant_target(self, instruction):
2.489 -
2.490 - "Return whether 'instruction' provides a constant target."
2.491 -
2.492 - return isinstance(instruction, (StoreName, StoreAddress)) and \
2.493 - instruction.attr.assignments == 1
2.494 -
2.495 - def _is_simple_input(self, instruction):
2.496 -
2.497 - """
2.498 - Return whether 'instruction' provides a simple input (typically a load
2.499 - instruction).
2.500 - """
2.501 -
2.502 - return isinstance(instruction, (LoadConst, LoadName, LoadTemp, LoadResult, LoadAddress))
2.503 -
2.504 - def _is_simple_input_user(self, instruction):
2.505 -
2.506 - "Return whether 'instruction' can use simple input from the current value."
2.507 -
2.508 - return isinstance(instruction, (
2.509 - StoreTemp, StoreFrame, StoreResult, StoreException, # as the value being stored
2.510 - LoadAddressContext, LoadAttr, LoadAttrIndex, # as the object being referenced
2.511 - StoreAttr, StoreAttrIndex, StoreCallable, # as the object being referenced
2.512 - LoadCallable,
2.513 - TestIdentity, TestIdentityAddress, CheckSelf, # as one of the operands
2.514 - CheckFrame, MakeObject,
2.515 - LoadContext # as the object providing the result
2.516 - ))
2.517 -
2.518 - def _is_resultant_no_operation(self, instruction):
2.519 -
2.520 - """
2.521 - Return whether 'instruction' merely stores its input where the input
2.522 - originally came from.
2.523 - """
2.524 -
2.525 - return (
2.526 - isinstance(instruction.input, LoadTemp) and isinstance(instruction, StoreTemp) and
2.527 - instruction.input.attr == instruction.attr) or (
2.528 - isinstance(instruction.input, LoadResult) and isinstance(instruction, StoreResult)
2.529 - )
2.530 -
2.531 - def _is_input(self, instruction):
2.532 -
2.533 - "Return whether 'instruction' provides an input."
2.534 -
2.535 - return isinstance(instruction, self.current_value_instructions)
2.536 -
2.537 - # Convenience tests on outputs.
2.538 -
2.539 - def _have_constant_target(self):
2.540 -
2.541 - "Return whether the active instruction provides a constant target."
2.542 -
2.543 - return self._is_constant_target(self.active)
2.544 -
2.545 - def _have_constant_source(self):
2.546 -
2.547 - "Return whether the active instruction has a constant source."
2.548 -
2.549 - return self._is_constant_input(self.active.source)
2.550 -
2.551 - # Convenience tests on inputs.
2.552 -
2.553 - def _have_constant_input(self):
2.554 -
2.555 - "Return whether the active instruction provides a constant input."
2.556 -
2.557 - return self._is_constant_input(self.active_value)
2.558 -
2.559 - _have_known_target = _have_constant_input
2.560 -
2.561 - def _have_simple_input(self):
2.562 -
2.563 - "Return whether the active instruction provides a simple input."
2.564 -
2.565 - return self._is_simple_input(self.active_value)
2.566 -
2.567 - def _have_input(self):
2.568 -
2.569 - "Return whether the active instruction provides an input."
2.570 -
2.571 - return self._is_input(self.active_value)
2.572 -
2.573 - def _have_self_input(self):
2.574 -
2.575 - "Return whether the active instruction is a reference to self."
2.576 -
2.577 - return isinstance(self.unit, Function) and \
2.578 - self.unit.is_method() and isinstance(self.active_value, LoadName) and \
2.579 - self.active_value.attr.name == "self"
2.580 -
2.581 - def _have_temp_compatible_access(self):
2.582 -
2.583 - """
2.584 - Indicate whether the active instruction can be used in place of access
2.585 - to a temporary variable retaining the result of the last instruction.
2.586 - """
2.587 -
2.588 - # LoadResult cannot be relied upon in general since the result register
2.589 - # could be updated since first being referenced.
2.590 -
2.591 - return isinstance(self.active_value, (LoadName, LoadTemp, LoadAddress, LoadConst)) or \
2.592 - isinstance(self.active_value, LoadResult) and self.active_value is self.active
2.593 -
2.594 - def _have_correct_self_for_target(self, context):
2.595 -
2.596 - "Return whether the 'context' is compatible with the current value."
2.597 -
2.598 - if context is not None and self._have_self_input():
2.599 -
2.600 - parent = self.unit.parent
2.601 - if parent is context or parent.has_subclass(context) or context.has_subclass(parent):
2.602 - return 1
2.603 -
2.604 - return 0
2.605 -
2.606 - # Optimisation methods. See the supported_optimisations class attribute.
2.607 -
2.608 - def _optimise_constant_storage(self):
2.609 -
2.610 - """
2.611 - Where the last operation stores a constant into a target which is also
2.612 - constant, optimise away both operations.
2.613 - """
2.614 -
2.615 - if self._should_optimise_constant_storage() and \
2.616 - self._have_constant_target() and \
2.617 - self._have_constant_source():
2.618 -
2.619 - self.remove_op()
2.620 - return 1
2.621 - else:
2.622 - return 0
2.623 -
2.624 - def _optimise_source_storage(self):
2.625 -
2.626 - """
2.627 - Where the source value in an assignment can be inserted into the
2.628 - eventual target without intermediate storage, optimise away the storage
2.629 - instruction.
2.630 - """
2.631 -
2.632 - if self._should_optimise_source_storage() and \
2.633 - self.active_source is not None and \
2.634 - self.active_source.source is None and \
2.635 - self.active_source.input is None and \
2.636 - self.active_source is self.active:
2.637 -
2.638 - self.remove_op()
2.639 - return 1
2.640 - else:
2.641 - return 0
2.642 -
2.643 - def _optimise_known_target(self):
2.644 -
2.645 - """
2.646 - Where the target of an invocation is known, provide information about it
2.647 - and its context. If a class is being invoked and the conditions are
2.648 - appropriate, get information about the specific initialiser.
2.649 - """
2.650 -
2.651 - if self._should_optimise_known_target() and self._have_known_target():
2.652 - last = self.active_value
2.653 - target = last.attr.value
2.654 - context = last.attr.context
2.655 -
2.656 - return target, context
2.657 - else:
2.658 - return None
2.659 -
2.660 - def _optimise_self_access(self, attrname, classes, node):
2.661 -
2.662 - """
2.663 - Where the provided 'attrname' accesses an attribute which occupies the
2.664 - same position in all possible objects which can be accessed, generate an
2.665 - instruction using one of the given 'classes', accessing the attribute
2.666 - directly.
2.667 - """
2.668 -
2.669 - AddressInstruction, AddressContextInstruction, AttrInstruction = classes
2.670 -
2.671 - if self._should_optimise_self_access() and self._have_self_input() and \
2.672 - not self.unit.is_relocated(attrname):
2.673 -
2.674 - # Either generate an instruction operating on an instance attribute.
2.675 -
2.676 - try:
2.677 - attr = self.unit.parent.instance_attributes()[attrname]
2.678 - self.new_op(AttrInstruction(attr))
2.679 -
2.680 - # Or generate an instruction operating on a class attribute.
2.681 -
2.682 - except KeyError:
2.683 - attr = self.unit.parent.all_attributes()[attrname]
2.684 -
2.685 - # Switch the context if the class attribute is compatible with
2.686 - # the instance.
2.687 -
2.688 - if attr.defined_within_hierarchy():
2.689 -
2.690 - # Only permit loading (not storing) of class attributes via self.
2.691 -
2.692 - if AddressContextInstruction is not None:
2.693 - self.new_op(AddressContextInstruction(attr))
2.694 - else:
2.695 - raise TranslateError(self.module.full_name(), node,
2.696 - "Storing of class attribute %r via self not permitted." % attrname)
2.697 -
2.698 - # Preserve the context if the class attribute comes from an
2.699 - # incompatible class.
2.700 -
2.701 - else:
2.702 - if AddressInstruction is not None:
2.703 - self.new_op(AddressInstruction(attr))
2.704 - else:
2.705 - raise TranslateError(self.module.full_name(), node,
2.706 - "Storing of class attribute %r via self not permitted." % attrname)
2.707 -
2.708 - return 1
2.709 - else:
2.710 - return 0
2.711 -
2.712 - def _optimise_temp_storage(self):
2.713 -
2.714 - """
2.715 - Where the next operation would involve storing a value into temporary
2.716 - storage at 'temp_position', record and remove any simple instruction
2.717 - which produced the value to be stored such that instead of subsequently
2.718 - accessing the temporary storage, that instruction is substituted.
2.719 -
2.720 - If no optimisation can be achieved, a StoreTemp instruction is produced
2.721 - and the appropriate LoadTemp instruction is returned.
2.722 -
2.723 - Restriction: for use only in situations where the source of the
2.724 - temporary data will not be disturbed between its first access and its
2.725 - subsequent use.
2.726 - """
2.727 -
2.728 - if self._should_optimise_temp_storage() and \
2.729 - self._have_temp_compatible_access():
2.730 -
2.731 - removed = self.active
2.732 - self.remove_active_value()
2.733 - return removed
2.734 - else:
2.735 - return self.get_temp()
2.736 -
2.737 - def _optimise_load_operations(self, instruction):
2.738 -
2.739 - """
2.740 - Incorporate previous load operations into other operations.
2.741 - """
2.742 -
2.743 - if self._should_optimise_load_operations() and \
2.744 - self._have_simple_input() and \
2.745 - self._is_simple_input_user(instruction):
2.746 -
2.747 - self.remove_active_value()
2.748 - instruction.input = self.active_value
2.749 -
2.750 - def _optimise_away_no_operations(self, instruction):
2.751 -
2.752 - """
2.753 - Optimise away operations which just store their inputs in the place
2.754 - the inputs originally came from.
2.755 - """
2.756 -
2.757 - if self._should_optimise_away_no_operations() and \
2.758 - self._is_resultant_no_operation(instruction):
2.759 -
2.760 - return 1
2.761 - else:
2.762 - return 0
2.763 -
2.764 - def _optimise_unused_results(self):
2.765 -
2.766 - "Discard results which will not be used."
2.767 -
2.768 - if self._have_simple_input():
2.769 - self.remove_active_value()
2.770 -
2.771 # Visitor methods.
2.772
2.773 def default(self, node, *args):
2.774 @@ -741,7 +789,7 @@
2.775 # Where the last operation (defining the attribute owner) yields a
2.776 # constant...
2.777
2.778 - if self._have_constant_input():
2.779 + if self.optimiser.have_constant_input():
2.780 last = self.active_value
2.781
2.782 # Get the details of the access.
2.783 @@ -790,7 +838,7 @@
2.784 # see if the attribute is acceptably positioned and produce a direct
2.785 # access to the attribute.
2.786
2.787 - elif self._optimise_self_access(attrname, (AddressInstruction, AddressContextInstruction, AttrInstruction), node):
2.788 + elif self.optimiser.optimise_self_access(attrname, (AddressInstruction, AddressContextInstruction, AttrInstruction), node):
2.789 return
2.790
2.791 # Otherwise, perform a normal operation.
2.792 @@ -850,7 +898,7 @@
2.793 invocation target.
2.794 """
2.795
2.796 - t = self._optimise_known_target()
2.797 + t = self.optimiser.optimise_known_target()
2.798 if t:
2.799 target, context = t
2.800 else:
2.801 @@ -860,7 +908,7 @@
2.802 # NOTE: This may not be appropriate for class invocations
2.803 # NOTE: (instantiation).
2.804
2.805 - temp = self._optimise_temp_storage()
2.806 + temp = self.optimiser.optimise_temp_storage()
2.807
2.808 # Where a target or context are not known or where an instance is known
2.809 # to be the context, load the context.
2.810 @@ -1025,7 +1073,7 @@
2.811
2.812 # Drop any test if the target and the context are known.
2.813
2.814 - if not self._have_correct_self_for_target(context):
2.815 + if not self.optimiser.have_correct_self_for_target(context):
2.816
2.817 continue_label = self.new_label()
2.818 self.new_op(CheckSelf())
2.819 @@ -1255,7 +1303,7 @@
2.820 # Evaluate and store the operand in temporary storage.
2.821
2.822 self.dispatch(node.expr)
2.823 - temp = self._optimise_temp_storage()
2.824 + temp = self.optimiser.optimise_temp_storage()
2.825
2.826 # Produce the invocation.
2.827
2.828 @@ -1265,7 +1313,7 @@
2.829 # Get the method on temp.
2.830
2.831 self._generateAttr(node, method, self.attribute_load_instructions)
2.832 - temp_method = self._optimise_temp_storage()
2.833 + temp_method = self.optimiser.optimise_temp_storage()
2.834
2.835 self._handleAttributeError(node, end_call_label)
2.836
2.837 @@ -1317,12 +1365,12 @@
2.838 # Evaluate and store the left operand in temporary storage.
2.839
2.840 self.dispatch(node.left)
2.841 - temp1 = self._optimise_temp_storage()
2.842 + temp1 = self.optimiser.optimise_temp_storage()
2.843
2.844 # Evaluate and store the right operand in temporary storage.
2.845
2.846 self.dispatch(node.right)
2.847 - temp2 = self._optimise_temp_storage()
2.848 + temp2 = self.optimiser.optimise_temp_storage()
2.849
2.850 self._generateBinary(node, temp1, temp2, left_method, right_method)
2.851
2.852 @@ -1378,7 +1426,7 @@
2.853 # Get method on temp1.
2.854
2.855 self._generateAttr(node, method_name, self.attribute_load_instructions)
2.856 - temp_method = self._optimise_temp_storage()
2.857 + temp_method = self.optimiser.optimise_temp_storage()
2.858
2.859 self._handleAttributeError(node, end_attempt_label)
2.860
2.861 @@ -1412,7 +1460,7 @@
2.862 attribute access cannot be resolved at compile-time.
2.863 """
2.864
2.865 - if not self._optimise_known_target():
2.866 + if not self.optimiser.optimise_known_target():
2.867 self.load_builtin("AttributeError", node)
2.868 self.new_op(CheckException())
2.869 self.new_op(JumpIfTrue(end_call_label))
2.870 @@ -1446,7 +1494,7 @@
2.871 # NOTE: Using __bool__ instead of __nonzero__.
2.872
2.873 self._generateAttr(node, "__bool__", self.attribute_load_instructions)
2.874 - temp_method = self._optimise_temp_storage()
2.875 + temp_method = self.optimiser.optimise_temp_storage()
2.876
2.877 self._startCallFunc()
2.878 self.new_op(temp)
2.879 @@ -1544,7 +1592,7 @@
2.880 # Optimise away intermediate source storage.
2.881
2.882 if top_level:
2.883 - no_source = self._optimise_source_storage()
2.884 + no_source = self.optimiser.optimise_source_storage()
2.885 self._visitName(node, self.name_store_instructions)
2.886 if not top_level or not no_source:
2.887 self.set_source()
2.888 @@ -1613,7 +1661,7 @@
2.889 temp_result = LoadTemp(temp_pos)
2.890
2.891 self.dispatch(node.expr)
2.892 - temp2 = self._optimise_temp_storage()
2.893 + temp2 = self.optimiser.optimise_temp_storage()
2.894
2.895 last_op = node.ops[-1]
2.896
2.897 @@ -1623,7 +1671,7 @@
2.898
2.899 temp1 = temp2
2.900 self.dispatch(next_node)
2.901 - temp2 = self._optimise_temp_storage()
2.902 + temp2 = self.optimiser.optimise_temp_storage()
2.903
2.904 # Use the appropriate mechanism, setting the boolean status for the
2.905 # comparison.
2.906 @@ -1655,7 +1703,7 @@
2.907 # Get method on temp2.
2.908
2.909 self._generateAttr(node, "__contains__", self.attribute_load_instructions)
2.910 - temp_method = self._optimise_temp_storage()
2.911 + temp_method = self.optimiser.optimise_temp_storage()
2.912
2.913 # Add arguments.
2.914 # NOTE: No support for defaults.
2.915 @@ -1705,7 +1753,7 @@
2.916
2.917 def visitDiscard(self, node):
2.918 self.dispatch(node.expr)
2.919 - self._optimise_unused_results()
2.920 + self.optimiser.optimise_unused_results()
2.921
2.922 def visitDiv(self, node):
2.923 self._visitBinary(node, "__div__", "__rdiv__")
2.924 @@ -1733,7 +1781,7 @@
2.925 self._doCallFunc(temp, target)
2.926 self._endCallFunc(temp, target)
2.927
2.928 - temp_iterator = self._optimise_temp_storage()
2.929 + temp_iterator = self.optimiser.optimise_temp_storage()
2.930
2.931 # In the loop...
2.932
2.933 @@ -1934,7 +1982,7 @@
2.934 def visitNot(self, node):
2.935 self.dispatch(node.expr)
2.936
2.937 - temp = self._optimise_temp_storage()
2.938 + temp = self.optimiser.optimise_temp_storage()
2.939 self._generateTestBoolean(node.expr, temp)
2.940 self.discard_temp(temp)
2.941
2.942 @@ -1983,10 +2031,10 @@
2.943 self.dispatch(node.expr1)
2.944
2.945 if node.expr2 is not None:
2.946 - temp = self._optimise_temp_storage()
2.947 + temp = self.optimiser.optimise_temp_storage()
2.948
2.949 self.dispatch(node.expr2)
2.950 - temp_arg = self._optimise_temp_storage()
2.951 + temp_arg = self.optimiser.optimise_temp_storage()
2.952
2.953 self._startCallFunc()
2.954 self.new_op(temp_arg)