def visit_UnaryOp( s, node ): if isinstance( node.op, bir.Not ): dtype = node.operand.Type.get_dtype() if not rdt.Bool()( dtype ): raise PyMTLTypeError( s.blk, node.ast, 'the operand of "Logic-not" cannot be cast to bool!' ) if dtype.get_length() != 1: raise PyMTLTypeError( s.blk, node.ast, 'the operand of "Logic-not" is not a single bit!' ) node.Type = rt.NetWire( rdt.Bool() ) else: node.Type = node.operand.Type if hasattr( node.operand, '_value' ): opmap = { bir.Invert : '~', bir.Not : 'not', bir.UAdd : '+', bir.USub : '-', } try: op = opmap[node.op.__class__] operand = node.operand._value.uint() node._value = eval(f"Bits32({op}{operand})") except: pass
def visit_BoolOp(s, node): for value in node.values: if not isinstance(value.Type, rt.Signal) or not rdt.Bool()( value.Type.get_dtype()): raise PyMTLTypeError( s.blk, node.ast, f"{value} of {value.Type} cannot be cast into bool!") node.Type = rt.NetWire(rdt.Bool())
def visit_UnaryOp( s, node ): if isinstance( node.op, bir.Not ): dtype = node.operand.Type.get_dtype() if not rdt.Bool()( dtype ): raise PyMTLTypeError( s.blk, node.ast, 'the operand of "Logic-not" cannot be cast to bool!' ) if dtype.get_length() != 1: raise PyMTLTypeError( s.blk, node.ast, 'the operand of "Logic-not" is not a single bit!' ) node.Type = rt.NetWire( rdt.Bool() ) else: node.Type = node.operand.Type
def visit_Compare( s, node ): l_type = node.left.Type.get_dtype() r_type = node.right.Type.get_dtype() if l_type != r_type: raise PyMTLTypeError( s.blk, node.ast, f"LHS and RHS of {node.op.__class__.__name__} have different types ({l_type} vs {r_type})!" ) node.Type = rt.NetWire( rdt.Bool() )
def visit_IfExp(s, node): # Can the type of condition be cast into bool? if not rdt.Bool()(node.cond.Type.get_dtype()): raise PyMTLTypeError( s.blk, node.ast, 'the condition of "if-exp" cannot be converted to bool!') # body and orelse must have the same type # if node.body.Type != node.orelse.Type: if not node.body.Type.get_dtype()(node.orelse.Type.get_dtype()): raise PyMTLTypeError( s.blk, node.ast, 'the body and orelse of "if-exp" must have the same type!') lhs_dtype, rhs_dtype = node.body.Type.get_dtype( ), node.orelse.Type.get_dtype() lhs_is_vector = isinstance(lhs_dtype, rdt.Vector) rhs_is_vector = isinstance(rhs_dtype, rdt.Vector) lhs_nbits, rhs_nbits = lhs_dtype.get_length(), rhs_dtype.get_length() # Unify body and orelse if both are rdt.Vector if lhs_is_vector and rhs_is_vector and lhs_nbits != rhs_nbits: is_lhs_inferred = not node.body._is_explicit is_rhs_inferred = not node.orelse._is_explicit # Both sides are explicit if not is_lhs_inferred and not is_rhs_inferred: raise PyMTLTypeError( s.blk, node.ast, f'the body and orelse of "if-exp" have different bitwidth {lhs_nbits} vs {rhs_nbits}!' ) # Both sides are implicit elif is_lhs_inferred and is_rhs_inferred: if lhs_nbits >= rhs_nbits: target_nbits = lhs_nbits op = node.body else: target_nbits = rhs_nbits op = node.orelse context = rt.NetWire(rdt.Vector(target_nbits)) s.enforcer.enter(s.blk, context, op) else: # One side is explicit and the other implicit if is_lhs_inferred: exp_str, imp_str = "or-else", "body" context, op, explicit, implicit = node.orelse.Type, node.body, rhs_nbits, lhs_nbits else: exp_str, imp_str = "body", "or-else" context, op, explicit, implicit = node.body.Type, node.orelse, lhs_nbits, rhs_nbits if explicit < implicit: raise PyMTLTypeError( s.blk, node.ast, f"The {exp_str} side of if-exp has {explicit} bits but " f"the {imp_str} side requires more bits ({implicit})!") s.enforcer.enter(s.blk, context, op) node.Type = node.body.Type node._is_explicit = node.body._is_explicit or node.orelse._is_explicit
def visit_Compare( s, node ): l_type = node.left.Type.get_dtype() r_type = node.right.Type.get_dtype() l_explicit, r_explicit = node.left._is_explicit, node.right._is_explicit l_nbits, r_nbits = l_type.get_length(), r_type.get_length() if l_explicit and r_explicit: if l_type != r_type: raise PyMTLTypeError( s.blk, node.ast, f"LHS and RHS of {node.op.__class__.__name__} have different types ({l_type} vs {r_type})!" ) elif not l_explicit and not r_explicit: if l_nbits >= r_nbits: target_nbits = l_nbits op = node.right else: target_nbits = r_nbits op = node.left context = rt.NetWire(rdt.Vector(target_nbits)) s.enforcer.enter( s.blk, context, op ) else: context, op, explicit, implicit = node.left.Type, node.right, l_nbits, r_nbits if not l_explicit: context, op, explicit, implicit = node.right.Type, node.left, r_nbits, l_nbits # Check if any implicit truncation happens if explicit < implicit: raise PyMTLTypeError( s.blk, node.ast, f"The explicitly sized side of comparison has {explicit} bits but " f"the integer literal requires more bits ({implicit}) to hold!" ) s.enforcer.enter( s.blk, context, op ) node.Type = rt.NetWire( rdt.Bool() ) node._is_explicit = True
def visit_If(s, node): # Can the type of condition be cast into bool? dtype = node.cond.Type.get_dtype() if not rdt.Bool()(dtype): raise PyMTLTypeError( s.blk, node.ast, 'the condition of "if" cannot be converted to bool!') node.Type = None
def visit_IfExp( s, node ): # Can the type of condition be cast into bool? if not rdt.Bool()( node.cond.Type.get_dtype() ): raise PyMTLTypeError( s.blk, node.ast, 'the condition of "if-exp" cannot be converted to bool!' ) # body and orelse must have the same type # if node.body.Type != node.orelse.Type: if not node.body.Type.get_dtype()( node.orelse.Type.get_dtype() ): raise PyMTLTypeError( s.blk, node.ast, 'the body and orelse of "if-exp" must have the same type!' ) node.Type = node.body.Type