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
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
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
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
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
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
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
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
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
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
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