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. lhs = ast.Binop(self.m, self.fake_span, ast.BinopKind.NE, make_lhs(), self._make_number(0, lhs_type)) rhs = ast.Binop(self.m, self.fake_span, ast.BinopKind.NE, make_rhs(), self._make_number(0, rhs_type)) # Pick some operation to do. op = self.rng.choice([ast.BinopKind.LOGICAL_AND, ast.BinopKind.LOGICAL_OR]) return ast.Binop(self.m, self.fake_span, op, lhs, rhs), self._make_type_annotation(False, 1)
def test_format_binop(self): m = ast.Module('test') fake_pos = self.fake_pos fake_span = Span(fake_pos, fake_pos) le = ast.Binop(m, Token(TokenKind.OANGLE_EQUALS, span=fake_span), self.five, self.five) self.assertEqual('(5) <= (5)', str(le))
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))
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)
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.BinopKind.COMPARISON_KIND_LIST) output_type = self._make_type_annotation(False, 1) else: op = self.rng.choice(self._binops) if op in ast.BinopKind.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(self.m, self.fake_span, op, lhs, rhs), output_type
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)
def _make_ge(self, lhs: ast.Expr, rhs: ast.Expr) -> ast.Expr: return ast.Binop(self.m, self.fake_span, ast.BinopKind.GE, lhs, rhs)