diff --git a/xls/build_rules/xls_ir_rules.bzl b/xls/build_rules/xls_ir_rules.bzl index a19f3588c7..a83504e1f9 100644 --- a/xls/build_rules/xls_ir_rules.bzl +++ b/xls/build_rules/xls_ir_rules.bzl @@ -146,6 +146,8 @@ def _convert_to_ir(ctx, src): IR_CONV_FLAGS = ( "dslx_path", "emit_fail_as_assert", + "emit_trace", + "emit_cover", "warnings_as_errors", "disable_warnings", "convert_tests", diff --git a/xls/dslx/ir_convert/convert_options.h b/xls/dslx/ir_convert/convert_options.h index bc24187883..67fcdb3694 100644 --- a/xls/dslx/ir_convert/convert_options.h +++ b/xls/dslx/ir_convert/convert_options.h @@ -36,6 +36,12 @@ struct ConvertOptions { // Whether to emit fail!() operations as predicated assertion IR nodes. bool emit_fail_as_assert = true; + // Whether to emit trace operations. + bool emit_trace = true; + + // Whether to emit cover operations. + bool emit_cover = true; + // Should the generated IR be verified? bool verify_ir = true; diff --git a/xls/dslx/ir_convert/function_converter.cc b/xls/dslx/ir_convert/function_converter.cc index edecac1b1d..5afed56446 100644 --- a/xls/dslx/ir_convert/function_converter.cc +++ b/xls/dslx/ir_convert/function_converter.cc @@ -2459,6 +2459,14 @@ absl::Status FunctionConverter::HandleFormatMacro(const FormatMacro* node) { XLS_RET_CHECK(implicit_token_data_->create_control_predicate != nullptr); BValue control_predicate = implicit_token_data_->create_control_predicate(); + // Don't generate anything if no traces. + if (!options_.emit_trace) { + Def(node, [&](const SourceInfo& loc) { + return implicit_token_data_->entry_token; + }); + return absl::OkStatus(); + } + // We have to rewrite the format string if a struct is present. // // Traverse through the original format steps, and if we encounter a struct, @@ -2532,6 +2540,14 @@ absl::Status FunctionConverter::HandleCoverBuiltin(const Invocation* node, XLS_RET_CHECK(implicit_token_data_->create_control_predicate != nullptr); BValue control_predicate = implicit_token_data_->create_control_predicate(); + // Don't generate anything if no traces. + if (!options_.emit_cover) { + Def(node, [&](const SourceInfo& loc) { + return implicit_token_data_->entry_token; + }); + return absl::OkStatus(); + } + // Variables: // * we got to the control point (CP) // * the cover condition (CC) diff --git a/xls/dslx/ir_convert/ir_converter_main.cc b/xls/dslx/ir_convert/ir_converter_main.cc index 484d963a44..6717a98ccd 100644 --- a/xls/dslx/ir_convert/ir_converter_main.cc +++ b/xls/dslx/ir_convert/ir_converter_main.cc @@ -103,6 +103,8 @@ absl::Status RealMain(absl::Span paths) { bool type_inference_v2 = ir_converter_options.type_inference_v2(); bool force_implicit_token_calling_convention = ir_converter_options.force_implicit_token_calling_convention(); + bool emit_trace = ir_converter_options.emit_trace(); + bool emit_cover = ir_converter_options.emit_cover(); // Start with the default set, then enable the to-enable and then disable the // to-disable. @@ -119,6 +121,8 @@ absl::Status RealMain(absl::Span paths) { const ConvertOptions convert_options = { .emit_positions = true, .emit_fail_as_assert = emit_fail_as_assert, + .emit_trace = emit_trace, + .emit_cover = emit_cover, .verify_ir = verify_ir, .warnings_as_errors = warnings_as_errors, .warnings = warnings, diff --git a/xls/dslx/ir_convert/ir_converter_options_flags.cc b/xls/dslx/ir_convert/ir_converter_options_flags.cc index 2166b26eca..944cee66a1 100644 --- a/xls/dslx/ir_convert/ir_converter_options_flags.cc +++ b/xls/dslx/ir_convert/ir_converter_options_flags.cc @@ -48,6 +48,10 @@ ABSL_FLAG( ABSL_FLAG(bool, emit_fail_as_assert, true, "Feature flag for emitting fail!() in the DSL as an assert IR op."); +ABSL_FLAG(bool, emit_trace, true, + "Feature flag for emitting trace!() in the DSL as a trace IR op."); +ABSL_FLAG(bool, emit_cover, true, + "Feature flag for emitting cover!() in the DSL as a cover IR op."); ABSL_FLAG(bool, convert_tests, false, "Feature flag for emitting test procs/functions to IR."); ABSL_FLAG(bool, verify, true, @@ -145,6 +149,8 @@ absl::StatusOr SetOptionsFromFlags(IrConverterOptionsFlagsProto& proto) { POPULATE_FLAG(lower_to_proc_scoped_channels); POPULATE_FLAG(force_implicit_token_calling_convention); POPULATE_REPEATED_FLAG(configured_values); + POPULATE_FLAG(emit_trace); + POPULATE_FLAG(emit_cover); #undef POPULATE_FLAG diff --git a/xls/dslx/ir_convert/ir_converter_options_flags.proto b/xls/dslx/ir_convert/ir_converter_options_flags.proto index 79b7c2af5a..afcf2acd46 100644 --- a/xls/dslx/ir_convert/ir_converter_options_flags.proto +++ b/xls/dslx/ir_convert/ir_converter_options_flags.proto @@ -42,4 +42,8 @@ message IrConverterOptionsFlagsProto { optional bool lower_to_proc_scoped_channels = 17; repeated string configured_values = 18; optional bool force_implicit_token_calling_convention = 19; + // If true will emit trace operations. + optional bool emit_trace = 20; + // If true will emit cover operations. + optional bool emit_cover = 21; } diff --git a/xls/dslx/ir_convert/ir_converter_test.cc b/xls/dslx/ir_convert/ir_converter_test.cc index 5a08f5761d..6e7a87fa5c 100644 --- a/xls/dslx/ir_convert/ir_converter_test.cc +++ b/xls/dslx/ir_convert/ir_converter_test.cc @@ -5699,6 +5699,48 @@ fn test_func() { "but test conversion is disabled"))); } +TEST_P(IrConverterWithBothTypecheckVersionsTest, NonSynthNoAssert) { + constexpr std::string_view program = + R"(fn f() -> u32 { + let x = u32:42; + assert!(x > u32:11, "bang"); + x +})"; + XLS_ASSERT_OK_AND_ASSIGN( + std::string converted, + ConvertOneFunctionForTest(program, "f", + ConvertOptions{.emit_fail_as_assert = false})); + ExpectIr(converted); +} + +TEST_P(IrConverterWithBothTypecheckVersionsTest, NonSynthNoTrace) { + constexpr std::string_view program = + R"(fn f() -> u32 { + let x = u32:42; + trace_fmt!("bang {}", x); + x +})"; + XLS_ASSERT_OK_AND_ASSIGN( + std::string converted, + ConvertOneFunctionForTest(program, "f", + ConvertOptions{.emit_trace = false})); + ExpectIr(converted); +} + +TEST_P(IrConverterWithBothTypecheckVersionsTest, NonSynthNoCover) { + constexpr std::string_view program = + R"(fn f() -> u32 { + let x = u32:42; + cover!("bang", x > u32:11); + x +})"; + XLS_ASSERT_OK_AND_ASSIGN( + std::string converted, + ConvertOneFunctionForTest(program, "f", + ConvertOptions{.emit_cover = false})); + ExpectIr(converted); +} + INSTANTIATE_TEST_SUITE_P(IrConverterWithBothTypecheckVersionsTestSuite, IrConverterWithBothTypecheckVersionsTest, testing::Values(TypeInferenceVersion::kVersion1, diff --git a/xls/dslx/ir_convert/testdata/ir_converter_test_NonSynthNoAssert.ir b/xls/dslx/ir_convert/testdata/ir_converter_test_NonSynthNoAssert.ir new file mode 100644 index 0000000000..db01a14227 --- /dev/null +++ b/xls/dslx/ir_convert/testdata/ir_converter_test_NonSynthNoAssert.ir @@ -0,0 +1,20 @@ +package test_module + +file_number 0 "test_module.x" + +fn __itok__test_module__f(__token: token id=1, __activated: bits[1] id=2) -> (token, bits[32]) { + x: bits[32] = literal(value=42, id=3, pos=[(0,1,10)]) + literal.4: bits[32] = literal(value=11, id=4, pos=[(0,2,14)]) + after_all.8: token = after_all(id=8) + ugt.5: bits[1] = ugt(x, literal.4, id=5, pos=[(0,2,10)]) + literal.6: bits[8][4] = literal(value=[98, 97, 110, 103], id=6, pos=[(0,2,22)]) + tuple.7: () = tuple(id=7) + ret tuple.9: (token, bits[32]) = tuple(after_all.8, x, id=9) +} + +top fn __test_module__f() -> bits[32] { + after_all.10: token = after_all(id=10) + literal.11: bits[1] = literal(value=1, id=11) + invoke.12: (token, bits[32]) = invoke(after_all.10, literal.11, to_apply=__itok__test_module__f, id=12) + ret tuple_index.13: bits[32] = tuple_index(invoke.12, index=1, id=13) +} diff --git a/xls/dslx/ir_convert/testdata/ir_converter_test_NonSynthNoCover.ir b/xls/dslx/ir_convert/testdata/ir_converter_test_NonSynthNoCover.ir new file mode 100644 index 0000000000..a683ba6c11 --- /dev/null +++ b/xls/dslx/ir_convert/testdata/ir_converter_test_NonSynthNoCover.ir @@ -0,0 +1,19 @@ +package test_module + +file_number 0 "test_module.x" + +fn __itok__test_module__f(__token: token id=1, __activated: bits[1] id=2) -> (token, bits[32]) { + x: bits[32] = literal(value=42, id=3, pos=[(0,1,10)]) + literal.5: bits[32] = literal(value=11, id=5, pos=[(0,2,21)]) + after_all.7: token = after_all(id=7) + literal.4: bits[8][4] = literal(value=[98, 97, 110, 103], id=4, pos=[(0,2,9)]) + ugt.6: bits[1] = ugt(x, literal.5, id=6, pos=[(0,2,17)]) + ret tuple.8: (token, bits[32]) = tuple(after_all.7, x, id=8) +} + +top fn __test_module__f() -> bits[32] { + after_all.9: token = after_all(id=9) + literal.10: bits[1] = literal(value=1, id=10) + invoke.11: (token, bits[32]) = invoke(after_all.9, literal.10, to_apply=__itok__test_module__f, id=11) + ret tuple_index.12: bits[32] = tuple_index(invoke.11, index=1, id=12) +} diff --git a/xls/dslx/ir_convert/testdata/ir_converter_test_NonSynthNoTrace.ir b/xls/dslx/ir_convert/testdata/ir_converter_test_NonSynthNoTrace.ir new file mode 100644 index 0000000000..ee1c452467 --- /dev/null +++ b/xls/dslx/ir_convert/testdata/ir_converter_test_NonSynthNoTrace.ir @@ -0,0 +1,16 @@ +package test_module + +file_number 0 "test_module.x" + +fn __itok__test_module__f(__token: token id=1, __activated: bits[1] id=2) -> (token, bits[32]) { + after_all.4: token = after_all(id=4) + x: bits[32] = literal(value=42, id=3, pos=[(0,1,10)]) + ret tuple.5: (token, bits[32]) = tuple(after_all.4, x, id=5) +} + +top fn __test_module__f() -> bits[32] { + after_all.6: token = after_all(id=6) + literal.7: bits[1] = literal(value=1, id=7) + invoke.8: (token, bits[32]) = invoke(after_all.6, literal.7, to_apply=__itok__test_module__f, id=8) + ret tuple_index.9: bits[32] = tuple_index(invoke.8, index=1, id=9) +}