Skip to content

Commit 5c5cdc6

Browse files
allightcopybara-github
authored andcommitted
Refactor Verilog fuzzing to use a VerilogGenerator struct.
This change introduces a `VerilogGenerator` struct that encapsulates the XLS package, scheduling options, and codegen options. The fuzz domains now generate instances of `VerilogGenerator`, and the actual Verilog generation is performed by calling the `GenerateVerilog()` method on this struct. This allows fuzz tests to access the inputs (package and options) even when codegen fails, aiding in debugging. PiperOrigin-RevId: 872027638
1 parent 88d3f34 commit 5c5cdc6

File tree

4 files changed

+103
-52
lines changed

4 files changed

+103
-52
lines changed

xls/fuzzer/verilog_fuzzer/BUILD

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ cc_library(
3636
"//xls/public:runtime_codegen_actions",
3737
"//xls/tools:codegen_flags_cc_proto",
3838
"//xls/tools:scheduling_options_flags_cc_proto",
39+
"@com_google_absl//absl/log",
3940
"@com_google_absl//absl/log:check",
4041
"@com_google_absl//absl/status:statusor",
4142
],
@@ -48,6 +49,7 @@ cc_test(
4849
":verilog_fuzz_domain",
4950
"//xls/common:xls_gunit_main",
5051
"//xls/common/fuzzing:fuzztest",
52+
"//xls/fuzzer/ir_fuzzer:ir_fuzz_domain",
5153
"//xls/tools:codegen_flags_cc_proto",
5254
"//xls/tools:scheduling_options_flags_cc_proto",
5355
"@com_google_absl//absl/status",

xls/fuzzer/verilog_fuzzer/codegen_fuzz_test.cc

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "absl/status/status.h"
2121
#include "absl/status/status_matchers.h"
2222
#include "absl/status/statusor.h"
23+
#include "xls/fuzzer/ir_fuzzer/ir_fuzz_domain.h"
2324
#include "xls/fuzzer/verilog_fuzzer/verilog_fuzz_domain.h"
2425
#include "xls/tools/codegen_flags.pb.h"
2526
#include "xls/tools/scheduling_options_flags.pb.h"
@@ -36,6 +37,13 @@ using ::testing::Not;
3637

3738
constexpr std::string_view kTop = "dut";
3839

40+
MATCHER_P(HasVerilogText, text,
41+
absl::StrCat("Expected verilog text to match ",
42+
testing::DescribeMatcher<std::string>(text))) {
43+
return testing::ExplainMatchResult(text, arg.codegen_result.verilog_text,
44+
result_listener);
45+
}
46+
3947
SchedulingOptionsFlagsProto DefaultSchedulingOptions() {
4048
SchedulingOptionsFlagsProto scheduling_options;
4149
scheduling_options.set_delay_model("sky130");
@@ -55,15 +63,18 @@ CodegenFlagsProto DefaultCodegenOptions() {
5563
}
5664

5765
void CodegenSucceedsForEveryFunctionWithNoPipelineLimit(
58-
absl::StatusOr<std::string> verilog) {
59-
EXPECT_THAT(verilog, IsOkAndHolds(Not(IsEmpty())));
66+
VerilogGenerator verilog) {
67+
auto result = verilog.GenerateVerilog();
68+
EXPECT_THAT(result, IsOkAndHolds(HasVerilogText(Not(IsEmpty()))))
69+
<< result.status();
6070
}
71+
6172
FUZZ_TEST(CodegenFuzzTest, CodegenSucceedsForEveryFunctionWithNoPipelineLimit)
62-
.WithDomains(StatusOrVerilogFuzzDomain(DefaultSchedulingOptions(),
63-
DefaultCodegenOptions()));
73+
.WithDomains(VerilogGeneratorDomain(
74+
IrFuzzDomain(), fuzztest::Just(DefaultSchedulingOptions()),
75+
fuzztest::Just(DefaultCodegenOptions())));
6476

65-
void CodegenSucceedsOrThrowsReasonableError(
66-
absl::StatusOr<std::string> verilog) {
77+
void CodegenSucceedsOrThrowsReasonableError(VerilogGenerator verilog) {
6778
// We check for success or expected errors here. The expected errors are:
6879
// - absl::NotFoundError("No delay estimator found named")- an
6980
// incorrectly-named delay estimator in the scheduling options.
@@ -77,8 +88,8 @@ void CodegenSucceedsOrThrowsReasonableError(
7788
// We don't expect:
7889
// - CHECK-fails, OOMs, etc.
7990
// - Random absl::InternalError(), or other "unexpected" errors.
80-
EXPECT_THAT(verilog,
81-
AnyOf(IsOkAndHolds(Not(IsEmpty())),
91+
EXPECT_THAT(verilog.GenerateVerilog(),
92+
AnyOf(IsOkAndHolds(HasVerilogText(Not(IsEmpty()))),
8293
StatusIs(absl::StatusCode::kNotFound,
8394
HasSubstr("No delay estimator found named")),
8495
StatusIs(absl::StatusCode::kInternal,
@@ -89,9 +100,9 @@ void CodegenSucceedsOrThrowsReasonableError(
89100
absl::StatusCode::kUnimplemented))));
90101
}
91102
FUZZ_TEST(CodegenFuzzTest, CodegenSucceedsOrThrowsReasonableError)
92-
.WithDomains(fuzztest::FlatMap(StatusOrVerilogFuzzDomain,
93-
NoFdoSchedulingOptionsFlagsDomain(),
94-
CodegenFlagsDomain()));
103+
.WithDomains(VerilogGeneratorDomain(IrFuzzDomain(),
104+
NoFdoSchedulingOptionsFlagsDomain(),
105+
CodegenFlagsDomain()));
95106

96107
} // namespace
97108
} // namespace xls

xls/fuzzer/verilog_fuzzer/verilog_fuzz_domain.cc

Lines changed: 49 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@
1616

1717
#include <memory>
1818
#include <string>
19+
#include <utility>
1920

2021
#include "xls/common/fuzzing/fuzztest.h"
2122
#include "absl/log/check.h"
23+
#include "absl/log/log.h"
2224
#include "absl/status/statusor.h"
2325
#include "xls/common/logging/log_lines.h"
2426
#include "xls/common/status/ret_check.h"
@@ -31,51 +33,65 @@
3133

3234
namespace xls {
3335

34-
fuzztest::Domain<absl::StatusOr<std::string>> StatusOrVerilogFuzzDomain(
35-
SchedulingOptionsFlagsProto scheduling_options,
36-
CodegenFlagsProto codegen_options) {
37-
return fuzztest::Map(
38-
[scheduling_options, codegen_options](
39-
std::shared_ptr<Package> package) -> absl::StatusOr<std::string> {
40-
XLS_RET_CHECK_GE(package->functions().size(), 1)
41-
<< "We expect IrFuzzDomain() to return a package with at least one "
42-
"function.\n"
43-
<< package->DumpIr();
44-
// Make the function the top-level module.
45-
XLS_RETURN_IF_ERROR(package->SetTop(package->functions().front().get()))
46-
<< "Failed to set top-level module in:\n"
47-
<< package->DumpIr();
36+
fuzztest::Domain<VerilogGenerator> VerilogGeneratorDomain(
37+
fuzztest::Domain<std::shared_ptr<Package>>&& package_domain,
38+
fuzztest::Domain<SchedulingOptionsFlagsProto>&& scheduling_options,
39+
fuzztest::Domain<CodegenFlagsProto>&& codegen_options) {
40+
return fuzztest::StructOf<VerilogGenerator>(std::move(package_domain),
41+
std::move(scheduling_options),
42+
std::move(codegen_options));
43+
}
4844

49-
XLS_ASSIGN_OR_RETURN(
50-
(auto [scheduling_result, codegen_result]),
51-
ScheduleAndCodegenPackage(package.get(), scheduling_options,
52-
codegen_options,
53-
/*with_delay_model=*/true),
54-
_ << " while scheduling and codegening package:\n"
55-
<< package->DumpIr());
45+
absl::StatusOr<ScheduleAndCodegenResult> VerilogGenerator::GenerateVerilog() {
46+
XLS_RET_CHECK_GE(package->functions().size(), 1)
47+
<< "We expect IrFuzzDomain() to return a package with at least one "
48+
"function.\n"
49+
<< package->DumpIr();
50+
// Make the function the top-level module.
51+
XLS_RETURN_IF_ERROR(package->SetTop(package->functions().front().get()))
52+
<< "Failed to set top-level module in:\n"
53+
<< package->DumpIr();
5654

57-
XLS_LOG_LINES(INFO, package->DumpIr());
58-
XLS_LOG_LINES(INFO, codegen_result.verilog_text);
55+
XLS_ASSIGN_OR_RETURN(auto result,
56+
ScheduleAndCodegenPackage(
57+
package.get(), scheduling_options, codegen_options,
58+
/*with_delay_model=*/true),
59+
_ << " while scheduling and codegening package:\n"
60+
<< package->DumpIr());
5961

60-
return codegen_result.verilog_text;
61-
},
62-
IrFuzzDomain());
62+
if (VLOG_IS_ON(2)) {
63+
XLS_LOG_LINES(INFO, package->DumpIr());
64+
XLS_LOG_LINES(INFO, result.codegen_result.verilog_text);
65+
}
66+
67+
return std::move(result);
68+
}
69+
70+
namespace internal {
71+
std::string UnwrapStatusOrVerilog(
72+
const absl::StatusOr<ScheduleAndCodegenResult>& verilog) {
73+
CHECK_OK(verilog.status());
74+
return verilog->codegen_result.verilog_text;
75+
}
76+
absl::StatusOr<ScheduleAndCodegenResult> DoGenerateVerilog(
77+
VerilogGenerator verilog) {
78+
return verilog.GenerateVerilog();
6379
}
80+
} // namespace internal
6481

6582
fuzztest::Domain<std::string> VerilogFuzzDomain(
6683
SchedulingOptionsFlagsProto scheduling_options,
6784
CodegenFlagsProto codegen_options) {
6885
return fuzztest::Map(
69-
[](absl::StatusOr<std::string> verilog) -> std::string {
70-
// Should be filtered
71-
CHECK_OK(verilog.status());
72-
return *verilog;
73-
},
86+
&internal::UnwrapStatusOrVerilog,
7487
fuzztest::Filter(
75-
[](const absl::StatusOr<std::string> &verilog) {
88+
[](const absl::StatusOr<ScheduleAndCodegenResult>& verilog) {
7689
return verilog.ok();
7790
},
78-
StatusOrVerilogFuzzDomain(scheduling_options, codegen_options)));
91+
fuzztest::Map(internal::DoGenerateVerilog,
92+
VerilogGeneratorDomain(
93+
IrFuzzDomain(), fuzztest::Just(scheduling_options),
94+
fuzztest::Just(codegen_options)))));
7995
}
8096

8197
fuzztest::Domain<CodegenFlagsProto> CodegenFlagsDomain() {

xls/fuzzer/verilog_fuzzer/verilog_fuzz_domain.h

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,21 @@
1919

2020
#include "xls/common/fuzzing/fuzztest.h"
2121
#include "absl/status/statusor.h"
22+
#include "xls/fuzzer/ir_fuzzer/ir_fuzz_domain.h"
23+
#include "xls/ir/package.h"
24+
#include "xls/public/runtime_codegen_actions.h"
2225
#include "xls/tools/codegen_flags.pb.h"
2326
#include "xls/tools/scheduling_options_flags.pb.h"
2427

2528
namespace xls {
2629

27-
// A domain that generates standalone Verilog files.
28-
// These files are created by taking the output of IrFuzzDomain() and
29-
// running codegen on it with the provided options. The returned domain
30-
// contains a StatusOr<> because codegen can fail for a variety of reasons,
31-
// e.g. scheduling options that cannot be satisfied.
32-
fuzztest::Domain<absl::StatusOr<std::string>> StatusOrVerilogFuzzDomain(
33-
SchedulingOptionsFlagsProto scheduling_options,
34-
CodegenFlagsProto codegen_options);
30+
struct VerilogGenerator {
31+
std::shared_ptr<Package> package;
32+
SchedulingOptionsFlagsProto scheduling_options;
33+
CodegenFlagsProto codegen_options;
34+
35+
absl::StatusOr<ScheduleAndCodegenResult> GenerateVerilog();
36+
};
3537

3638
// A domain like StatusOrVerilogFuzzDomain that filters out any inputs that are
3739
// infeasible given the provided scheduling and codegen options.
@@ -48,6 +50,26 @@ fuzztest::Domain<CodegenFlagsProto> CodegenFlagsDomain();
4850
fuzztest::Domain<SchedulingOptionsFlagsProto>
4951
NoFdoSchedulingOptionsFlagsDomain();
5052

53+
// A domain that can be used to create verilog out of arbitrary xls packages.
54+
//
55+
// To get the actual verilog the user should call the 'GenerateVerilog()'
56+
// function. This domain may not always be able to generate verilog because
57+
// some combinations of XLS packages and scheduling/codegen options are
58+
// infeasible.
59+
fuzztest::Domain<VerilogGenerator> VerilogGeneratorDomain(
60+
fuzztest::Domain<std::shared_ptr<Package>>&& package_domain =
61+
IrFuzzDomain(),
62+
fuzztest::Domain<SchedulingOptionsFlagsProto>&& scheduling_options =
63+
NoFdoSchedulingOptionsFlagsDomain(),
64+
fuzztest::Domain<CodegenFlagsProto>&& codegen_options =
65+
CodegenFlagsDomain());
66+
namespace internal {
67+
std::string UnwrapStatusOrVerilog(
68+
const absl::StatusOr<ScheduleAndCodegenResult>& verilog);
69+
absl::StatusOr<ScheduleAndCodegenResult> DoGenerateVerilog(
70+
VerilogGenerator verilog);
71+
} // namespace internal
72+
5173
} // namespace xls
5274

5375
#endif // XLS_FUZZER_IR_FUZZER_VERILOG_FUZZ_DOMAIN_H_

0 commit comments

Comments
 (0)