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 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 goto_new_block(self) -> BasicBlock: goto = Goto(INVALID_LABEL) self.add(goto) block = self.new_block() goto.label = block.label return block
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'