Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 32 additions & 12 deletions xls/jit/jit_wrapper_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,17 +227,31 @@ def is_float_tuple(t: type_pb2.TypeProto) -> bool:
return is_floating_point(t, 8, 23)


def to_c_type(t: type_pb2.TypeProto) -> str:
def to_c_type(t: type_pb2.TypeProto) -> Optional[str]:
"""Get the C++ type for the given XLS type.

Args:
t: The XLS type proto.

Returns:
The C++ type, or None if it can't be determined. None indicates an
XLS::Value should be used instead of the C++ type.
"""
c_type = to_specialized(t, int_only=True)
if c_type is not None:
return c_type
the_type = t.type_enum
if the_type == type_pb2.TypeProto.TUPLE:
inner = ", ".join(to_c_type(e) for e in t.tuple_elements)
return f"std::tuple<{inner}>"
elems = [to_c_type(e) for e in t.tuple_elements]
if any(e is None for e in elems):
return None
return f"std::tuple<{', '.join(elems)}>"
elif the_type == type_pb2.TypeProto.ARRAY:
return f"std::array<{to_c_type(t.array_element)}, {t.array_size}>"
raise app.UsageError(f"Cannot convert {t} to c_type")
elem_c_type = to_c_type(t.array_element)
if elem_c_type is None:
return None
return f"std::array<{elem_c_type}, {t.array_size}>"
return None


def to_specialized(
Expand Down Expand Up @@ -317,6 +331,12 @@ def to_domain(
app.UsageError: If the domain specification is invalid or unsupported for
the given type.
"""
if t.type_enum == type_pb2.TypeProto.ARRAY:
elem_domain = to_domain(t.array_element, None)
if elem_domain is None:
return None
return f"fuzztest::ArrayOf<{t.array_size}>({elem_domain})"

if (
d is None
or d.HasField("arbitrary")
Expand All @@ -340,11 +360,7 @@ def to_domain(
if any(e is None for e in elems):
return None
return f"fuzztest::TupleOf({', '.join(elems)})"
elif t.type_enum == type_pb2.TypeProto.ARRAY:
elem_domain = to_domain(t.array_element, None)
if elem_domain is None:
return None
return f"fuzztest::VectorOf({elem_domain}).WithSize({t.array_size})"

else:
return None

Expand Down Expand Up @@ -399,7 +415,7 @@ def to_value_conversion(t: type_pb2.TypeProto, expr: str) -> str:
elems = []
for i in range(t.array_size):
elems.append(to_value_conversion(t.array_element, f"{expr}[{i}]"))
return f"xls::Value::Array({{{', '.join(elems)}}})"
return f"xls::Value::ArrayOrDie({{{', '.join(elems)}}})"
raise app.UsageError(f"Unsupported type for value conversion: {t}")


Expand Down Expand Up @@ -620,7 +636,11 @@ def wrapped_to_fuzztest(
else:
cpp_type = to_c_type(p.type_proto)

conversion_snippet = to_value_conversion(p.type_proto, p.name)
if cpp_type is None:
cpp_type = "xls::Value"
conversion_snippet = None
else:
conversion_snippet = to_value_conversion(p.type_proto, p.name)

if (
p.type_proto.type_enum == type_pb2.TypeProto.TUPLE
Expand Down
65 changes: 62 additions & 3 deletions xls/jit/jit_wrapper_generator_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,25 @@ def test_nested_tuple(self):
'std::tuple<std::tuple<uint8_t, uint32_t>, uint64_t>',
)

def test_unsupported_bits(self):
u128 = type_pb2.TypeProto(type_enum=type_pb2.TypeProto.BITS, bit_count=128)
self.assertIsNone(jit_wrapper_generator.to_c_type(u128))

def test_unsupported_array(self):
u128 = type_pb2.TypeProto(type_enum=type_pb2.TypeProto.BITS, bit_count=128)
a128 = type_pb2.TypeProto(
type_enum=type_pb2.TypeProto.ARRAY, array_size=4, array_element=u128
)
self.assertIsNone(jit_wrapper_generator.to_c_type(a128))

def test_unsupported_tuple(self):
u8 = type_pb2.TypeProto(type_enum=type_pb2.TypeProto.BITS, bit_count=8)
u128 = type_pb2.TypeProto(type_enum=type_pb2.TypeProto.BITS, bit_count=128)
tup = type_pb2.TypeProto(
type_enum=type_pb2.TypeProto.TUPLE, tuple_elements=[u8, u128]
)
self.assertIsNone(jit_wrapper_generator.to_c_type(tup))


class JitWrapperGeneratorWrappedToFuzztestTest(absltest.TestCase):

Expand Down Expand Up @@ -357,6 +376,35 @@ def test_function_no_result(self):
self.assertLen(prop_func.params, 1)
self.assertEqual(prop_func.params[0].name, 'a')

def test_function_unsupported_param_fallback(self):
u128 = type_pb2.TypeProto(type_enum=type_pb2.TypeProto.BITS, bit_count=128)
wrapped_ir = jit_wrapper_generator.WrappedIr(
jit_type=jit_wrapper_generator.JitType.FUNCTION,
ir_text='',
function_name='big_bits_func',
class_name='BigBitsFuncJit',
header_guard='HEADER_GUARD',
header_filename='big_bits_func_jit.h',
namespace='xls',
aot_entrypoint=None,
params=[
jit_wrapper_generator.XlsNamedValue(
name='x',
type_proto=u128,
packed_type='',
unpacked_type='',
specialized_type=None,
),
],
result=None,
)
prop_func = jit_wrapper_generator.wrapped_to_fuzztest(
wrapped_ir, 'xls::BigBitsFuncJit', 'big_bits_func_jit.h'
)
self.assertLen(prop_func.params, 1)
self.assertEqual(prop_func.params[0].cpp_type, 'xls::Value')
self.assertIsNone(prop_func.params[0].conversion_snippet)


class JitWrapperGeneratorToValueConversionTest(absltest.TestCase):

Expand Down Expand Up @@ -391,7 +439,7 @@ def test_tuple_of_arrays(self):
)
self.assertEqual(
jit_wrapper_generator.to_value_conversion(tup, 't'),
'xls::Value::Tuple({xls::Value::Array({xls::Value(xls::UBits('
'xls::Value::Tuple({xls::Value::ArrayOrDie({xls::Value(xls::UBits('
'std::get<0>(t)[0], 8)), xls::Value(xls::UBits(std::get<0>(t)[1], 8))})'
'})',
)
Expand Down Expand Up @@ -420,7 +468,8 @@ def test_mixed_tuple(self):
self.assertEqual(
jit_wrapper_generator.to_value_conversion(tup, 't'),
'xls::Value::Tuple({xls::Value(xls::UBits(std::get<0>(t), 32)),'
' xls::Value::Array({xls::Value(xls::UBits(std::get<1>(t)[0], 8))})})',
' xls::Value::ArrayOrDie({xls::Value(xls::UBits(std::get<1>(t)[0],'
' 8))})})',
)


Expand Down Expand Up @@ -842,6 +891,16 @@ def test_nested_tuple_domain(self):
' fuzztest::TupleOf(fuzztest::InRange<uint32_t>(0, 5)))',
)

def test_array_domain(self):
u32 = type_pb2.TypeProto(type_enum=type_pb2.TypeProto.BITS, bit_count=32)
arr = type_pb2.TypeProto(
type_enum=type_pb2.TypeProto.ARRAY, array_size=3, array_element=u32
)
self.assertEqual(
jit_wrapper_generator.to_domain(arr, None),
'fuzztest::ArrayOf<3>(fuzztest::Arbitrary<uint32_t>())',
)

def test_tuple_with_array_domain(self):
u32 = type_pb2.TypeProto(type_enum=type_pb2.TypeProto.BITS, bit_count=32)
arr = type_pb2.TypeProto(
Expand All @@ -858,7 +917,7 @@ def test_tuple_with_array_domain(self):
self.assertEqual(
jit_wrapper_generator.to_domain(tup, d),
'fuzztest::TupleOf(fuzztest::Arbitrary<uint32_t>(),'
' fuzztest::VectorOf(fuzztest::Arbitrary<uint32_t>()).WithSize(3))',
' fuzztest::ArrayOf<3>(fuzztest::Arbitrary<uint32_t>()))',
)

def test_unsupported_domain_raises(self):
Expand Down
35 changes: 35 additions & 0 deletions xls/tests/fuzz_test/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,38 @@ dslx_fuzz_test(
library = ":enum_tests_dslx",
test_function = "oneof_enum",
)

xls_dslx_library(
name = "array_tests_dslx",
srcs = ["array_tests.x"],
)

dslx_fuzz_test(
name = "array_fuzz_test",
library = ":array_tests_dslx",
test_function = "arbitrary_array",
)

dslx_fuzz_test(
name = "array_of_tuples_fuzz_test",
library = ":array_tests_dslx",
test_function = "array_of_tuples",
)

dslx_fuzz_test(
name = "tuple_with_array_fuzz_test",
library = ":array_tests_dslx",
test_function = "tuple_with_array",
)

dslx_fuzz_test(
name = "big_array_fuzz_test",
library = ":array_tests_dslx",
test_function = "big_array",
)

dslx_fuzz_test(
name = "tuple_with_big_array_fuzz_test",
library = ":array_tests_dslx",
test_function = "tuple_with_big_array",
)
38 changes: 38 additions & 0 deletions xls/tests/fuzz_test/array_tests.x
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright 2026 The XLS Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[fuzz_test(domains=`()`)]
fn arbitrary_array(x: u32[3]) -> bool {
true
}

#[fuzz_test(domains=`()`)]
fn array_of_tuples(x: (u32, u32)[2]) -> bool {
true
}

#[fuzz_test(domains=`((), u32:0..9)`)]
fn tuple_with_array(x: (u32[2], u32)) -> bool {
true
}

#[fuzz_test(domains=`()`)]
fn big_array(x: uN[128][3]) -> bool {
true
}

#[fuzz_test(domains=`()`)]
fn tuple_with_big_array(x: (uN[128][2], u32)) -> bool {
true
}
Loading