Example #1
0
 def _symbolic_bind_tuple(self, param_type: ConcreteType,
                          arg_type: ConcreteType):
     """Binds any parametric symbols in the "tuple" param_type."""
     assert isinstance(param_type, TupleType) and isinstance(
         arg_type, TupleType)
     for param_member, arg_member in zip(param_type.get_unnamed_members(),
                                         arg_type.get_unnamed_members()):
         self._symbolic_bind(param_member, arg_member)
Example #2
0
def _bind_names(name_def_tree: ast.NameDefTree, type_: ConcreteType,
                ctx: DeduceCtx) -> None:
    """Binds names in name_def_tree to corresponding type given in type_."""
    if name_def_tree.is_leaf():
        name_def = name_def_tree.get_leaf()
        ctx.type_info[name_def] = type_
        return

    if not isinstance(type_, TupleType):
        raise XlsTypeError(
            name_def_tree.span,
            type_,
            rhs_type=None,
            suffix='Expected a tuple type for these names, but got {}.'.format(
                type_))

    if len(name_def_tree.tree) != type_.get_tuple_length():
        raise TypeInferenceError(
            name_def_tree.span, type_,
            'Could not bind names, names are mismatched in number vs type; at '
            'this level of the tuple: {} names, {} types.'.format(
                len(name_def_tree.tree), type_.get_tuple_length()))

    for subtree, subtype in zip(name_def_tree.tree,
                                type_.get_unnamed_members()):
        ctx.type_info[subtree] = subtype
        _bind_names(subtree, subtype, ctx)
Example #3
0
 def _visit_matcher(self, matcher: ast.NameDefTree, index: Tuple[int, ...],
                    matched_value: BValue,
                    matched_type: ConcreteType) -> BValue:
   if matcher.is_leaf():
     leaf = matcher.get_leaf()
     if isinstance(leaf, ast.WildcardPattern):
       return self._def(matcher, self.fb.add_literal_bits,
                        bits_mod.UBits(1, 1))
     elif isinstance(leaf, (ast.Number, ast.EnumRef)):
       leaf.accept(self)
       return self._def(matcher, self.fb.add_eq, self._use(leaf),
                        matched_value)
     elif isinstance(leaf, ast.NameRef):
       result = self._def(matcher, self.fb.add_eq, self._use(leaf.name_def),
                          matched_value)
       self._def_alias(leaf.name_def, to=leaf)
       return result
     else:
       assert isinstance(
           leaf, ast.NameDef
       ), 'Expected leaf to be wildcard, number, or name; got: {!r}'.format(
           leaf)
       ok = self._def(leaf, self.fb.add_literal_bits, bits_mod.UBits(1, 1))
       self.node_to_ir[matcher] = self.node_to_ir[leaf] = matched_value
       return ok
   else:
     ok = self.fb.add_literal_bits(bits_mod.UBits(value=1, bit_count=1))
     for i, (element, element_type) in enumerate(
         zip(matcher.tree, matched_type.get_unnamed_members())):  # pytype: disable=attribute-error
       # Extract the element.
       member = self.fb.add_tuple_index(matched_value, i)
       cond = self._visit_matcher(element, index + (i,), member, element_type)
       ok = self.fb.add_and(ok, cond)
     return ok
Example #4
0
 def _type_to_ir(self, concrete_type: ConcreteType) -> type_mod.Type:
   """Converts a concrete type to its corresponding IR representation."""
   assert isinstance(concrete_type, ConcreteType), concrete_type
   logging.vlog(4, 'Converting concrete type to IR: %s', concrete_type)
   if isinstance(concrete_type, ArrayType):
     element_type = self._type_to_ir(concrete_type.get_element_type())
     element_count = concrete_type.size
     if not isinstance(element_count, int):
       raise ValueError(
           'Expect array element count to be integer; got {!r}'.format(
               element_count))
     result = self.package.get_array_type(element_count, element_type)
     logging.vlog(
         4, 'Converted type to IR; concrete type: %s ir: %s element_count: %d',
         concrete_type, result, concrete_type.size)
     return result
   elif isinstance(concrete_type, BitsType) or isinstance(
       concrete_type, EnumType):
     return self.package.get_bits_type(concrete_type.get_total_bit_count())
   else:
     if not isinstance(concrete_type, TupleType):
       raise ValueError(
           'Expect type to be bits/enum, array, or tuple; got: '
           f'{concrete_type} ({concrete_type!r})')
     members = tuple(
         self._type_to_ir(m) for m in concrete_type.get_unnamed_members())
     return self.package.get_tuple_type(members)
Example #5
0
def sign_convert_value(concrete_type: ConcreteType, value: Value) -> Value:
    """Converts the values to matched the signedness of the concrete type.

  Converts bits-typed Values contained within the given Value to match the
  signedness of the ConcreteType. Examples:

  invocation: sign_convert_value(s8, u8:64)
  returns: s8:64

  invocation: sign_convert_value(s3, u8:7)
  returns: s3:-1

  invocation: sign_convert_value((s8, u8), (u8:42, u8:10))
  returns: (s8:42, u8:10)

  This conversion functionality is required because the Values used in the DSLX
  may be signed while Values in IR interpretation and Verilog simulation are
  always unsigned.

  This function is idempotent.

  Args:
    concrete_type: ConcreteType to match.
    value: Input value.

  Returns:
    Sign-converted value.
  """
    if isinstance(concrete_type, concrete_type_mod.TupleType):
        assert value.is_tuple()
        assert len(value.tuple_members) == concrete_type.get_tuple_length()
        return Value.make_tuple(
            tuple(
                sign_convert_value(t, a) for t, a in zip(
                    concrete_type.get_unnamed_members(), value.tuple_members)))
    elif isinstance(concrete_type, concrete_type_mod.ArrayType):
        assert value.is_array()
        assert len(value.array_payload.elements) == concrete_type.size
        return Value.make_array(
            tuple(
                sign_convert_value(concrete_type.get_element_type(), v)
                for v in value.array_payload.elements))
    elif concrete_type_mod.is_sbits(concrete_type):
        return Value.make_sbits(value.get_bit_count(), value.get_bits_value())
    else:
        assert concrete_type_mod.is_ubits(concrete_type)
        return value
Example #6
0
def generate_argument(arg_type: ConcreteType, rng: Random,
                      prior: Sequence[Value]) -> Value:
    """Generates an argument value of the same type as the concrete type."""
    if isinstance(arg_type, TupleType):
        return Value.make_tuple(
            tuple(
                generate_argument(t, rng, prior)
                for t in arg_type.get_unnamed_members()))
    elif isinstance(arg_type, ArrayType):
        return Value.make_array(
            tuple(
                generate_argument(arg_type.get_element_type(), rng, prior)
                for _ in range(arg_type.size)))
    else:
        assert isinstance(arg_type, BitsType)
        if not prior or rng.random() < 0.5:
            return _generate_unbiased_argument(arg_type, rng)

    to_mutate = rng.choice(prior)
    bit_count = arg_type.get_total_bit_count()
    if bit_count > to_mutate.get_bit_count():
        to_mutate = to_mutate.bits_payload.concat(
            _generate_bit_value(bit_count - to_mutate.get_bit_count(),
                                rng,
                                signed=False).bits_payload)
    else:
        to_mutate = to_mutate.bits_payload.slice(0, bit_count, lsb_is_0=False)

    assert to_mutate.bit_count == bit_count
    value = to_mutate.value
    mutation_count = randrange_biased_towards_zero(bit_count, rng)
    for _ in range(mutation_count):
        # Pick a random bit and flip it.
        bitno = rng.randrange(bit_count)
        value ^= 1 << bitno

    signed = arg_type.get_signedness()
    constructor = Value.make_sbits if signed else Value.make_ubits
    return constructor(value=value, bit_count=bit_count)
Example #7
0
def _value_compatible_with_type(type_: ConcreteType, value: Value) -> bool:
    """Returns whether value is compatible with type_ (recursively)."""
    assert isinstance(value, Value), value

    if isinstance(type_, TupleType) and value.is_tuple():
        return all(
            _value_compatible_with_type(ct, m)
            for ct, m in zip(type_.get_unnamed_members(), value.tuple_members))

    if isinstance(type_, ArrayType) and value.is_array():
        et = type_.get_element_type()
        return all(
            _value_compatible_with_type(et, m)
            for m in value.array_payload.elements)

    if isinstance(type_, EnumType) and value.tag == Tag.ENUM:
        return type_.nominal_type == value.type_

    if isinstance(type_,
                  BitsType) and not type_.signed and value.tag == Tag.UBITS:
        return value.bits_payload.bit_count == type_.get_total_bit_count()

    if isinstance(type_, BitsType) and type_.signed and value.tag == Tag.SBITS:
        return value.bits_payload.bit_count == type_.get_total_bit_count()

    if value.tag == Tag.ENUM and isinstance(type_, BitsType):
        return (value.type_.get_signedness() == type_.get_signedness() and
                value.bits_payload.bit_count == type_.get_total_bit_count())

    if value.tag == Tag.ARRAY and is_ubits(type_):
        flat_bit_count = value.array_payload.flatten().bits_payload.bit_count
        return flat_bit_count == type_.get_total_bit_count()

    if isinstance(type_, EnumType) and value.is_bits():
        return (type_.get_signedness() == (value.tag == Tag.SBITS)
                and type_.get_total_bit_count() == value.get_bit_count())

    raise NotImplementedError(type_, value)
Example #8
0
def _unify_NameDefTree(self: ast.NameDefTree, type_: ConcreteType,
                       ctx: DeduceCtx) -> None:
    """Unifies the NameDefTree AST node with the observed RHS type type_."""
    resolved_rhs_type = resolve(type_, ctx)
    if self.is_leaf():
        leaf = self.get_leaf()
        if isinstance(leaf, ast.NameDef):
            ctx.type_info[leaf] = resolved_rhs_type
        elif isinstance(leaf, ast.WildcardPattern):
            pass
        elif isinstance(leaf, (ast.Number, ast.EnumRef)):
            resolved_leaf_type = resolve(deduce(leaf, ctx), ctx)
            if resolved_leaf_type != resolved_rhs_type:
                raise TypeInferenceError(
                    span=self.span,
                    type_=resolved_rhs_type,
                    suffix=
                    'Conflicting types; pattern expects {} but got {} from value'
                    .format(resolved_rhs_type, resolved_leaf_type))
        else:
            assert isinstance(leaf, ast.NameRef), repr(leaf)
            ref_type = ctx.type_info[leaf.name_def]
            resolved_ref_type = resolve(ref_type, ctx)
            if resolved_ref_type != resolved_rhs_type:
                raise TypeInferenceError(
                    span=self.span,
                    type_=resolved_rhs_type,
                    suffix=
                    'Conflicting types; pattern expects {} but got {} from reference'
                    .format(resolved_rhs_type, resolved_ref_type))
    else:
        assert isinstance(self.tree, tuple)
        if isinstance(type_, TupleType) and type_.get_tuple_length() == len(
                self.tree):
            for subtype, subtree in zip(type_.get_unnamed_members(),
                                        self.tree):
                _unify(subtree, subtype, ctx)