Esempio n. 1
0
def faster_min_max(builder: IRBuilder, expr: CallExpr,
                   callee: RefExpr) -> Optional[Value]:
    if expr.arg_kinds == [ARG_POS, ARG_POS]:
        x, y = builder.accept(expr.args[0]), builder.accept(expr.args[1])
        result = Register(builder.node_type(expr))
        # CPython evaluates arguments reversely when calling min(...) or max(...)
        if callee.fullname == 'builtins.min':
            comparison = builder.binary_op(y, x, '<', expr.line)
        else:
            comparison = builder.binary_op(y, x, '>', expr.line)

        true_block, false_block, next_block = BasicBlock(), BasicBlock(
        ), BasicBlock()
        builder.add_bool_branch(comparison, true_block, false_block)

        builder.activate_block(true_block)
        builder.assign(result, builder.coerce(y, result.type, expr.line),
                       expr.line)
        builder.goto(next_block)

        builder.activate_block(false_block)
        builder.assign(result, builder.coerce(x, result.type, expr.line),
                       expr.line)
        builder.goto(next_block)

        builder.activate_block(next_block)
        return result
    return None
Esempio n. 2
0
def transform_op_expr(builder: IRBuilder, expr: OpExpr) -> Value:
    if expr.op in ('and', 'or'):
        return builder.shortcircuit_expr(expr)

    # Special case for string formatting
    if expr.op == '%' and (isinstance(expr.left, StrExpr)
                           or isinstance(expr.left, BytesExpr)):
        ret = translate_printf_style_formatting(builder, expr.left, expr.right)
        if ret is not None:
            return ret

    folded = try_constant_fold(builder, expr)
    if folded:
        return folded

    # Special case some int ops to allow borrowing operands.
    if (is_int_rprimitive(builder.node_type(expr.left))
            and is_int_rprimitive(builder.node_type(expr.right))):
        if expr.op in int_borrow_friendly_op:
            borrow_left = is_borrow_friendly_expr(builder, expr.right)
            left = builder.accept(expr.left, can_borrow=borrow_left)
            right = builder.accept(expr.right, can_borrow=True)
            return builder.binary_op(left, right, expr.op, expr.line)

    return builder.binary_op(builder.accept(expr.left),
                             builder.accept(expr.right), expr.op, expr.line)
Esempio n. 3
0
def transform_op_expr(builder: IRBuilder, expr: OpExpr) -> Value:
    if expr.op in ('and', 'or'):
        return builder.shortcircuit_expr(expr)

    # Special case for string formatting
    if expr.op == '%' and isinstance(expr.left, StrExpr):
        return translate_str_format_percent_sign(builder, expr.left,
                                                 expr.right)

    return builder.binary_op(builder.accept(expr.left),
                             builder.accept(expr.right), expr.op, expr.line)
Esempio n. 4
0
def transform_operator_assignment_stmt(builder: IRBuilder, stmt: OperatorAssignmentStmt) -> None:
    """Operator assignment statement such as x += 1"""
    builder.disallow_class_assignments([stmt.lvalue], stmt.line)
    target = builder.get_assignment_target(stmt.lvalue)
    target_value = builder.read(target, stmt.line)
    rreg = builder.accept(stmt.rvalue)
    # the Python parser strips the '=' from operator assignment statements, so re-add it
    op = stmt.op + '='
    res = builder.binary_op(target_value, rreg, op, stmt.line)
    # usually operator assignments are done in-place
    # but when target doesn't support that we need to manually assign
    builder.assign(target, res, res.line)
Esempio n. 5
0
def transform_basic_comparison(builder: IRBuilder, op: str, left: Value,
                               right: Value, line: int) -> Value:
    negate = False
    if op == 'is not':
        op, negate = 'is', True
    elif op == 'not in':
        op, negate = 'in', True

    target = builder.binary_op(left, right, op, line)

    if negate:
        target = builder.unary_op(target, 'not', line)
    return target
Esempio n. 6
0
def populate_switch_for_generator_class(builder: IRBuilder) -> None:
    cls = builder.fn_info.generator_class
    line = builder.fn_info.fitem.line

    builder.activate_block(cls.switch_block)
    for label, true_block in enumerate(cls.continuation_blocks):
        false_block = BasicBlock()
        comparison = builder.binary_op(cls.next_label_reg,
                                       builder.add(LoadInt(label)), '==', line)
        builder.add_bool_branch(comparison, true_block, false_block)
        builder.activate_block(false_block)

    builder.add(
        RaiseStandardError(RaiseStandardError.STOP_ITERATION, None, line))
    builder.add(Unreachable())
Esempio n. 7
0
def transform_basic_comparison(builder: IRBuilder, op: str, left: Value,
                               right: Value, line: int) -> Value:
    if (is_int_rprimitive(left.type) and is_int_rprimitive(right.type)
            and op in int_comparison_op_mapping.keys()):
        return builder.compare_tagged(left, right, op, line)
    negate = False
    if op == 'is not':
        op, negate = 'is', True
    elif op == 'not in':
        op, negate = 'in', True

    target = builder.binary_op(left, right, op, line)

    if negate:
        target = builder.unary_op(target, 'not', line)
    return target
Esempio n. 8
0
def transform_op_expr(builder: IRBuilder, expr: OpExpr) -> Value:
    if expr.op in ('and', 'or'):
        return builder.shortcircuit_expr(expr)

    # Special case for string formatting
    if expr.op == '%' and (isinstance(expr.left, StrExpr) or isinstance(expr.left, BytesExpr)):
        ret = translate_printf_style_formatting(builder, expr.left, expr.right)
        if ret is not None:
            return ret

    folded = try_constant_fold(builder, expr)
    if folded:
        return folded

    return builder.binary_op(
        builder.accept(expr.left), builder.accept(expr.right), expr.op, expr.line
    )
Esempio n. 9
0
def transform_operator_assignment_stmt(builder: IRBuilder, stmt: OperatorAssignmentStmt) -> None:
    """Operator assignment statement such as x += 1"""
    builder.disallow_class_assignments([stmt.lvalue], stmt.line)
    if (is_tagged(builder.node_type(stmt.lvalue))
            and is_tagged(builder.node_type(stmt.rvalue))
            and stmt.op in int_borrow_friendly_op):
        can_borrow = (is_borrow_friendly_expr(builder, stmt.rvalue)
                      and is_borrow_friendly_expr(builder, stmt.lvalue))
    else:
        can_borrow = False
    target = builder.get_assignment_target(stmt.lvalue)
    target_value = builder.read(target, stmt.line, can_borrow=can_borrow)
    rreg = builder.accept(stmt.rvalue, can_borrow=can_borrow)
    # the Python parser strips the '=' from operator assignment statements, so re-add it
    op = stmt.op + '='
    res = builder.binary_op(target_value, rreg, op, stmt.line)
    # usually operator assignments are done in-place
    # but when target doesn't support that we need to manually assign
    builder.assign(target, res, res.line)
Esempio n. 10
0
def gen_glue_ne_method(builder: IRBuilder, cls: ClassIR, line: int) -> FuncIR:
    """Generate a "__ne__" method from a "__eq__" method. """
    builder.enter()

    rt_args = (RuntimeArg("self", RInstance(cls)), RuntimeArg("rhs", object_rprimitive))

    # The environment operates on Vars, so we make some up
    fake_vars = [(Var(arg.name), arg.type) for arg in rt_args]
    args = [
        builder.read(
            builder.environment.add_local_reg(
                var, type, is_arg=True
            ),
            line
        )
        for var, type in fake_vars
    ]  # type: List[Value]
    builder.ret_types[-1] = object_rprimitive

    # If __eq__ returns NotImplemented, then __ne__ should also
    not_implemented_block, regular_block = BasicBlock(), BasicBlock()
    eqval = builder.add(MethodCall(args[0], '__eq__', [args[1]], line))
    not_implemented = builder.primitive_op(not_implemented_op, [], line)
    builder.add(Branch(
        builder.binary_op(eqval, not_implemented, 'is', line),
        not_implemented_block,
        regular_block,
        Branch.BOOL_EXPR))

    builder.activate_block(regular_block)
    retval = builder.coerce(
        builder.unary_op(eqval, 'not', line), object_rprimitive, line
    )
    builder.add(Return(retval))

    builder.activate_block(not_implemented_block)
    builder.add(Return(not_implemented))

    blocks, env, ret_type, _ = builder.leave()
    return FuncIR(
        FuncDecl('__ne__', cls.name, builder.module_name,
                 FuncSignature(rt_args, ret_type)),
        blocks, env)
Esempio n. 11
0
def add_raise_exception_blocks_to_generator_class(builder: IRBuilder,
                                                  line: int) -> None:
    """
    Generates blocks to check if error flags are set while calling the helper method for
    generator functions, and raises an exception if those flags are set.
    """
    cls = builder.fn_info.generator_class
    assert cls.exc_regs is not None
    exc_type, exc_val, exc_tb = cls.exc_regs

    # Check to see if an exception was raised.
    error_block = BasicBlock()
    ok_block = BasicBlock()
    comparison = builder.binary_op(exc_type, builder.none_object(), 'is not',
                                   line)
    builder.add_bool_branch(comparison, error_block, ok_block)

    builder.activate_block(error_block)
    builder.primitive_op(raise_exception_with_tb_op,
                         [exc_type, exc_val, exc_tb], line)
    builder.add(Unreachable())
    builder.goto_and_activate(ok_block)
Esempio n. 12
0
def add_get_to_callable_class(builder: IRBuilder, fn_info: FuncInfo) -> None:
    """Generate the '__get__' method for a callable class."""
    line = fn_info.fitem.line
    builder.enter(fn_info)

    vself = builder.read(
        builder.environment.add_local_reg(Var(SELF_NAME), object_rprimitive, True)
    )
    instance = builder.environment.add_local_reg(Var('instance'), object_rprimitive, True)
    builder.environment.add_local_reg(Var('owner'), object_rprimitive, True)

    # If accessed through the class, just return the callable
    # object. If accessed through an object, create a new bound
    # instance method object.
    instance_block, class_block = BasicBlock(), BasicBlock()
    comparison = builder.binary_op(
        builder.read(instance), builder.none_object(), 'is', line
    )
    builder.add_bool_branch(comparison, class_block, instance_block)

    builder.activate_block(class_block)
    builder.add(Return(vself))

    builder.activate_block(instance_block)
    builder.add(Return(builder.primitive_op(method_new_op, [vself, builder.read(instance)], line)))

    blocks, env, _, fn_info = builder.leave()

    sig = FuncSignature((RuntimeArg(SELF_NAME, object_rprimitive),
                         RuntimeArg('instance', object_rprimitive),
                         RuntimeArg('owner', object_rprimitive)),
                        object_rprimitive)
    get_fn_decl = FuncDecl('__get__', fn_info.callable_class.ir.name, builder.module_name, sig)
    get_fn_ir = FuncIR(get_fn_decl, blocks, env)
    fn_info.callable_class.ir.methods['__get__'] = get_fn_ir
    builder.functions.append(get_fn_ir)
Esempio n. 13
0
def translate_is_none(builder: IRBuilder, expr: Expression, negated: bool) -> Value:
    v = builder.accept(expr, can_borrow=True)
    return builder.binary_op(v, builder.none_object(), 'is not' if negated else 'is', expr.line)
Esempio n. 14
0
def transform_op_expr(builder: IRBuilder, expr: OpExpr) -> Value:
    if expr.op in ('and', 'or'):
        return builder.shortcircuit_expr(expr)
    return builder.binary_op(builder.accept(expr.left),
                             builder.accept(expr.right), expr.op, expr.line)