Ejemplo n.º 1
0
    def _generate_concat(self,
                         env: Env) -> Tuple[ast.Expr, ast.TypeAnnotation]:
        """Returns a (potentially vacuous) concatenate operation of values in `env`.

    Args:
      env: Environment of values that can be selected from for concatenation.
    Note: the concat operation will not exceed the maximum bit width so the
      concat may end up being a nop.
    """
        if self._env_contains_array(env) and self.rng.choice([True, False]):
            return self._generate_array_concat(env)

        count = self._generate_nary_operand_count(env) + 2
        operands = []
        operand_types = []
        for i in range(count):
            make_arg, arg_type = self._choose_env_value(
                env, self._is_builtin_unsigned)
            operands.append(make_arg())
            operand_types.append(arg_type)
        result = operands[0]
        result_bits = builtin_type_to_bits(operand_types[0])
        token = scanner.Token(ast.Binop.CONCAT, self.fake_span,
                              ast.Binop.CONCAT.value)
        for i in range(1, count):
            this_bits = builtin_type_to_bits(operand_types[i])
            if result_bits + this_bits > self.options.max_width_bits_types:
                break
            result = ast.Binop(token, result, operands[i])
            result_bits += this_bits
        assert result_bits <= self.options.max_width_bits_types, result_bits
        return (result, self._make_large_type_annotation('UN', result_bits))
Ejemplo n.º 2
0
    def _generate_cast_bits_to_array(
            self, env: Env) -> Tuple[ast.Cast, ast.TypeAnnotation]:
        """Generates a cast from bits to array type."""

        # Get a random bits-typed element from the environment.
        make_arg, arg_type = self._choose_env_value(env,
                                                    self._is_builtin_unsigned)

        # Next, find factors of the bit count and select one pair.
        bit_count = builtin_type_to_bits(arg_type)
        factors = []
        for i in range(1, bit_count + 1):
            if bit_count % i == 0:
                factors.append((i, bit_count // i))

        element_size, array_size = self.rng.choice(factors)
        element_type = ast.make_builtin_type_annotation(
            self.fake_span,
            scanner.Token(scanner.TokenKind.KEYWORD,
                          value=scanner.Keyword.UN,
                          span=self.fake_span),
            (self._make_number(element_size, None), ))

        outer_array_type = self._make_array_type(element_type, array_size)

        return (ast.Cast(outer_array_type, make_arg()), outer_array_type)
Ejemplo n.º 3
0
    def _generate_array_concat(
            self, env: Env) -> Tuple[ast.Expr, ast.TypeAnnotation]:
        """Returns a binary concatenation of two arrays in env.

    The two arrays to concatenate in env will have the same element type.

    Args:
      env: Environment of values that can be selected from for array
        concatenation.
    Precondition: There must be an array value present in env.
    """
        make_lhs, lhs_type = self._choose_env_value(
            env, lambda t: isinstance(t, ast.ArrayTypeAnnotation))
        assert isinstance(lhs_type, ast.ArrayTypeAnnotation), lhs_type

        def array_same_elem_type(t: ast.TypeAnnotation) -> bool:
            return (isinstance(t, ast.ArrayTypeAnnotation)
                    and t.element_type == lhs_type.element_type)

        make_rhs, rhs_type = self._choose_env_value(env, array_same_elem_type)
        token = scanner.Token(ast.Binop.CONCAT, self.fake_span,
                              ast.Binop.CONCAT.value)
        result = ast.Binop(token, make_lhs(), make_rhs())
        lhs_size = self._get_array_size(lhs_type)
        bits_per_elem = self._get_type_bit_count(lhs_type) // lhs_size
        result_size = lhs_size + self._get_array_size(rhs_type)
        dim = self._make_number(result_size, None)
        result_type = ast.ArrayTypeAnnotation(self.fake_span,
                                              lhs_type.element_type, dim)
        self._type_bit_counts[str(result_type)] = bits_per_elem * result_size
        return (result, result_type)
Ejemplo n.º 4
0
 def _generate_logical_binop(
         self, env: Env) -> Tuple[ast.Binop, ast.TypeAnnotation]:
     """Generates a logical binary operation (e.g. and, xor, or)."""
     make_lhs, lhs_type = self._choose_env_value(env,
                                                 self._not_tuple_or_array)
     make_rhs, rhs_type = self._choose_env_value(env,
                                                 self._not_tuple_or_array)
     # Convert into one-bit numbers by checking whether lhs and rhs values are 0.
     ne_token = scanner.Token(ast.Binop.NE, self.fake_span,
                              ast.Binop.NE.value)
     lhs = ast.Binop(ne_token, make_lhs(), self._make_number(0, lhs_type))
     rhs = ast.Binop(ne_token, make_rhs(), self._make_number(0, rhs_type))
     # Pick some operation to do.
     op = self.rng.choice([ast.Binop.LOGICAL_AND, ast.Binop.LOGICAL_OR])
     op_token = scanner.Token(op, self.fake_span, op.value)
     return ast.Binop(op_token, lhs, rhs), self._make_type_annotation('u1')
Ejemplo n.º 5
0
def _create_element_invocation(owner: ast.AstNodeOwner, span_: span.Span,
                               callee: Union[ast.NameRef, ast.ModRef],
                               arg_array: ast.Expr) -> ast.Invocation:
    """Creates a function invocation on the first element of the given array.

  We need to create a fake invocation to deduce the type of a function
  in the case where map is called with a builtin as the map function. Normally,
  map functions (including parametric ones) have their types deduced when their
  ast.Function nodes are encountered (where a similar fake ast.Invocation node
  is created).

  Builtins don't have ast.Function nodes, so that inference can't occur, so we
  essentually perform that synthesis and deduction here.

  Args:
    owner: AST node owner.
    span_: The location in the code where analysis is occurring.
    callee: The function to be invoked.
    arg_array: The array of arguments (at least one) to the function.

  Returns:
    An invocation node for the given function when called with an element in the
    argument array.
  """
    annotation = ast_helpers.make_builtin_type_annotation(
        owner, span_,
        scanner.Token(scanner.TokenKind.KEYWORD, span_, scanner.Keyword.U32),
        ())
    index_number = ast.Number(owner, span_, '32', ast.NumberKind.OTHER,
                              annotation)
    index = ast.Index(owner, span_, arg_array, index_number)
    return ast.Invocation(owner, span_, callee, (index, ))
Ejemplo n.º 6
0
 def _make_large_type_annotation(self, kw_identifier: Text,
                                 width: int) -> ast.TypeAnnotation:
     """Creates type annotations for widths > 64 bits."""
     token = scanner.Token(scanner.TokenKind.KEYWORD, self.fake_span,
                           scanner.Keyword[kw_identifier])
     dim = self._make_number(width, None)
     dims = (dim, )
     return ast.make_builtin_type_annotation(self.fake_span, token, dims)
Ejemplo n.º 7
0
 def _generate_type_primitive(self) -> scanner.Token:
     """Generates a primitive type token for use in building a type."""
     # Exclude "bits" from the primitive set because it's unclear what a bits[]
     # represents.
     #
     # TODO(leary): 2019-06-14 Define this!
     kw_identifier = self.rng.choice(self._kw_identifiers)
     return scanner.Token(scanner.TokenKind.KEYWORD, self.fake_span,
                          scanner.Keyword(kw_identifier))
Ejemplo n.º 8
0
def concrete_type_to_annotation(
    concrete_type: concrete_type_mod.ConcreteType) -> ast.TypeAnnotation:
  if isinstance(concrete_type, concrete_type_mod.BitsType):
    keyword = SN_KEYWORD if concrete_type.get_signedness() else UN_KEYWORD
    num_tok = scanner.Token(scanner.TokenKind.NUMBER, FAKE_SPAN,
                            concrete_type.get_total_bit_count())
    return ast.make_builtin_type_annotation(
        FAKE_SPAN, keyword, dims=(ast.Number(num_tok),))

  raise NotImplementedError(concrete_type)
Ejemplo n.º 9
0
 def _generate_binop_same_input_type(
     self, lhs: ast.Expr, rhs: ast.Expr, input_type: ast.TypeAnnotation
 ) -> Tuple[ast.Binop, ast.TypeAnnotation]:
     """Generates a binary operator on lhs/rhs which have the same input type."""
     if self.rng.random() < 0.1:
         op = self.rng.choice(ast.Binop.COMPARISON_KIND_LIST)
         output_type = self._make_type_annotation('bool')
     else:
         op = self.rng.choice(self._binops)
         if op in ast.Binop.SHIFTS and self.rng.random() < 0.8:
             # Clamp the RHS to be in range most of the time.
             assert isinstance(input_type,
                               ast.BuiltinTypeAnnotation), input_type
             bit_count = builtin_type_to_bits(input_type)
             new_upper = self.rng.randrange(bit_count)
             rhs = self._generate_umin(rhs, input_type, new_upper)
         output_type = input_type
     return ast.Binop(scanner.Token(op, self.fake_span, op.value), lhs,
                      rhs), output_type
Ejemplo n.º 10
0
 def _generate_unop(self, env: Env) -> Tuple[ast.Unop, ast.TypeAnnotation]:
     make_arg, arg_type = self._choose_env_value(env,
                                                 self._not_tuple_or_array)
     op = self.rng.choice(ast.Unop.SAME_TYPE_KIND_LIST)
     return ast.Unop(scanner.Token(op, self.fake_span, op.value),
                     make_arg()), arg_type
Ejemplo n.º 11
0
 def _make_ge(self, lhs: ast.Expr, rhs: ast.Expr) -> ast.Expr:
     return ast.Binop(
         scanner.Token(ast.Binop.GE, self.fake_span, ast.Binop.GE.value),
         lhs, rhs)
Ejemplo n.º 12
0
 def _make_identifier_token(self, identifier: Text) -> scanner.Token:
     return scanner.Token(scanner.TokenKind.IDENTIFIER, self.fake_span,
                          identifier)
Ejemplo n.º 13
0
 def _make_type_annotation(self, kw_identifier: Text) -> ast.TypeAnnotation:
     assert kw_identifier in scanner.TYPE_KEYWORD_STRINGS, kw_identifier
     token = scanner.Token(scanner.TokenKind.KEYWORD, self.fake_span,
                           scanner.Keyword(kw_identifier))
     return ast.make_builtin_type_annotation(self.fake_span, token, dims=())
Ejemplo n.º 14
0
from xls.dslx import concrete_type as concrete_type_mod
from xls.dslx import import_routines
from xls.dslx import parser
from xls.dslx import parser_helpers
from xls.dslx import scanner
from xls.dslx import span
from xls.dslx import typecheck
from xls.dslx import xls_type_error
from xls.dslx.interpreter import interpreter as interpreter_mod
from xls.dslx.interpreter import value as value_mod

FLAGS = flags.FLAGS
FILENAME = '/fake/repl.x'
FAKE_POS = span.Pos(FILENAME, 0, 0)
FAKE_SPAN = span.Span(FAKE_POS, FAKE_POS)
UN_KEYWORD = scanner.Token(scanner.TokenKind.KEYWORD, FAKE_SPAN,
                           scanner.Keyword.UN)
SN_KEYWORD = scanner.Token(scanner.TokenKind.KEYWORD, FAKE_SPAN,
                           scanner.Keyword.SN)


def concrete_type_to_annotation(
    concrete_type: concrete_type_mod.ConcreteType) -> ast.TypeAnnotation:
  if isinstance(concrete_type, concrete_type_mod.BitsType):
    keyword = SN_KEYWORD if concrete_type.get_signedness() else UN_KEYWORD
    num_tok = scanner.Token(scanner.TokenKind.NUMBER, FAKE_SPAN,
                            concrete_type.get_total_bit_count())
    return ast.make_builtin_type_annotation(
        FAKE_SPAN, keyword, dims=(ast.Number(num_tok),))

  raise NotImplementedError(concrete_type)