1 #!/usr/bin/env python 2 3 """ 4 Generate low-level code. 5 6 Copyright (C) 2007, 2008, 2009, 2010, 2011 Paul Boddie <paul@boddie.org.uk> 7 8 This program is free software; you can redistribute it and/or modify it under 9 the terms of the GNU General Public License as published by the Free Software 10 Foundation; either version 3 of the License, or (at your option) any later 11 version. 12 13 This program is distributed in the hope that it will be useful, but WITHOUT 14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 16 details. 17 18 You should have received a copy of the GNU General Public License along with 19 this program. If not, see <http://www.gnu.org/licenses/>. 20 """ 21 22 from micropython.opt import Optimiser 23 from micropython.common import * 24 from micropython.data import * 25 from micropython.rsvp import * 26 import compiler.ast 27 28 class Assembler: 29 30 "Support for generating low-level code." 31 32 def __init__(self, program): 33 34 """ 35 Initialise the assembler with a program, optimiser and status 36 attributes. 37 """ 38 39 self.program = program 40 41 # Optimisation. 42 43 self.optimiser = Optimiser(self, program.optimisations) 44 45 # The current unit being translated. 46 47 self.unit = None 48 49 # The temporary storage used by the current assignment expression. 50 51 self.expr_temp = [] 52 53 # The start of the current assignment target instructions. 54 55 self.target_start = None 56 57 # Wiring within the code. 58 59 self.labels = {} 60 self.label_number = 0 61 self.loop_blocks = [] 62 self.exception_blocks = [] 63 64 def reset(self): 65 66 "Reset the state of the assembler." 67 68 # The code itself. This is limited to the code for a particular block 69 # being processed. 70 71 self.blocks = [] 72 73 # Information about temporary values. 74 75 self.temp_positions = set() 76 self.max_temp_position = -1 77 78 # Information about instructions which construct frames. 79 80 self.frame_makers = [] 81 82 # Optimiser state must be reset for each unit. 83 84 self.optimiser.reset() 85 86 def new_block(self): 87 88 "Return a new code block." 89 90 return Block() 91 92 def get_block(self): 93 94 "Return the current block." 95 96 return self.blocks[-1] 97 98 def set_block(self, block, preceding=None): 99 100 """ 101 Add the given 'block' to the unit's list of blocks, noting any active 102 value information from 'preceding' blocks on the new block. 103 """ 104 105 self.optimiser.reset(block, preceding) 106 self.blocks.append(block) 107 108 def get_loop_blocks(self): 109 return self.loop_blocks[-1] 110 111 def add_loop_blocks(self, next_block, exit_block): 112 self.loop_blocks.append((next_block, exit_block)) 113 114 def drop_loop_blocks(self): 115 self.loop_blocks.pop() 116 117 def add_exception_unit(self): 118 self.exception_blocks.append([]) 119 120 def get_exception_blocks(self): 121 return self.exception_blocks[-1][-1] 122 123 def add_exception_blocks(self, handler_block, exit_block): 124 self.exception_blocks[-1].append((handler_block, exit_block)) 125 126 def drop_exception_blocks(self): 127 self.exception_blocks[-1].pop() 128 129 def drop_exception_unit(self): 130 self.exception_blocks.pop() 131 132 # Assignment expression values. 133 134 def record_value(self, immediate=1): 135 136 """ 137 Record the current active value for an assignment. If the optional 138 'immediate' parameter is set to a false value, new temporary storage to 139 hold the recorded value will be allocated; otherwise, the 140 value-providing instruction may be replicated in order to provide the 141 active value later on. 142 """ 143 144 if immediate: 145 temp = self.optimiser.optimise_temp_storage() 146 else: 147 temp = self.get_temp() 148 self.expr_temp.append(temp) 149 150 def discard_value(self): 151 152 "Discard any temporary storage in use for the current assignment value." 153 154 self.discard_temp(self.expr_temp.pop()) 155 156 def start_target(self): 157 158 """ 159 Start recording instructions used to define the target of an assignment. 160 """ 161 162 self.target_start = len(self.blocks[-1]) 163 164 def remove_target_ops(self): 165 166 "Remove the assignment target instructions." 167 168 del self.blocks[-1].code[self.target_start:] 169 self.target_start = None 170 self.optimiser.clear_active() 171 172 def get_target_ops(self): 173 174 "Return the assignment target instructions." 175 176 return self.blocks[-1].code[self.target_start:] 177 178 def assign_value(self, expr=None): 179 180 """ 181 Set the source of an assignment using 'expr' or the current assignment 182 value. This may set the source register of the current instruction. 183 """ 184 185 expr = expr or self.expr_temp[-1] 186 187 # Optimise away constant storage if appropriate. 188 189 if self.optimiser.optimise_constant_storage(expr): 190 self.remove_target_ops() 191 return 192 193 # Otherwise, insert the assignment source. 194 195 expr_copy = expr.copy() 196 assign_ops = self.get_target_ops() 197 198 if not assign_ops: 199 self.target_start = None 200 return 201 202 assign_op = assign_ops[-1] 203 204 # Either insert the instruction yielding the value and adjust the 205 # assignment source. 206 207 expr_copy.target = "source" 208 209 if self.insert_op(-1, expr_copy): 210 assign_op.source = "source" 211 self.update_temp(expr, expr_copy) 212 213 # (Now, the instruction need not be inserted.) 214 215 # Or transfer the working value to the source register. 216 217 elif assign_op.working == "working": 218 self.insert_op(-1, Transfer(source="working_context", target="source_context")) 219 self.insert_op(-1, Transfer(source="working", target="source")) 220 assign_op.source = "source" 221 222 # Or let the assignment use the working register. 223 224 else: 225 assign_op.source = "working" 226 227 self.target_start = None 228 229 def set_target(self, target): 230 231 "Reset the target of the active instruction to 'target'." 232 233 self.optimiser.set_target(target) 234 235 def is_immediate_user(self, node): 236 237 """ 238 Return whether 'node' is an immediate user of an assignment expression. 239 """ 240 241 return isinstance(node, (compiler.ast.AssName, compiler.ast.AssAttr)) 242 243 def has_immediate_usage(self, nodes): 244 245 """ 246 Return whether 'nodes' are all immediate users of an assignment expression. 247 """ 248 249 for n in nodes: 250 if not self.is_immediate_user(n): 251 return 0 252 return 1 253 254 # Temporary storage administration. 255 256 def get_temp(self): 257 258 """ 259 Return a temporary storage access instruction for the current value. 260 Initially, this instruction is not associated with an allocated unit of 261 temporary storage, and if used as a new instruction will not be added to 262 the code, but if the current value changes, the 'set_temp' method will 263 be called by the optimiser and a unit of storage will be allocated. 264 """ 265 266 temp = LoadTemp(None) 267 self.optimiser.request_active_value(temp, self.blocks[-1], len(self.blocks[-1].code)) 268 return temp 269 270 def set_temp(self, temp, block, pos): 271 272 """ 273 Emit a storage instruction for the given 'temp' loading instruction, 274 reserving a new temporary storage location. 275 """ 276 277 if temp.attr is None: 278 temp.attr = self.reserve_temp() 279 block.insert(pos, StoreTemp(temp.attr)) 280 281 def update_temp(self, temp, updated): 282 283 "Update 'temp' using the given 'updated' instruction." 284 285 if isinstance(temp, LoadTemp): 286 temp.attr = updated.attr 287 288 def reserve_temp(self, temp_position=None): 289 290 """ 291 Reserve a new temporary storage position, or if the optional 292 'temp_position' is specified, ensure that this particular position is 293 reserved. 294 """ 295 296 if temp_position is not None: 297 pass 298 elif not self.temp_positions: 299 temp_position = 0 300 else: 301 temp_position = max(self.temp_positions) + 1 302 303 self.temp_positions.add(temp_position) 304 self.max_temp_position = max(self.max_temp_position, temp_position) 305 return self.unit.all_local_usage + temp_position # position in frame 306 307 def ensure_temp(self, instruction=None): 308 309 """ 310 Ensure that the 'instruction' is using a reserved temporary storage 311 position. 312 """ 313 314 if isinstance(instruction, LoadTemp): 315 temp_position = instruction.attr - self.unit.all_local_usage 316 self.reserve_temp(temp_position) 317 318 def discard_temp(self, instruction=None): 319 320 "Discard any temporary storage position used by 'instruction'." 321 322 if isinstance(instruction, LoadTemp) and instruction.attr is not None: 323 temp_position = instruction.attr - self.unit.all_local_usage 324 self.free_temp(temp_position) 325 326 # Prevent any requested active value from generating instructions now 327 # that our interest in it has passed. 328 329 self.optimiser.ignore_active_value() 330 331 def free_temp(self, temp_position): 332 333 "Free the temporary storage position specified by 'temp_position'." 334 335 if temp_position in self.temp_positions: 336 self.temp_positions.remove(temp_position) 337 338 def set_frame_usage(self, node, extend): 339 340 """ 341 Ensure that the frame usage for the unit associated with 'node' is set 342 on the 'extend' instruction. 343 """ 344 345 # Remove any ExtendFrame instructions which do nothing. 346 347 if self.last_op() is extend: 348 self.remove_op() 349 return 350 351 ntemp = self.max_temp_position + 1 352 extend.attr = ntemp + node.unit.local_usage # NOTE: See get_code for similar code. 353 354 # Code writing methods. 355 356 def new_op(self, op): 357 358 """ 359 Add 'op' to the generated code, returning a true value if an instruction 360 was added. 361 """ 362 363 if not self.check_op(op): 364 return 0 365 366 # Add the operation to the current block. 367 368 self.optimiser.set_new(op) 369 self.blocks[-1].append(op) 370 return 1 371 372 def insert_op(self, i, op): 373 374 "Insert at index 'i' in the current block the instruction 'op'." 375 376 if not self.check_op(op): 377 return 0 378 379 self.blocks[-1].insert(i, op) 380 return 1 381 382 def check_op(self, op): 383 384 "Return whether the given 'op' is to be added to the code." 385 386 # Optimise away temporary storage instructions where the active value is 387 # still available and was not recorded. 388 389 if isinstance(op, LoadTemp) and op.attr is None: 390 return 0 391 392 # Optimise load operations employed by this instruction. 393 394 if self.optimiser.optimise_away_no_operations(op) or self.optimiser.optimise_unused_handlers(op): 395 return 0 396 397 return 1 398 399 def remove_op(self): 400 401 "Remove the last instruction." 402 403 op = self.blocks[-1].code.pop() 404 self.optimiser.clear_active() 405 return op 406 407 def replace_op(self, op): 408 409 "Replace the last added instruction with 'op'." 410 411 self.remove_op() 412 self.new_op(op) 413 414 def replace_active_value(self, op): 415 416 """ 417 Replace the value-providing active instruction with 'op' if appropriate. 418 """ 419 420 removed = self.optimiser.remove_active_value() 421 self.new_op(op) 422 return removed 423 424 def last_op(self): 425 426 "Return the last added instruction." 427 428 try: 429 return self.blocks[-1].code[-1] 430 except IndexError: 431 return None 432 433 # Allocation-related methods. 434 435 def make_instance(self, cls, n): 436 437 """ 438 Request a new instance using the given class 'cls' and with 'n' 439 attributes. 440 """ 441 442 # Load the class in order to locate the instance template. 443 444 self.new_op(LoadConst(cls)) 445 446 # NOTE: Instance headers are one location. 447 448 self.new_op(MakeInstance(n + 1)) 449 450 def make_exception(self, name): 451 452 "Make an exception of the given 'name' using 'node'." 453 454 # NOTE: Reserving an attribute. 455 456 self.make_instance(self.get_builtin_class(name), 1) 457 458 # Name-related methods. 459 460 def get_scope(self, name): 461 462 "Return the scope for the given 'name'." 463 464 attr, scope, from_name = self.unit._get_with_scope(name) 465 return scope 466 467 def load_builtin(self, name, node): 468 469 "Generate an instruction loading 'name' for the given 'node'." 470 471 self.new_op(LoadAddress(self.get_builtin(name))) 472 473 def get_builtin_class(self, name): 474 475 "Return the built-in class with the given 'name'." 476 477 return self.get_builtin(name).get_value() 478 479 def get_builtin(self, name): 480 481 "Return the built-in module definition for the given 'name'." 482 483 if self.builtins is not None: 484 try: 485 return self.builtins[name] 486 except KeyError: 487 raise TranslateError("No __builtins__ definition is available for name %r." % name) 488 else: 489 raise TranslateError("No __builtins__ module is available for name %r." % name) 490 491 # vim: tabstop=4 expandtab shiftwidth=4