def optimize(self, expr: BinaryOp):

        if expr.op == "Add" and len(expr.operands) == 2:
            op0, op1 = expr.operands
            if isinstance(op0, BinaryOp) and op0.op == "Div" and isinstance(
                    op0.operands[1], Const):
                if isinstance(op1,
                              BinaryOp) and op1.op == "Div" and isinstance(
                                  op1.operands[1], Const):
                    if isinstance(op1.operands[0], BinaryOp) and op1.operands[0].op == "Mul" and \
                            isinstance(op1.operands[0].operands[1], Const):
                        a0 = op0.operands[0]
                        a1 = op1.operands[0].operands[0]
                        if a0.likes(a1):
                            N0 = op0.operands[1]
                            N1: int = op1.operands[0].operands[1].value
                            if N0.value == op1.operands[1].value:
                                mul = BinaryOp(op0.idx, "Mul", [
                                    a0,
                                    Const(None, None, N1 + 1, expr.bits, **
                                          expr.operands[0].operands[1].tags)
                                ], False, **op0.tags)
                                div = BinaryOp(expr.idx, "Div", [mul, N0],
                                               False, **expr.tags)
                                return div

        return None
Beispiel #2
0
    def optimize(self, expr: BinaryOp):

        if expr.op == "Shr" and len(expr.operands) == 2 and isinstance(expr.operands[1], Const) \
                and isinstance(expr.operands[0], BinaryOp) and expr.operands[0].op == "Div" \
                and isinstance(expr.operands[0].operands[1], Const):
            inner = expr.operands[0].operands[0]
            if isinstance(inner, BinaryOp) and inner.op == "Mul" and isinstance(inner.operands[1], Const):
                a = inner.operands[0]
                N0 = inner.operands[1].value
                N1 = expr.operands[0].operands[1]
                N2 = expr.operands[1].value

                mul = BinaryOp(inner.idx, "Mul",
                               [a,
                                Const(None, None, N0 // (2 ** N2), expr.bits, **expr.operands[0].operands[1].tags)
                                ],
                               False,
                               **inner.tags)
                div = BinaryOp(expr.idx, "Div",
                               [mul,
                                N1],
                               False,
                               **expr.tags)
                return div

        return None
    def optimize(self, expr: BinaryOp):

        if isinstance(expr.operands[0], Convert):
            if (expr.operands[0].to_bits == 32  # converting to an int
                and isinstance(expr.operands[1], Const)
            ):
                if expr.op == "And":
                    if expr.operands[0].from_bits == 16 and expr.operands[1].value <= 0xffff:
                        con = Const(None, None, expr.operands[1].value, 16, **expr.operands[1].tags)
                        new_expr = BinaryOp(expr.idx, "And", (expr.operands[0].operand, con), expr.signed,
                                        bits=16, **expr.tags)
                        return Convert(expr.operands[0].idx, 16, 32, expr.operands[0].is_signed, new_expr,
                                       **expr.operands[0].tags)
                    elif expr.operands[0].from_bits == 8 and expr.operands[1].value <= 0xff:
                        con = Const(None, None, expr.operands[1].value, 8, **expr.operands[1].tags)
                        new_expr = BinaryOp(expr.idx, "And", (expr.operands[0].operand, con), expr.signed,
                                        bits=8, **expr.tags)
                        return Convert(expr.operands[0].idx, 8, 32, expr.operands[0].is_signed, new_expr,
                                       **expr.operands[0].tags)

                elif expr.op in {"CmpEQ", "CmpNE", "CmpGT", "CmpGE", "CmpGTs", "CmpGEs", "CmpLT", "CmpLE", "CmpLTs", "CmpLEs"}:
                    if expr.operands[0].from_bits == 16 and expr.operands[1].value <= 0xffff:
                        con = Const(None, None, expr.operands[1].value, 16, **expr.operands[1].tags)
                        new_expr = BinaryOp(expr.idx, expr.op, (expr.operands[0].operand, con), expr.signed,
                                            bits=16, **expr.tags)
                        return new_expr
                    elif expr.operands[0].from_bits == 8 and expr.operands[1].value <= 0xff:
                        con = Const(None, None, expr.operands[1].value, 8, **expr.operands[1].tags)
                        new_expr = BinaryOp(expr.idx, expr.op, (expr.operands[0].operand, con), expr.signed,
                                            bits=8, **expr.tags)
                        return new_expr

            elif (isinstance(expr.operands[1], Convert)
                  and expr.operands[1].to_bits == expr.operands[0].to_bits
                  and expr.operands[1].from_bits == expr.operands[0].from_bits
            ):
                if expr.op in {"Add", "Sub"}:
                    op0 = expr.operands[0]
                    op0_inner = expr.operands[0].operand
                    # op1 = expr.operands[1]
                    op1_inner = expr.operands[1].operand

                    new_expr = BinaryOp(expr.idx, expr.op, (op0_inner, op1_inner), expr.signed,
                                        bits=op0.from_bits, **expr.tags,
                                        )
                    r = Convert(expr.idx, op0.from_bits, op0.to_bits, op0.is_signed, new_expr,
                                **op0.tags,
                                )
                    return r

        return None
Beispiel #4
0
    def optimize(self, expr: BinaryOp):

        # (Conv(M->N, expr) << P) >> Q  ==>  (Conv(M->N, expr) & bitmask) >> (Q-P), where
        #       Q >= P, and
        #       M < N, and
        #       bitmask = 0b('1' * (N - P))
        if expr.op == "Shr" and isinstance(expr.operands[1], Const):
            q = expr.operands[1].value
            expr_b = expr.operands[0]
            if isinstance(expr_b,
                          BinaryOp) and expr_b.op == "Shl" and isinstance(
                              expr_b.operands[1], Const):
                p = expr_b.operands[1].value
                expr_a = expr_b.operands[0]
                if q >= p and isinstance(expr_a,
                                         Convert) and not expr_a.is_signed:
                    m = expr_a.from_bits
                    n = expr_a.to_bits
                    if m < n and n >= p:
                        bitmask = (1 << (n - p)) - 1
                        and_expr = BinaryOp(
                            None,
                            'And',
                            (
                                Convert(expr_a.idx, m, n, False,
                                        expr_a.operand, **expr_a.tags),
                                Const(None, None, bitmask, n),
                            ),
                            False,
                            variable=None,
                            variable_offset=None,
                            **expr.tags,
                        )
                        return BinaryOp(
                            None,
                            'Shr',
                            (
                                and_expr,
                                Const(None, None, q - p, and_expr.bits),
                            ),
                            False,
                            **expr.tags,
                        )

        return None
Beispiel #5
0
    def optimize(self, expr: BinaryOp):

        if expr.op == "Sub" and len(expr.operands) == 2 \
                and isinstance(expr.operands[1], BinaryOp) and expr.operands[1].op == "Div" \
                and isinstance(expr.operands[1].operands[1], Const):
            a = expr.operands[0]
            if expr.operands[1].operands[0].likes(a):
                N = expr.operands[1].operands[1].value
                mul = BinaryOp(expr.idx, "Mul",
                               [a, Const(None, None, N - 1, expr.bits)], False,
                               **expr.tags)
                div = BinaryOp(expr.operands[1].idx, "Div", [
                    mul,
                    Const(None, None, N, expr.bits, **expr.operands[1].tags)
                ], False, **expr.operands[1].tags)
                return div

        return None
Beispiel #6
0
    def optimize(self, expr: Convert):

        # Conv(M->1, ((expr) >> N) & 1) => expr < 0
        # Conv(M->1, ((expr - 0) >> N) & 1) => expr < 0
        if expr.to_bits == 1:
            if isinstance(expr.operand, BinaryOp) and expr.operand.op == "And" \
                    and isinstance(expr.operand.operands[1], Const) \
                    and expr.operand.operands[1].value == 1:
                # taking a single bit
                inner_expr = expr.operand.operands[0]
                if isinstance(inner_expr, BinaryOp) and inner_expr.op == "Shr" \
                        and isinstance(inner_expr.operands[1], Const):
                    # right-shifting with a constant
                    shr_amount = inner_expr.operands[1].value
                    if shr_amount == 7:
                        # int8_t
                        to_bits = 8
                    elif shr_amount == 15:
                        # int16_t
                        to_bits = 16
                    elif shr_amount == 31:
                        # int32_t
                        to_bits = 32
                    elif shr_amount == 63:
                        # int64_t
                        to_bits = 64
                    else:
                        # unsupported
                        return None

                    real_expr = inner_expr.operands[0]

                    if isinstance(real_expr, BinaryOp) and real_expr.op == "Sub" \
                            and isinstance(real_expr.operands[1], Const) \
                            and real_expr.operands[1].value == 0:
                        real_expr = real_expr.operands[0]

                    cvt = Convert(expr.idx, real_expr.bits, to_bits, False,
                                  real_expr, **expr.tags)
                    cmp = BinaryOp(
                        None,
                        "CmpLT",
                        (
                            cvt,
                            Const(None, None, 0, to_bits),
                        ),
                        True,
                        **expr.tags,
                    )
                    return cmp

        return None
Beispiel #7
0
 def _handle_BinaryOp(self, expr_idx: int, expr: BinaryOp, stmt_idx: int, stmt: Statement, block: Block):
     new_operands = [ self._handle_expr(0, expr.operands[0], stmt_idx, stmt, block),
                      self._handle_expr(1, expr.operands[1], stmt_idx, stmt, block),
                      ]
     if any(op is not None for op in new_operands):
         new_operands = [(new_op if new_op is not None else old_op) for new_op, old_op in zip(new_operands, expr.operands)]
         return BinaryOp(expr.idx, expr.op,
                         new_operands,
                         expr.signed,
                         variable=expr.variable,
                         variable_offset=expr.variable_offset,
                         **expr.tags
                         )
     return None
Beispiel #8
0
    def optimize(self, expr: BinaryOp):

        if expr.op == "Sub" and len(expr.operands) == 2 \
                and isinstance(expr.operands[0], BinaryOp) and expr.operands[0].op == "Shl" \
                and isinstance(expr.operands[0].operands[1], Const):
            a = expr.operands[1]
            if expr.operands[0].operands[0].likes(a):
                N = expr.operands[0].operands[1].value
                return BinaryOp(expr.idx, "Mul",
                                [a,
                                 Const(None, None, 2 ** N - 1, expr.bits, **expr.operands[0].operands[1].tags)
                                 ],
                                False,
                                **expr.tags)

        return None
Beispiel #9
0
    def optimize(self, expr: BinaryOp):

        if expr.op == "Sub" and len(expr.operands) == 2 \
                and isinstance(expr.operands[1], BinaryOp) and expr.operands[1].op == "Mul" \
                and isinstance(expr.operands[1].operands[1], Const):
            a0 = expr.operands[0]
            op1 = expr.operands[1]
            mul_const = expr.operands[1].operands[1]
            if isinstance(op1.operands[0], BinaryOp) and op1.operands[0].op == "Div" and \
                    isinstance(op1.operands[0].operands[1], Const):
                a1 = op1.operands[0].operands[0]
                div_const = op1.operands[0].operands[1]

                if a0.likes(a1) and mul_const.value == div_const.value:
                    mod = BinaryOp(expr.idx, "DivMod", [a0, div_const], False,
                                   **expr.tags)
                    return mod

        return None
Beispiel #10
0
    def optimize(self, expr: Convert):

        if expr.from_bits == 64 and expr.to_bits == 32 \
                and isinstance(expr.operand, BinaryOp) and expr.operand.op == "Shr" \
                and isinstance(expr.operand.operands[1], Const) \
                and expr.operand.operands[1].value == 32:

            inner = expr.operand.operands[0]
            if isinstance(inner,
                          BinaryOp) and inner.op == "Mull" and isinstance(
                              inner.operands[0], Const):
                bits = 32
                C = inner.operands[0].value
                X = inner.operands[1]
                V = bits
                ndigits = 5 if V == 32 else 6
                divisor = self._check_divisor(pow(2, V), C, ndigits)
                if divisor is not None:
                    new_const = Const(None, None, divisor, V)
                    new_expr = BinaryOp(inner.idx, 'Div', [X, new_const],
                                        inner.signed, **inner.tags)
                    return new_expr
Beispiel #11
0
    def _handle_BinaryOp(self, expr_idx: int, expr: BinaryOp, stmt_idx: int,
                         stmt: Statement, block: Optional[Block]):
        changed = False

        operand_0 = self._handle_expr(0, expr.operands[0], stmt_idx, stmt,
                                      block)
        if operand_0 is not None and operand_0 is not expr.operands[0]:
            changed = True
        else:
            operand_0 = expr.operands[0]

        operand_1 = self._handle_expr(1, expr.operands[1], stmt_idx, stmt,
                                      block)
        if operand_1 is not None and operand_1 is not expr.operands[1]:
            changed = True
        else:
            operand_1 = expr.operands[1]

        if changed:
            new_expr = expr.copy()
            new_expr.operands = (operand_0, operand_1)
            return new_expr
        return None
Beispiel #12
0
    def optimize(self, expr: BinaryOp):

        #
        if expr.op == "And" \
                and isinstance(expr.operands[1], Const):
            mask = expr.operands[1].value
            to_bits = _MASK_TO_BITS.get(mask, None)
            if to_bits is None:
                return None

            if isinstance(expr.operands[0], Convert):
                conv: Convert = expr.operands[0]
                atom = conv.operand
                if conv.from_bits <= to_bits:
                    # this masking is useless
                    return Convert(None, conv.from_bits, expr.bits,
                                   conv.is_signed, atom, **conv.tags)

            elif isinstance(expr.operands[0], BinaryOp) and expr.operands[0].op in {'Shl', 'Shr', 'Sar'} \
                    and isinstance(expr.operands[0].operands[0], Convert):
                binop_expr = expr.operands[0]
                conv: Convert = expr.operands[0].operands[0]
                atom = conv.operand
                if conv.from_bits <= to_bits:
                    # this masking is useless
                    # apply the binary operation
                    atom = BinaryOp(None,
                                    binop_expr.op,
                                    (atom, binop_expr.operands[1]),
                                    binop_expr.signed,
                                    variable=binop_expr.variable,
                                    variable_offset=binop_expr.variable_offset,
                                    **binop_expr.tags)
                    return Convert(None, conv.from_bits, expr.bits,
                                   conv.is_signed, atom, **conv.tags)

        return None