# Path: krakatau-lib/src/main/resources/Lib/Krakatau/ssa/constraints/int_c.py
# class IntConstraint(ValueType):
#     __slots__ = "width min max".split()
# 
#     def __init__(self, width, min_, max_):
#         self.width = width
#         self.min = min_
#         self.max = max_
#         # self.isBot = (-min_ == max_+1 == (1<<width)//2)
# 
#     @staticmethod
#     def range(width, min_, max_):
#         if min_ > max_:
#             return None
#         return IntConstraint(width, min_, max_)
# 
#     @staticmethod
#     def const(width, val):
#         return IntConstraint(width, val, val)
# 
#     @staticmethod
#     def bot(width):
#         return IntConstraint(width, -1<<(width-1), (1<<(width-1))-1)
# 
#     def _key(self): return self.min, self.max
# 
#     def join(*cons):
#         xmin = max(c.min for c in cons)
#         xmax = min(c.max for c in cons)
#         if xmin > xmax:
#             return None
#         res = IntConstraint(cons[0].width, xmin, xmax)
#         return cons[0] if cons[0] == res else res
# 
#     def meet(*cons):
#         xmin = min(c.min for c in cons)
#         xmax = max(c.max for c in cons)
#         return IntConstraint(cons[0].width, xmin, xmax)


from ..constraints import IntConstraint
import itertools, operator
        k = min(numzeroes, (y-x+1).bit_length()-1)
        out.append((x,k))
        x += 1<<k
    assert(x == y+1)
    return out

def propagateBitwise(arg1, arg2, op, usemin, usemax):
    ranges1 = split_pow2ranges(arg1.min, arg1.max)
    ranges2 = split_pow2ranges(arg2.min, arg2.max)

    vals = []
    for (s1,k1),(s2,k2) in itertools.product(ranges1, ranges2):
        # there are three parts. The high bits fixed in both arguments,
        # the middle bits fixed in one but not the other, and the
        # lowest bits which can be chosen freely for both arguments
        # high = op(h1,h2) and low goes from 0 to 1... but the range of
        # the middle depends on the particular operation
        # 0-x, x-1 and 0-1 for and, or, and xor respectively
        if k1 > k2:
            (s1,k1),(s2,k2) = (s2,k2),(s1,k1)

        mask1 = (1<<k1) - 1
        mask2 = (1<<k2) - 1 - mask1

        high = op(s1, s2) & ~(mask1 | mask2)
        midmin = (s1 & mask2) if usemin else 0
        midmax = (s1 & mask2) if usemax else mask2

        vals.append(high | midmin)
        vals.append(high | midmax | mask1)

# Path: krakatau-lib/src/main/resources/Lib/Krakatau/ssa/constraints/int_c.py
# class IntConstraint(ValueType):
#     __slots__ = "width min max".split()
# 
#     def __init__(self, width, min_, max_):
#         self.width = width
#         self.min = min_
#         self.max = max_
#         # self.isBot = (-min_ == max_+1 == (1<<width)//2)
# 
#     @staticmethod
#     def range(width, min_, max_):
#         if min_ > max_:
#             return None
#         return IntConstraint(width, min_, max_)
# 
#     @staticmethod
#     def const(width, val):
#         return IntConstraint(width, val, val)
# 
#     @staticmethod
#     def bot(width):
#         return IntConstraint(width, -1<<(width-1), (1<<(width-1))-1)
# 
#     def _key(self): return self.min, self.max
# 
#     def join(*cons):
#         xmin = max(c.min for c in cons)
#         xmax = min(c.max for c in cons)
#         if xmin > xmax:
#             return None
#         res = IntConstraint(cons[0].width, xmin, xmax)
#         return cons[0] if cons[0] == res else res
# 
#     def meet(*cons):
#         xmin = min(c.min for c in cons)
#         xmax = max(c.max for c in cons)
#         return IntConstraint(cons[0].width, xmin, xmax)


# Path: krakatau-lib/src/main/resources/Lib/Krakatau/ssa/ssa_ops/bitwise_util.py
from ..constraints import IntConstraint
import itertools, operator

        k = min(numzeroes, (y-x+1).bit_length()-1)
        out.append((x,k))
        x += 1<<k
    assert(x == y+1)
    return out

def propagateBitwise(arg1, arg2, op, usemin, usemax):
    ranges1 = split_pow2ranges(arg1.min, arg1.max)
    ranges2 = split_pow2ranges(arg2.min, arg2.max)

    vals = []
    for (s1,k1),(s2,k2) in itertools.product(ranges1, ranges2):
        # there are three parts. The high bits fixed in both arguments,
        # the middle bits fixed in one but not the other, and the
        # lowest bits which can be chosen freely for both arguments
        # high = op(h1,h2) and low goes from 0 to 1... but the range of
        # the middle depends on the particular operation
        # 0-x, x-1 and 0-1 for and, or, and xor respectively
        if k1 > k2:
            (s1,k1),(s2,k2) = (s2,k2),(s1,k1)

        mask1 = (1<<k1) - 1
        mask2 = (1<<k2) - 1 - mask1

        high = op(s1, s2) & ~(mask1 | mask2)
        midmin = (s1 & mask2) if usemin else 0
        midmax = (s1 & mask2) if usemax else mask2

        vals.append(high | midmin)
        vals.append(high | midmax | mask1)

    return IntConstraint.range(arg1.width, min(vals), max(vals))