def gen_return(self, builder: 'IRBuilder', value: Value, line: int) -> None: if self.ret_reg is None: self.ret_reg = builder.alloc_temp(builder.ret_types[-1]) builder.add(Assign(self.ret_reg, value)) builder.add(Goto(self.target))
def add_leave(self) -> Optional[Goto]: if not self.blocks[-1][-1].ops or not isinstance( self.blocks[-1][-1].ops[-1], Return): leave = Goto(INVALID_LABEL) self.add(leave) return leave return None
def add_block(ops: Iterable[Op], blocks: List[BasicBlock], label: Label) -> Label: block = BasicBlock(Label(len(blocks))) block.ops.extend(ops) block.ops.append(Goto(label)) blocks.append(block) return block.label
def visit_while_stmt(self, s: WhileStmt) -> Register: self.push_loop_stack() # Split block so that we get a handle to the top of the loop. goto = Goto(INVALID_LABEL) self.add(goto) top = self.new_block() goto.label = top.label branches = self.process_conditional(s.expr) body = self.new_block() # Bind "true" branches to the body block. self.set_branches(branches, True, body) s.body.accept(self) # Add branch to the top at the end of the body. self.add(Goto(top.label)) next = self.new_block() # Bind "false" branches to the new block. self.set_branches(branches, False, next) self.pop_loop_stack(top, next) return INVALID_REGISTER
def add_block(decincs: DecIncs, cache: BlockCache, blocks: List[BasicBlock], label: BasicBlock) -> BasicBlock: decs, incs = decincs if not decs and not incs: return label # TODO: be able to share *partial* results if (label, decincs) in cache: return cache[label, decincs] block = BasicBlock() blocks.append(block) block.ops.extend(DecRef(reg, is_xdec=xdec) for reg, xdec in decs) block.ops.extend(IncRef(reg) for reg in incs) block.ops.append(Goto(label)) cache[label, decincs] = block return block
def visit_conditional_expr(self, expr: ConditionalExpr) -> Register: branches = self.process_conditional(expr.cond) target = self.alloc_target(self.node_type(expr)) if_body = self.new_block() self.set_branches(branches, True, if_body) self.accept(expr.if_expr, target=target) if_goto_next = Goto(INVALID_LABEL) self.add(if_goto_next) else_body = self.new_block() self.set_branches(branches, False, else_body) self.accept(expr.else_expr, target=target) else_goto_next = Goto(INVALID_LABEL) self.add(else_goto_next) next = self.new_block() if_goto_next.label = next.label else_goto_next.label = next.label return target
def test_goto(self) -> None: self.assert_emit(Goto(BasicBlock(2)), "goto CPyL2;")
def goto(self, target: BasicBlock) -> None: if not self.blocks[-1].terminated: self.add(Goto(target))
def goto(self, target: BasicBlock) -> None: if not self.blocks[-1][-1].ops or not isinstance(self.blocks[-1][-1].ops[-1], ControlOp): self.add(Goto(target))
def gen_continue(self, builder: 'IRBuilder', line: int) -> None: builder.add(Goto(self.continue_block))
def gen_break(self, builder: 'IRBuilder', line: int) -> None: builder.add(Goto(self.break_block))
def goto_new_block(self) -> BasicBlock: goto = Goto(INVALID_LABEL) self.add(goto) block = self.new_block() goto.label = block.label return block
def visit_continue_stmt(self, node: ContinueStmt) -> Register: self.continue_gotos[-1].append(Goto(INVALID_LABEL)) self.add(self.continue_gotos[-1][-1]) return INVALID_REGISTER
def visit_break_stmt(self, node: BreakStmt) -> Register: self.break_gotos[-1].append(Goto(INVALID_LABEL)) self.add(self.break_gotos[-1][-1]) return INVALID_REGISTER
def visit_for_stmt(self, s: ForStmt) -> Register: if (isinstance(s.expr, CallExpr) and isinstance(s.expr.callee, RefExpr) and s.expr.callee.fullname == 'builtins.range'): self.push_loop_stack() # Special case for x in range(...) # TODO: Check argument counts and kinds; check the lvalue end = s.expr.args[0] end_reg = self.accept(end) # Initialize loop index to 0. index_reg = self.assign(s.index, IntExpr(0), IntRType(), IntRType(), declare_new=True) goto = Goto(INVALID_LABEL) self.add(goto) # Add loop condition check. top = self.new_block() goto.label = top.label branch = Branch(index_reg, end_reg, INVALID_LABEL, INVALID_LABEL, Branch.INT_LT) self.add(branch) branches = [branch] body = self.new_block() self.set_branches(branches, True, body) s.body.accept(self) end_goto = Goto(INVALID_LABEL) self.add(end_goto) end_block = self.new_block() end_goto.label = end_block.label # Increment index register. one_reg = self.alloc_temp(IntRType()) self.add(LoadInt(one_reg, 1)) self.add( PrimitiveOp(index_reg, PrimitiveOp.INT_ADD, index_reg, one_reg)) # Go back to loop condition check. self.add(Goto(top.label)) next = self.new_block() self.set_branches(branches, False, next) self.pop_loop_stack(end_block, next) return INVALID_REGISTER if self.node_type(s.expr).name == 'list': self.push_loop_stack() expr_reg = self.accept(s.expr) index_reg = self.alloc_temp(IntRType()) self.add(LoadInt(index_reg, 0)) one_reg = self.alloc_temp(IntRType()) self.add(LoadInt(one_reg, 1)) assert isinstance(s.index, NameExpr) assert isinstance(s.index.node, Var) lvalue_reg = self.environment.add_local(s.index.node, self.node_type(s.index)) condition_block = self.goto_new_block() # For compatibility with python semantics we recalculate the length # at every iteration. len_reg = self.alloc_temp(IntRType()) self.add(PrimitiveOp(len_reg, PrimitiveOp.LIST_LEN, expr_reg)) branch = Branch(index_reg, len_reg, INVALID_LABEL, INVALID_LABEL, Branch.INT_LT) self.add(branch) branches = [branch] body_block = self.new_block() self.set_branches(branches, True, body_block) target_list_type = self.types[s.expr] assert isinstance(target_list_type, Instance) target_type = self.type_to_rtype(target_list_type.args[0]) value_box = self.alloc_temp(ObjectRType()) self.add( PrimitiveOp(value_box, PrimitiveOp.LIST_GET, expr_reg, index_reg)) self.unbox_or_cast(value_box, target_type, target=lvalue_reg) s.body.accept(self) end_block = self.goto_new_block() self.add( PrimitiveOp(index_reg, PrimitiveOp.INT_ADD, index_reg, one_reg)) self.add(Goto(condition_block.label)) next_block = self.new_block() self.set_branches(branches, False, next_block) self.pop_loop_stack(end_block, next_block) return INVALID_REGISTER assert False, 'for not supported'
def test_goto(self) -> None: self.assert_emit(Goto(Label(2)), "goto CPyL2;")