Currently the typing of ite is a mess and inconsistent with magma.
Now before you all go looking at the mess I want you all to consider the following code snippets and tell me which of the following should be allowable syntax (otherwise you will never understand why ite is such a mess).
Assume the following for all snippets:
BV = BitVector
class SBV(BV): pass
class TBV(BV): pass
class WrappedInt:
def __init__(self, i):
self.i = i
def __int__(self):
return self.i
bv1 = BV[8](4) # values here don't really matter
bv2 = BV[8](5)
sbv = SBV[8](4)
tbv = TBV[8](4)
wi = WrappedInt(4)
b = Bit(0) # again the value here is arbitrary
Also keep in mind the following property:
res = bv1 & 4
assert isinstance(res, BV[8])
assert res == BV[8](4) == 4
res = bv1 & sbv # Note: sbv & tbv is an error
assert isinstance(res, BV[8])
assert res == BV[8](4) == 4
res = bv1 & wi
assert isinstance(res, BV[8])
assert res == BV[8](4) == 4
# The preceding may surprise you but would it make sense for it
# to fail and the following to succeed?
res = bv1 & (0 + wi)
res = bv1 & BV[8](wi)
Okay on to the code snippets
b.ite(bv1, 0) # 1
b.ite(bv1, wi) # 2 (Note I consider this to be the same case as 1)
b.ite(bv1, sbv) # 3
b.ite((bv1, sbv), (bv1, sbv)) # 4
b.ite((bv1, sbv), (sbv, sbv)) # 5
# 6
@ssa # this could be ast_tools or magma combinational
def foo(cond: Bit) -> (BV, BV):
if cond:
return bv1, bv2
else:
return bv2, bv1
# 7
@ssa
def bar(cond: Bit) -> (BV, BV):
if cond:
r_val = bv1, bv2
else:
return bv2, bv1
return r_val
# 8
@ssa
def foobar(cond: Bit) -> (BV, BV):
if cond:
r_val = bv1, bv2
else:
r_val = bv2, bv1
return r_val
Currently, hwtypes with ast_tools rewrites* accepts all of these (if it doesn't there is a bug).
It would not be hard to convince me to drop 1 and 2, they are coercions. While it is consistent with other methods to coerce I am fine not coercing in ite and continuing to coerce in other methods (I would rather have no coercion at all)
I feel very strongly that 3 is correct sbv is a BV[8] so there is no reason it shouldn't work
4 and 5 are (partly) the cause of current mess but I feel strongly that if 4 is valid and 3 is valid then logically so must be 5.
Finally, the last 3 cases are the reason why hwtypes accepts tuples. Currently magma combinational will work with 6 and 7 but not 8. This is because magma is quite clever about unpacking return values before it muxes (by using the returns annotation to determine if a return value is a tuple), it however cannot support the arbitrary muxing of tuples which is why 8 does not work. Hence to support 8 we must support 4**.
I find allowing 6 and 7 but not 8 to be pretty unintuitive and hence undesirable.
Now these requirements leads to the really messy typing rules for ITE. See:
https://github.com/leonardt/hwtypes/blob/master/hwtypes/bit_vector.py#L82
https://github.com/leonardt/hwtypes/blob/master/hwtypes/smt_bit_vector.py#L137
https://github.com/leonardt/hwtypes/blob/master/hwtypes/bit_vector_util.py
*
@end_rewrite()
@if_to_phi(Bit.ite)
@bool_to_bit()
@ssa()
@begin_rewrite()
**
I tried to come up with an ast transformation that could robustly perform the necessary unpacking of tuples. However, all the solutions I came up with either required type annotations on ALL assignments (r_val: (BV, BV) = ...) or a static type inference engine (which would give us those annotations). Note as we a have dependent type system we cannot easily hack mypy (or any other static type checking tool that I am aware of) to generate annotations for us.
Currently the typing of
iteis a mess and inconsistent with magma.Now before you all go looking at the mess I want you all to consider the following code snippets and tell me which of the following should be allowable syntax (otherwise you will never understand why
iteis such a mess).Assume the following for all snippets:
Also keep in mind the following property:
Okay on to the code snippets
Currently, hwtypes with ast_tools rewrites* accepts all of these (if it doesn't there is a bug).
It would not be hard to convince me to drop 1 and 2, they are coercions. While it is consistent with other methods to coerce I am fine not coercing in
iteand continuing to coerce in other methods (I would rather have no coercion at all)I feel very strongly that 3 is correct
sbvis aBV[8]so there is no reason it shouldn't work4 and 5 are (partly) the cause of current mess but I feel strongly that if 4 is valid and 3 is valid then logically so must be 5.
Finally, the last 3 cases are the reason why hwtypes accepts tuples. Currently magma combinational will work with 6 and 7 but not 8. This is because magma is quite clever about unpacking return values before it muxes (by using the returns annotation to determine if a return value is a tuple), it however cannot support the arbitrary muxing of tuples which is why 8 does not work. Hence to support 8 we must support 4**.
I find allowing 6 and 7 but not 8 to be pretty unintuitive and hence undesirable.
Now these requirements leads to the really messy typing rules for ITE. See:
https://github.com/leonardt/hwtypes/blob/master/hwtypes/bit_vector.py#L82
https://github.com/leonardt/hwtypes/blob/master/hwtypes/smt_bit_vector.py#L137
https://github.com/leonardt/hwtypes/blob/master/hwtypes/bit_vector_util.py
*
**
I tried to come up with an ast transformation that could robustly perform the necessary unpacking of tuples. However, all the solutions I came up with either required type annotations on ALL assignments (
r_val: (BV, BV) = ...) or a static type inference engine (which would give us those annotations). Note as we a have dependent type system we cannot easily hack mypy (or any other static type checking tool that I am aware of) to generate annotations for us.