def basic_blocks(self, tree, startLabel, endLabel): # divides tree into a list of basic blocks # we assume it has a Seq() at the top, and no other seqs or eseqs assert (isinstance(tree, ir.Seq)) tree.children.append(ir.Label(endLabel, tree.node)) blocks = [] label = startLabel inBlock = 0 block = [] for stm in tree.children: if isinstance(stm, ir.Label): if block == []: block.append(stm) else: # close existing block, create a new one if not self.is_jump(block[-1]): # append a jump to current label block.append(ir.Jump(stm.name, stm.node)) blocks.append(block) block = [stm] else: if block == []: # manufacture a label if first stm is not a label block.append(ir.Label(label, tree.node)) label = self.symbols.newLabel() block.append(stm) if self.is_jump(stm): blocks.append(block) block = [] return blocks
def visit_while_statement(self, node, *args): lbl_start = self.get_id() lbl_body = self.get_id() lbl_end = self.get_id() return [ ir.Label(lbl_start), self.visit(node.condition, ir.COND, lbl_body, lbl_end), ir.Label(lbl_body), list(map(self.visit, node.stmt)), ir.Jump(lbl_start), ir.Label(lbl_end), ]
def visit_if_statement(self, node, *args): lbl_then = self.get_id() lbl_else = self.get_id() lbl_end = self.get_id() return [ self.visit(node.condition, ir.COND, lbl_then, lbl_else), ir.Label(lbl_then), list(map(self.visit, node.stmt_then)), ir.Jump(lbl_end), ir.Label(lbl_else), list(map(self.visit, node.stmt_else)), ir.Label(lbl_end), ]
def add_block_to_trace(self, trace, in_block): # add block to trace. As a side-effect, tidy up last jump to # enforce condition that each cjump must be followed by its # false label block = copy.copy(in_block) # avoid modifying block used by caller target = block[0].name if trace != []: lastjump = trace[-1] if isinstance(lastjump, ir.Jump): if lastjump.dest == target: # remove jumps to the next stm del trace[-1] else: assert (isinstance(lastjump, ir.CJump)) if lastjump.falseDest == target: # no change required pass elif lastjump.trueDest == target: trace[-1] = self.flip_cjump(lastjump) else: # insert extra label and jump to make it work jump = ir.Jump(lastjump.falseDest, lastjump.node) newFalse = self.symbols.newLabel() label = ir.Label(newFalse, lastjump.node) lastjump.falseDest = newFalse trace += [label, jump] trace += block
def visit_bin_op(self, node, target, *args): if node.op in ['+', '-', '*', '%'] or (node.op == '<' and target == ir.EXPR): assert target == ir.EXPR lhs = self.get_id() rhs = self.get_id() arg1, arg2 = self.reorder_for_bin_op(node.left, node.right, lhs, rhs) return [ arg1, arg2, ir.BinOp(node.op, lhs, rhs, args[0]), ] if node.op == '<': assert target == ir.COND lhs = self.get_id() rhs = self.get_id() arg1, arg2 = self.reorder_for_bin_op(node.left, node.right, lhs, rhs) return [ arg1, arg2, ir.CJumpLess(lhs, rhs, args[0], args[1]), ] if node.op == '&&': if target == ir.COND: lbl_second_arg = self.get_id() return [ self.visit(node.left, ir.COND, lbl_second_arg, args[1]), ir.Label(lbl_second_arg), self.visit(node.right, ir.COND, args[0], args[1]), ] else: lbl_second_arg = self.get_id() lbl_false = self.get_id() lbl_true = self.get_id() lbl_end = self.get_id() return [ self.visit(node.left, ir.COND, lbl_second_arg, lbl_false), ir.Label(lbl_second_arg), self.visit(node.right, ir.COND, lbl_true, lbl_false), ir.Label(lbl_true), ir.Const(1, args[0]), ir.Jump(lbl_end), ir.Label(lbl_false), ir.Const(0, args[0]), ir.Label(lbl_end), ] if node.op == '||': if target == ir.COND: lbl_second_arg = self.get_id() return [ self.visit(node.left, ir.COND, args[0], lbl_second_arg), ir.Label(lbl_second_arg), self.visit(node.right, ir.COND, args[0], args[1]), ] else: lbl_second_arg = self.get_id() lbl_false = self.get_id() lbl_true = self.get_id() lbl_end = self.get_id() return [ self.visit(node.left, ir.COND, lbl_true, lbl_second_arg), ir.Label(lbl_second_arg), self.visit(node.right, ir.COND, lbl_true, lbl_false), ir.Label(lbl_false), ir.Const(0, args[0]), ir.Jump(lbl_end), ir.Label(lbl_true), ir.Const(1, args[0]), ir.Label(lbl_end), ] assert False
def label(self, name): return ir.Label(name, self.fakeNode)