Beispiel #1
0
 def _generate_unop_builtin(
         self, env: Env) -> Tuple[ast.Invocation, ast.TypeAnnotation]:
     """Generates a call to a unary builtin."""
     make_arg, arg_type = self._choose_env_value(env,
                                                 self._is_builtin_unsigned)
     choices = ['clz']
     # Since one_hot adds a bit, only use it when we have head room beneath
     # max_width_bits_types to add another bit.
     one_hot_ok = builtin_type_to_bits(
         arg_type) < self.options.max_width_bits_types
     if one_hot_ok:
         choices.append('one_hot')
     to_invoke = self.rng.choice(choices)
     if to_invoke == 'clz':
         invocation = ast.Invocation(self.fake_span,
                                     self._builtin_name_ref(to_invoke),
                                     args=(make_arg(), ))
         result_type = arg_type
     else:
         assert to_invoke == 'one_hot'
         lsb_or_msb = self.rng.choice((True, False))
         invocation = ast.Invocation(self.fake_span,
                                     self._builtin_name_ref(to_invoke),
                                     args=(make_arg(),
                                           self._make_bool(lsb_or_msb)))
         result_bits = builtin_type_to_bits(arg_type) + 1
         result_type = self._make_large_type_annotation('UN', result_bits)
     return invocation, result_type
Beispiel #2
0
    def _generate_one_hot_select_builtin(
            self, env: Env) -> Tuple[ast.Invocation, ast.TypeAnnotation]:
        """Generates an invocation of the one_hot_sel builtin."""

        # We need to choose a selector with a certain number of bits, then form an
        # array from that many values in the environment.
        def choose_value(t: ast.TypeAnnotation) -> bool:
            return not isinstance(
                t, ast.TupleTypeAnnotation) and not isinstance(
                    t, ast.ArrayTypeAnnotation) and builtin_type_to_bits(t) < 8

        try:
            make_lhs, lhs_type = self._choose_env_value(env, choose_value)
        except EmptyEnvError:
            bits = self.rng.randrange(1, 8)
            make_lhs = lambda: self._generate_number(
                env, bits, signedness=False)[0]
            lhs_type = self._make_large_type_annotation('UN', bits)
        make_rhs, rhs_type = self._choose_env_value(env,
                                                    self._not_tuple_or_array)
        cases = [make_rhs]
        total_operands = builtin_type_to_bits(lhs_type)
        for _ in range(total_operands - 1):
            make_rhs, rhs_type = self._choose_env_value(
                env, lambda t: t == rhs_type)
            cases.append(make_rhs)

        invocation = ast.Invocation(
            self.fake_span,
            self._builtin_name_ref('one_hot_sel'),
            args=(make_lhs(),
                  self._make_array(tuple(make_case() for make_case in cases))))
        return invocation, rhs_type
Beispiel #3
0
    def _generate_map(self, level,
                      env: Env) -> Tuple[ast.Invocation, ast.TypeAnnotation]:
        """Generates an invocation of the map builtin."""

        map_fn_name = self.gensym()
        # generate_function, in turn, can call generate_map, so we need some way of
        # bounding the recursion. To limit explosion, we increase level by three
        # (chosen empirically) instead of just one.
        map_fn = self.generate_function(map_fn_name, level + 3, param_count=1)
        self._functions.append(map_fn)

        map_arg_signedness, map_arg_bits = builtin_type_to_signedness_and_bits(
            map_fn.params[0].type_)

        array_size = self.rng.randrange(
            1, max(2, self.options.max_width_aggregate_types // map_arg_bits))
        return_type = self._make_array_type(map_fn.return_type, array_size)

        # Seems pretty unlikely that we'll have the exact array we need, so we'll
        # just create one.
        # TODO(b/144724970): Consider creating arrays from values in the env.
        def get_number():
            return self._generate_number(env, map_arg_bits, map_arg_signedness)

        args = self._make_constant_array(
            tuple(get_number()[0] for i in range(array_size)))
        args.type_ = ast.ArrayTypeAnnotation(
            self.fake_span, map_fn.params[0].type_,
            self._make_number(array_size, None))

        fn_ref = self._make_name_ref(self._make_name_def(map_fn_name))
        invocation = ast.Invocation(self.fake_span,
                                    self._builtin_name_ref('map'),
                                    (args, fn_ref))
        return invocation, return_type
Beispiel #4
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, ))
Beispiel #5
0
 def _generate_bitwise_reduction(
         self, env: Env) -> Tuple[ast.Invocation, ast.TypeAnnotation]:
     """Generates one of the bitwise reductions as an Invocation node."""
     make_arg, _ = self._choose_env_value(env, self._is_builtin_unsigned)
     ops = ['and_reduce', 'or_reduce', 'xor_reduce']
     callee = self._builtin_name_ref(self.rng.choice(ops))
     type_ = self._make_type_annotation('u1')
     return (ast.Invocation(self.fake_span, callee, (make_arg(), )), type_)
Beispiel #6
0
 def _make_range(self, zero: ast.Expr, arg: ast.Expr):
     return ast.Invocation(self.fake_span,
                           self._builtin_name_ref('range'),
                           args=(zero, arg))