Example #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.m,
                                     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.m,
                                     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_type_annotation(False, result_bits)
     return invocation, result_type
Example #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 self._is_unsigned_bit_vector(
          t) and 0 < self._get_type_bit_count(t) <= 8

    try:
      make_lhs, lhs_type = self._choose_env_value(env, choose_value)
    except EmptyEnvError:
      # If there's no natural environment value to use as the LHS, make up a
      # number and number of bits.
      bits = self.rng.randrange(1, 8)
      make_lhs = lambda: self._generate_number(env, bits, signedness=False)[0]
      lhs_type = self._make_type_annotation(False, bits)

    make_rhs, rhs_type = self._choose_env_value(env, self._not_tuple_or_array)
    cases = [make_rhs]
    assert self._is_unsigned_bit_vector(lhs_type), lhs_type
    total_operands = self._get_type_bit_count(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.m,
        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
Example #3
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(False, 1)
     return (ast.Invocation(self.m, self.fake_span, callee,
                            (make_arg(), )), type_)
Example #4
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_type = map_fn.params[0].type_
    assert self._is_bit_vector(map_arg_type), map_arg_type
    map_arg_signedness = not self._is_unsigned_bit_vector(map_arg_type)
    map_arg_bits = self._get_type_bit_count(map_arg_type)

    max_array_size = (
        self.options.max_width_aggregate_types //
        self._get_type_bit_count(map_fn.return_type))
    array_size = self.rng.randint(1, max(1, max_array_size))
    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.m, 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.m, self.fake_span,
                                self._builtin_name_ref('map'), (args, fn_ref))
    return invocation, return_type
Example #5
0
 def _make_range(self, zero: ast.Expr, arg: ast.Expr):
     return ast.Invocation(self.m,
                           self.fake_span,
                           self._builtin_name_ref('range'),
                           args=(zero, arg))