Ejemplo n.º 1
0
 def _generate_bit_slice(self,
                         env: Env) -> Tuple[ast.Index, ast.TypeAnnotation]:
   """Generates a bit slice AST node."""
   make_arg, arg_type = self._choose_env_value(env, self._not_tuple_or_array)
   bit_count = self._get_type_bit_count(arg_type)
   slice_type = self.rng.choice(['bit_slice', 'width_slice', 'dynamic_slice'])
   while True:
     start_low = 0 if slice_type == 'width_slice' else -bit_count - 1
     start = (
         self.rng.randrange(start_low, bit_count + 1) if self.rng.choice(
             (True, False)) else None)
     limit = (
         self.rng.randrange(-bit_count - 1, bit_count + 1) if self.rng.choice(
             (True, False)) else None)
     _, width = bit_helpers.resolve_bit_slice_indices(bit_count, start, limit)
     if width <= 0:  # Make sure we produce non-zero-width things.
       continue
     else:
       break
   if slice_type == 'width_slice':
     index_slice = ast.WidthSlice(self.m, self.fake_span,
                                  self._make_number(start or 0, None),
                                  self._make_type_annotation(False, width))
   elif slice_type == 'bit_slice':
     index_slice = ast.Slice(
         self.m, self.fake_span,
         None if start is None else self._make_number(start, None),
         None if limit is None else self._make_number(limit, None))
   else:
     start_arg, _ = self._choose_env_value(env, self._is_unsigned_bit_vector)
     index_slice = ast.WidthSlice(self.m, self.fake_span, start_arg(),
                                  self._make_type_annotation(False, width))
   type_ = self._make_type_annotation(False, width)
   return (ast.Index(self.m, self.fake_span, make_arg(), index_slice), type_)
Ejemplo n.º 2
0
def _deduce_slice_type(self: ast.Index, ctx: DeduceCtx,
                       lhs_type: ConcreteType) -> ConcreteType:
    """Deduces the concrete type of an Index AST node with a slice spec."""
    index_slice = self.index
    assert isinstance(index_slice, (ast.Slice, ast.WidthSlice)), index_slice

    # TODO(leary): 2019-10-28 Only slicing bits types for now, and only with
    # number ast nodes, generalize to arrays and constant expressions.
    if not isinstance(lhs_type, BitsType):
        raise XlsTypeError(self.span, lhs_type, None,
                           'Value to slice is not of "bits" type.')

    bit_count = lhs_type.get_total_bit_count()

    if isinstance(index_slice, ast.WidthSlice):
        start = index_slice.start
        if isinstance(start, ast.Number) and start.type_ is None:
            start_type = lhs_type.to_ubits()
            resolved_start_type = resolve(start_type, ctx)
            if not bit_helpers.fits_in_bits(
                    start.get_value_as_int(),
                    resolved_start_type.get_total_bit_count()):
                raise TypeInferenceError(
                    start.span, resolved_start_type,
                    'Cannot fit {} in {} bits (inferred from bits to slice).'.
                    format(start.get_value_as_int(),
                           resolved_start_type.get_total_bit_count()))
            ctx.type_info[start] = start_type
        else:
            start_type = deduce(start, ctx)

        # Check the start is unsigned.
        if start_type.signed:
            raise TypeInferenceError(
                start.span,
                type_=start_type,
                suffix='Start index for width-based slice must be unsigned.')

        width_type = deduce(index_slice.width, ctx)
        if isinstance(width_type.get_total_bit_count(), int) and isinstance(
                lhs_type.get_total_bit_count(),
                int) and width_type.get_total_bit_count(
                ) > lhs_type.get_total_bit_count():
            raise XlsTypeError(
                start.span, lhs_type, width_type,
                'Slice type must have <= original number of bits; attempted slice from {} to {} bits.'
                .format(lhs_type.get_total_bit_count(),
                        width_type.get_total_bit_count()))

        # Check the width type is bits-based (no enums, since value could be out
        # of range of the enum values).
        if not isinstance(width_type, BitsType):
            raise TypeInferenceError(
                self.span,
                type_=width_type,
                suffix='Require a bits-based type for width-based slice.')

        # The width type is the thing returned from the width-slice.
        return width_type

    assert isinstance(index_slice, ast.Slice), index_slice
    limit = index_slice.limit.get_value_as_int() if index_slice.limit else None
    # PyType has trouble figuring out that start is definitely an Number at this
    # point.
    start = index_slice.start
    assert isinstance(start, (ast.Number, type(None)))
    start = start.get_value_as_int() if start else None

    _, fn_symbolic_bindings = ctx.fn_stack[-1]
    if isinstance(bit_count, ParametricExpression):
        bit_count = bit_count.evaluate(fn_symbolic_bindings)
    start, width = bit_helpers.resolve_bit_slice_indices(
        bit_count, start, limit)
    key = tuple(fn_symbolic_bindings.items())
    ctx.type_info.add_slice_start_width(index_slice, key, (start, width))
    return BitsType(signed=False, size=width)