def test_branch(self) -> None:
     self.assert_emit(
         Branch(self.b, BasicBlock(8), BasicBlock(9), Branch.BOOL),
         """if (cpy_r_b) {
                             goto CPyL8;
                         } else
                             goto CPyL9;
                      """)
     b = Branch(self.b, BasicBlock(8), BasicBlock(9), Branch.BOOL)
     b.negated = True
     self.assert_emit(
         b, """if (!cpy_r_b) {
                             goto CPyL8;
                         } else
                             goto CPyL9;
                      """)
Esempio n. 2
0
 def test_branch_is_error(self) -> None:
     b = Branch(self.b, BasicBlock(8), BasicBlock(9), Branch.IS_ERROR)
     self.assert_emit(
         b, """if (cpy_r_b == 2) {
                             goto CPyL8;
                         } else
                             goto CPyL9;
                      """)
     b = Branch(self.b, BasicBlock(8), BasicBlock(9), Branch.IS_ERROR)
     b.negated = True
     self.assert_emit(
         b, """if (cpy_r_b != 2) {
                             goto CPyL8;
                         } else
                             goto CPyL9;
                      """)
Esempio n. 3
0
 def compare_tagged(self, lhs: Value, rhs: Value, op: str, line: int) -> Value:
     """Compare two tagged integers using given op"""
     op_type, c_func_desc = int_logical_op_mapping[op]
     result = self.alloc_temp(bool_rprimitive)
     short_int_block, int_block, out = BasicBlock(), BasicBlock(), BasicBlock()
     check = self.check_tagged_short_int(lhs, line)
     branch = Branch(check, short_int_block, int_block, Branch.BOOL_EXPR)
     branch.negated = False
     self.add(branch)
     self.activate_block(short_int_block)
     eq = self.binary_int_op(bool_rprimitive, lhs, rhs, op_type, line)
     self.add(Assign(result, eq, line))
     self.goto(out)
     self.activate_block(int_block)
     call = self.call_c(c_func_desc, [lhs, rhs], line)
     self.add(Assign(result, call, line))
     self.goto_and_activate(out)
     return result
Esempio n. 4
0
 def test_cast_and_branch_no_merge_2(self) -> None:
     op = Cast(self.r, dict_rprimitive, 1)
     next_block = BasicBlock(9)
     branch = Branch(op, BasicBlock(8), next_block, Branch.IS_ERROR)
     branch.negated = True
     branch.traceback_entry = ('foobar', 123)
     self.assert_emit(
         op,
         """\
         if (likely(PyDict_Check(cpy_r_r)))
             cpy_r_r0 = cpy_r_r;
         else {
             CPy_TypeError("dict", cpy_r_r);
             cpy_r_r0 = NULL;
         }
         """,
         next_block=next_block,
         next_branch=branch,
     )
Esempio n. 5
0
 def compare_tagged(self, lhs: Value, rhs: Value, op: str,
                    line: int) -> Value:
     """Compare two tagged integers using given op"""
     # generate fast binary logic ops on short ints
     if is_short_int_rprimitive(lhs.type) and is_short_int_rprimitive(
             rhs.type):
         return self.comparison_op(lhs, rhs,
                                   int_comparison_op_mapping[op][0], line)
     op_type, c_func_desc, negate_result, swap_op = int_comparison_op_mapping[
         op]
     result = self.alloc_temp(bool_rprimitive)
     short_int_block, int_block, out = BasicBlock(), BasicBlock(
     ), BasicBlock()
     check_lhs = self.check_tagged_short_int(lhs, line)
     if op in ("==", "!="):
         check = check_lhs
     else:
         # for non-equal logical ops(less than, greater than, etc.), need to check both side
         check_rhs = self.check_tagged_short_int(rhs, line)
         check = self.binary_int_op(bool_rprimitive, check_lhs, check_rhs,
                                    BinaryIntOp.AND, line)
     branch = Branch(check, short_int_block, int_block, Branch.BOOL_EXPR)
     branch.negated = False
     self.add(branch)
     self.activate_block(short_int_block)
     eq = self.comparison_op(lhs, rhs, op_type, line)
     self.add(Assign(result, eq, line))
     self.goto(out)
     self.activate_block(int_block)
     if swap_op:
         args = [rhs, lhs]
     else:
         args = [lhs, rhs]
     call = self.call_c(c_func_desc, args, line)
     if negate_result:
         # TODO: introduce UnaryIntOp?
         call_result = self.unary_op(call, "not", line)
     else:
         call_result = call
     self.add(Assign(result, call_result, line))
     self.goto_and_activate(out)
     return result
Esempio n. 6
0
def split_blocks_at_errors(blocks: List[BasicBlock],
                           default_error_handler: BasicBlock,
                           func_name: Optional[str]) -> List[BasicBlock]:
    new_blocks = []  # type: List[BasicBlock]

    # First split blocks on ops that may raise.
    for block in blocks:
        ops = block.ops
        block.ops = []
        cur_block = block
        new_blocks.append(cur_block)

        # If the block has an error handler specified, use it. Otherwise
        # fall back to the default.
        error_label = block.error_handler or default_error_handler
        block.error_handler = None

        for op in ops:
            target = op
            cur_block.ops.append(op)
            if isinstance(op, RegisterOp) and op.error_kind != ERR_NEVER:
                # Split
                new_block = BasicBlock()
                new_blocks.append(new_block)

                if op.error_kind == ERR_MAGIC:
                    # Op returns an error value on error that depends on result RType.
                    variant = Branch.IS_ERROR
                    negated = False
                elif op.error_kind == ERR_FALSE:
                    # Op returns a C false value on error.
                    variant = Branch.BOOL
                    negated = True
                elif op.error_kind == ERR_ALWAYS:
                    variant = Branch.BOOL
                    negated = True
                    # this is a hack to represent the always fail
                    # semantics, using a temporary bool with value false
                    tmp = LoadInt(0, rtype=bool_rprimitive)
                    cur_block.ops.append(tmp)
                    target = tmp
                else:
                    assert False, 'unknown error kind %d' % op.error_kind

                # Void ops can't generate errors since error is always
                # indicated by a special value stored in a register.
                if op.error_kind != ERR_ALWAYS:
                    assert not op.is_void, "void op generating errors?"

                branch = Branch(target,
                                true_label=error_label,
                                false_label=new_block,
                                op=variant,
                                line=op.line)
                branch.negated = negated
                if op.line != NO_TRACEBACK_LINE_NO and func_name is not None:
                    branch.traceback_entry = (func_name, op.line)
                cur_block.ops.append(branch)
                cur_block = new_block

    return new_blocks