diff --git a/docs_src/passes_list.md b/docs_src/passes_list.md index 186105ee41..3b1404ebee 100755 --- a/docs_src/passes_list.md +++ b/docs_src/passes_list.md @@ -30,6 +30,7 @@ value. - [simplify-and-inline](#simplify-and-inline) - [post-inlining](#post-inlining) +- [prepare-for-scheduling](#prepare-for-scheduling) @@ -178,6 +179,39 @@ class CanonicalizationPass iterates over nodes and tries to canonicalize the exp +## canonicalize_proc_state - canonicalize proc state representation {#canonicalize_proc_state} + + +Bring proc-state representation to the canonical 'flat' representationother passes expect. + + +[Text-proto](http://github.com/google/xls/tree/main/xls/passes/optimization_pass_pipeline.txtpb) + + +### Options Set + + +Run to a fixedpoint. + + + + + + + + +### Invoked Passes + + +- [fixedpoint_proc_state_flattening](#fixedpoint_proc_state_flattening) +- [proc_state_bits_shatter](#proc_state_bits_shatter) +- [proc_state_tuple_flat](#proc_state_tuple_flat) +- [ident_remove](#ident_remove) +- [dataflow](#dataflow) +- [dce](#dce) + + + ## channel_legalization - Legalize multiple send/recvs per channel {#channel_legalization} @@ -772,6 +806,12 @@ Passes performed after inlining - [fixedpoint_simp(2)](#fixedpoint_simp2) - [cond_spec(noBdd)](#cond_specnoBdd) +- [canonicalize_proc_state](#canonicalize_proc_state) +- [non_synth_separation](#non_synth_separation) +- [dce](#dce) +- [next_value_opt](#next_value_opt) +- [dce](#dce) +- [fixedpoint_simp(2)](#fixedpoint_simp2) - [dce](#dce) - [bdd_simp(2)](#bdd_simp2) - [dce](#dce) @@ -799,13 +839,13 @@ Passes performed after inlining - [channel_legalization](#channel_legalization) - [token_dependency](#token_dependency) - [fixedpoint_simp(2)](#fixedpoint_simp2) -- [fixedpoint_proc_state_flattening](#fixedpoint_proc_state_flattening) -- [proc_state_bits_shatter](#proc_state_bits_shatter) -- [proc_state_tuple_flat](#proc_state_tuple_flat) -- [ident_remove](#ident_remove) -- [dataflow](#dataflow) +- [canonicalize_proc_state](#canonicalize_proc_state) +- [non_synth_separation](#non_synth_separation) +- [dce](#dce) - [next_value_opt](#next_value_opt) - [dce](#dce) +- [fixedpoint_simp(2)](#fixedpoint_simp2) +- [dce](#dce) - [proc_state_narrow](#proc_state_narrow) - [dce](#dce) - [proc_state_opt](#proc_state_opt) @@ -899,6 +939,42 @@ Passes performed before each inlining. +## prepare-for-scheduling - Prepare for scheduling optimization passes {#prepare-for-scheduling} + + +Passes performed at the very end of optimization. + +TODO(allight): We might want to move resource sharing into here fororganizational reasons. + +TODO(allight): The duplication between this and [scheduling-opt](#scheduling-opt) is a massive code-smell. Significant adjustments to codegen/sched pass pipelines are likely required. + + +[Text-proto](http://github.com/google/xls/tree/main/xls/passes/optimization_pass_pipeline.txtpb) + + +### Options Set + + + + +Min opt level: 1 + + + + + + +### Invoked Passes + + +- [full-inlining](#full-inlining) +- [dce](#dce) +- [dfe](#dfe) +- [fixedpoint_simp](#fixedpoint_simp) +- [dce](#dce) + + + ## proc_state_array_flat - Proc State Array Flattening {#proc_state_array_flat} @@ -1059,6 +1135,11 @@ Min opt level: 1 - [fixedpoint_simp](#fixedpoint_simp) - [dce](#dce) +- [full-inlining](#full-inlining) +- [dce](#dce) +- [dfe](#dfe) +- [useless_assert_remove](#useless_assert_remove) +- [dce](#dce) diff --git a/xls/codegen/testdata/assertions_comb_multiple_ifdef_guards.svtxt b/xls/codegen/testdata/assertions_comb_multiple_ifdef_guards.svtxt old mode 100644 new mode 100755 index 78c8340950..f09a065b42 --- a/xls/codegen/testdata/assertions_comb_multiple_ifdef_guards.svtxt +++ b/xls/codegen/testdata/assertions_comb_multiple_ifdef_guards.svtxt @@ -2,24 +2,24 @@ module assertions_top( input wire [31:0] y, output wire [31:0] out ); - wire [30:0] add_195; - wire ult_202; - wire [30:0] add_209; - wire ult_206; - wire nand_211; - wire nand_212; - assign add_195 = y[31:1] + 31'h7fff_fffb; - assign ult_202 = y < 32'h0000_0014; - assign add_209 = y[31:1] + 31'h0000_000f; - assign ult_206 = y < 32'h0000_000a; - assign nand_211 = ~(y > 32'h0000_0009 & ult_202 & {add_195, y[0]} > 32'h0000_0004); - assign nand_212 = ~(ult_206 & y > 32'h0000_0004); - assign out = ult_206 ? {add_209, y[0]} : y & {32{ult_202}}; + wire [30:0] add_270; + wire ult_277; + wire [30:0] add_284; + wire ult_281; + wire nand_286; + wire nand_287; + assign add_270 = y[31:1] + 31'h7fff_fffb; + assign ult_277 = y < 32'h0000_0014; + assign add_284 = y[31:1] + 31'h0000_000f; + assign ult_281 = y < 32'h0000_000a; + assign nand_286 = ~(y > 32'h0000_0009 & ult_277 & {add_270, y[0]} > 32'h0000_0004); + assign nand_287 = ~(ult_281 & y > 32'h0000_0004); + assign out = ult_281 ? {add_284, y[0]} : y & {32{ult_277}}; `ifdef ASSERT_ON `ifndef SYNTHESIS - y_ge_than_21: assert final ($isunknown(ult_202) || ult_202) else $fatal(0, "Assertion failure via fail! @ xls/examples/assertions/assertions.x:32:14-32:37"); - __assertions__main_0___itok__assertions__main___itok__assertions__main_0___itok__assertions__func_0__32_x_less_than_5: assert final ($isunknown(nand_211) || nand_211) else $fatal(0, "Assertion failure via assert! @ xls/examples/assertions/assertions.x:21:12-21:40"); - __assertions__main_0___itok__assertions__main___itok__assertions__main_1___itok__assertions__func_0__32_x_less_than_5: assert final ($isunknown(nand_212) || nand_212) else $fatal(0, "Assertion failure via assert! @ xls/examples/assertions/assertions.x:21:12-21:40"); + __assertions__main_1_non_synth___assertions__main_non_synth___assertions__main_0_non_synth_non_synth___assertions__main_y_ge_than_21: assert final ($isunknown(ult_277) || ult_277) else $fatal(0, "Assertion failure via fail! @ xls/examples/assertions/assertions.x:32:14-32:37"); + __assertions__main_1_non_synth___assertions__main_non_synth___assertions__main_0_non_synth_non_synth___assertions__main___assertions__main_0___itok__assertions__main___itok__assertions__main_0___itok__assertions__func_0__32_x_less_than_5: assert final ($isunknown(nand_286) || nand_286) else $fatal(0, "Assertion failure via assert! @ xls/examples/assertions/assertions.x:21:12-21:40"); + __assertions__main_1_non_synth___assertions__main_non_synth___assertions__main_0_non_synth_non_synth___assertions__main___assertions__main_0___itok__assertions__main___itok__assertions__main_1___itok__assertions__func_0__32_x_less_than_5: assert final ($isunknown(nand_287) || nand_287) else $fatal(0, "Assertion failure via assert! @ xls/examples/assertions/assertions.x:21:12-21:40"); `endif // SYNTHESIS `endif // ASSERT_ON endmodule diff --git a/xls/codegen/testdata/assertions_comb_no_ifdef_guards.svtxt b/xls/codegen/testdata/assertions_comb_no_ifdef_guards.svtxt old mode 100644 new mode 100755 index b28a8872a7..495062bd46 --- a/xls/codegen/testdata/assertions_comb_no_ifdef_guards.svtxt +++ b/xls/codegen/testdata/assertions_comb_no_ifdef_guards.svtxt @@ -2,20 +2,20 @@ module assertions_top( input wire [31:0] y, output wire [31:0] out ); - wire [30:0] add_195; - wire ult_202; - wire [30:0] add_209; - wire ult_206; - wire nand_211; - wire nand_212; - assign add_195 = y[31:1] + 31'h7fff_fffb; - assign ult_202 = y < 32'h0000_0014; - assign add_209 = y[31:1] + 31'h0000_000f; - assign ult_206 = y < 32'h0000_000a; - assign nand_211 = ~(y > 32'h0000_0009 & ult_202 & {add_195, y[0]} > 32'h0000_0004); - assign nand_212 = ~(ult_206 & y > 32'h0000_0004); - assign out = ult_206 ? {add_209, y[0]} : y & {32{ult_202}}; - y_ge_than_21: assert final ($isunknown(ult_202) || ult_202) else $fatal(0, "Assertion failure via fail! @ xls/examples/assertions/assertions.x:32:14-32:37"); - __assertions__main_0___itok__assertions__main___itok__assertions__main_0___itok__assertions__func_0__32_x_less_than_5: assert final ($isunknown(nand_211) || nand_211) else $fatal(0, "Assertion failure via assert! @ xls/examples/assertions/assertions.x:21:12-21:40"); - __assertions__main_0___itok__assertions__main___itok__assertions__main_1___itok__assertions__func_0__32_x_less_than_5: assert final ($isunknown(nand_212) || nand_212) else $fatal(0, "Assertion failure via assert! @ xls/examples/assertions/assertions.x:21:12-21:40"); + wire [30:0] add_270; + wire ult_277; + wire [30:0] add_284; + wire ult_281; + wire nand_286; + wire nand_287; + assign add_270 = y[31:1] + 31'h7fff_fffb; + assign ult_277 = y < 32'h0000_0014; + assign add_284 = y[31:1] + 31'h0000_000f; + assign ult_281 = y < 32'h0000_000a; + assign nand_286 = ~(y > 32'h0000_0009 & ult_277 & {add_270, y[0]} > 32'h0000_0004); + assign nand_287 = ~(ult_281 & y > 32'h0000_0004); + assign out = ult_281 ? {add_284, y[0]} : y & {32{ult_277}}; + __assertions__main_1_non_synth___assertions__main_non_synth___assertions__main_0_non_synth_non_synth___assertions__main_y_ge_than_21: assert final ($isunknown(ult_277) || ult_277) else $fatal(0, "Assertion failure via fail! @ xls/examples/assertions/assertions.x:32:14-32:37"); + __assertions__main_1_non_synth___assertions__main_non_synth___assertions__main_0_non_synth_non_synth___assertions__main___assertions__main_0___itok__assertions__main___itok__assertions__main_0___itok__assertions__func_0__32_x_less_than_5: assert final ($isunknown(nand_286) || nand_286) else $fatal(0, "Assertion failure via assert! @ xls/examples/assertions/assertions.x:21:12-21:40"); + __assertions__main_1_non_synth___assertions__main_non_synth___assertions__main_0_non_synth_non_synth___assertions__main___assertions__main_0___itok__assertions__main___itok__assertions__main_1___itok__assertions__func_0__32_x_less_than_5: assert final ($isunknown(nand_287) || nand_287) else $fatal(0, "Assertion failure via assert! @ xls/examples/assertions/assertions.x:21:12-21:40"); endmodule diff --git a/xls/dslx/run_routines/BUILD b/xls/dslx/run_routines/BUILD index 95c3c1d19a..93fa93fbeb 100644 --- a/xls/dslx/run_routines/BUILD +++ b/xls/dslx/run_routines/BUILD @@ -72,6 +72,8 @@ cc_library( "//xls/ir:value_utils", "//xls/passes", "//xls/passes:dce_pass", + "//xls/passes:dfe_pass", + "//xls/passes:inlining_pass", "//xls/passes:optimization_pass", "//xls/passes:optimization_pass_pipeline", "//xls/passes:pass_base", diff --git a/xls/dslx/run_routines/run_routines.cc b/xls/dslx/run_routines/run_routines.cc index 217dbbd1e7..8b717e9a9a 100644 --- a/xls/dslx/run_routines/run_routines.cc +++ b/xls/dslx/run_routines/run_routines.cc @@ -85,6 +85,8 @@ #include "xls/ir/value.h" #include "xls/ir/value_utils.h" #include "xls/passes/dce_pass.h" +#include "xls/passes/dfe_pass.h" +#include "xls/passes/inlining_pass.h" #include "xls/passes/optimization_pass.h" #include "xls/passes/optimization_pass_pipeline.h" #include "xls/passes/pass_base.h" @@ -805,9 +807,13 @@ absl::StatusOr ParseAndProve( // non-inlined function calls. auto pipeline = CreateOptimizationPassPipeline(); - // By the time this pass executes only the single top function is left. + // By the time this pass executes only the single top function is left (and + // non-synth function). // Strip any remaining asserts from it and 'and' them to the quickcheck // goal. + pipeline->Add(); + pipeline->Add(); + pipeline->Add(); pipeline->Add(); pipeline->Add(); PassResults results; diff --git a/xls/flows/BUILD b/xls/flows/BUILD index fe4985277c..3d12ba5c32 100644 --- a/xls/flows/BUILD +++ b/xls/flows/BUILD @@ -74,6 +74,7 @@ cc_test( "//xls/common:xls_gunit_main", "//xls/common/logging:log_lines", "//xls/common/status:matchers", + "//xls/dev_tools:remove_identifiers", "//xls/dslx:create_import_data", "//xls/dslx:default_dslx_stdlib_path", "//xls/dslx:import_data", diff --git a/xls/flows/ir_wrapper_test.cc b/xls/flows/ir_wrapper_test.cc index cf51bf2005..213f76a5f1 100644 --- a/xls/flows/ir_wrapper_test.cc +++ b/xls/flows/ir_wrapper_test.cc @@ -29,6 +29,7 @@ #include "xls/common/golden_files.h" #include "xls/common/logging/log_lines.h" #include "xls/common/status/matchers.h" +#include "xls/dev_tools/remove_identifiers.h" #include "xls/dslx/create_import_data.h" #include "xls/dslx/default_dslx_stdlib_path.h" #include "xls/dslx/frontend/module.h" @@ -50,19 +51,39 @@ namespace xls { namespace { -void ExpectVersionSpecificIr(std::string_view got, std::string_view test_name, +void ExpectVersionSpecificIr(Package* got, std::string_view test_name, bool proc_scoped_channels) { std::string test_name_without_param(test_name); RE2::GlobalReplace(&test_name_without_param, R"(/\d)", ""); + // Remove id numbers which can be very sensitive to minor pass pipeline + // changes + LOG(ERROR) << got->DumpIr(); + XLS_ASSERT_OK_AND_ASSIGN( + auto strip_pkg, + StripPackage(got, + StripOptions{.new_package_name = test_name_without_param, + .strip_location_info = false, + .strip_node_names = true, + .strip_function_names = false, + .strip_chan_names = false, + .strip_reg_names = false})); ExpectEqualToGoldenFile( absl::StrFormat("xls/flows/testdata/ir_wrapper_test_%s%s.ir", test_name_without_param, proc_scoped_channels ? "PSC" : ""), - got); + strip_pkg->DumpIr()); } -void ExpectIr(std::string_view got, std::string_view test_name) { - ExpectVersionSpecificIr(got, test_name, false); +void ExpectIrStr(std::string_view got, std::string_view test_name) { + std::string test_name_without_param(test_name); + RE2::GlobalReplace(&test_name_without_param, R"(/\d)", ""); + ExpectEqualToGoldenFile( + absl::StrFormat("xls/flows/testdata/ir_wrapper_test_%s.ir", + test_name_without_param), + got); +} +void ExpectIr(Package* p, std::string_view test_name) { + ExpectVersionSpecificIr(p, test_name, false); } std::string TestName() { @@ -128,10 +149,10 @@ pub fn GetLatency() -> s64 { ir_wrapper.GetIrFunction("GetLatency")); XLS_VLOG_LINES(3, get_latency->DumpIr()); - ExpectIr(get_latency->DumpIr(), TestName() + "_get_latency"); + ExpectIrStr(get_latency->DumpIr(), TestName() + "_get_latency"); XLS_ASSERT_OK_AND_ASSIGN(Package * package, ir_wrapper.GetIrPackage()); - ExpectIr(package->DumpIr(), TestName() + "_package"); + ExpectIr(package, TestName() + "_package"); // Test that that the jit for the function can be retrieved and run. XLS_ASSERT_OK_AND_ASSIGN( @@ -186,7 +207,7 @@ TEST_P(IrWrapperTest, DslxProcsToIrOk) { XLS_VLOG_LINES(3, top_proc->DumpIr()); XLS_ASSERT_OK_AND_ASSIGN(Package * package, ir_wrapper.GetIrPackage()); - ExpectVersionSpecificIr(package->DumpIr(), TestName(), GetParam()); + ExpectVersionSpecificIr(package, TestName(), GetParam()); // Test that that the jit for the proc can be retrieved and run. XLS_ASSERT_OK_AND_ASSIGN(SerialProcRuntime * proc_runtime, diff --git a/xls/flows/testdata/ir_wrapper_test_DslxProcsToIrOk.ir b/xls/flows/testdata/ir_wrapper_test_DslxProcsToIrOk.ir index 40189a1981..d6ad3dee34 100644 --- a/xls/flows/testdata/ir_wrapper_test_DslxProcsToIrOk.ir +++ b/xls/flows/testdata/ir_wrapper_test_DslxProcsToIrOk.ir @@ -1,4 +1,4 @@ -package test_package +package DslxProcsToIrOk file_number 0 "top_module.x" @@ -7,13 +7,13 @@ chan test_package__in_1(bits[32], id=1, kind=streaming, ops=receive_only, flow_c chan test_package__output(bits[32], id=2, kind=streaming, ops=send_only, flow_control=ready_valid, strictness=proven_mutually_exclusive) proc __top__foo_0_next() { - tok: token = after_all(id=4) - receive.18: (token, bits[32]) = receive(tok, channel=test_package__in_0, id=18) - tok__1: token = tuple_index(receive.18, index=0, id=7, pos=[(0,12,13)]) - receive.19: (token, bits[32]) = receive(tok__1, channel=test_package__in_1, id=19) - a: bits[32] = tuple_index(receive.18, index=1, id=8, pos=[(0,12,18)]) - b: bits[32] = tuple_index(receive.19, index=1, id=12, pos=[(0,13,18)]) - tok__2: token = tuple_index(receive.19, index=0, id=11, pos=[(0,13,13)]) - add.13: bits[32] = add(a, b, id=13, pos=[(0,14,36)]) - tok__3: token = send(tok__2, add.13, channel=test_package__output, id=20) + after_all.1: token = after_all(id=1) + receive.2: (token, bits[32]) = receive(after_all.1, channel=test_package__in_0, id=2) + tuple_index.3: token = tuple_index(receive.2, index=0, id=3, pos=[(0,12,13)]) + receive.4: (token, bits[32]) = receive(tuple_index.3, channel=test_package__in_1, id=4) + tuple_index.5: bits[32] = tuple_index(receive.2, index=1, id=5, pos=[(0,12,18)]) + tuple_index.6: bits[32] = tuple_index(receive.4, index=1, id=6, pos=[(0,13,18)]) + tuple_index.7: token = tuple_index(receive.4, index=0, id=7, pos=[(0,13,13)]) + add.8: bits[32] = add(tuple_index.5, tuple_index.6, id=8, pos=[(0,14,36)]) + send.9: token = send(tuple_index.7, add.8, channel=test_package__output, id=9) } diff --git a/xls/flows/testdata/ir_wrapper_test_DslxProcsToIrOkPSC.ir b/xls/flows/testdata/ir_wrapper_test_DslxProcsToIrOkPSC.ir index 8ce9c5c9ff..bd4f0cffad 100644 --- a/xls/flows/testdata/ir_wrapper_test_DslxProcsToIrOkPSC.ir +++ b/xls/flows/testdata/ir_wrapper_test_DslxProcsToIrOkPSC.ir @@ -1,4 +1,4 @@ -package test_package +package DslxProcsToIrOk file_number 0 "top_module.x" @@ -6,13 +6,13 @@ top proc __top__foo_0_next bits[64] { - ret params_latency: bits[64] = literal(value=7, id=3, pos=[(0,2,17)]) + ret literal.1: bits[64] = literal(value=7, id=1, pos=[(0,2,17)]) } diff --git a/xls/ir/channel.cc b/xls/ir/channel.cc index 5c615892e2..d73b2d82c2 100644 --- a/xls/ir/channel.cc +++ b/xls/ir/channel.cc @@ -354,9 +354,9 @@ std::ostream& operator<<(std::ostream& os, ChannelDirection direction) { } std::unique_ptr SendChannelInterface::Clone( - std::optional new_name) const { - auto clone = std::make_unique(new_name.value_or(name()), - type(), kind()); + std::optional new_name, Type* new_ty) const { + auto clone = std::make_unique( + new_name.value_or(name()), new_ty ? new_ty : type(), kind()); clone->SetKind(kind()); clone->SetStrictness(strictness()); clone->SetFlowControl(flow_control()); @@ -365,9 +365,9 @@ std::unique_ptr SendChannelInterface::Clone( } std::unique_ptr ReceiveChannelInterface::Clone( - std::optional new_name) const { + std::optional new_name, Type* new_ty) const { auto clone = std::make_unique( - new_name.value_or(name()), type(), kind()); + new_name.value_or(name()), new_ty ? new_ty : type(), kind()); clone->SetKind(kind()); clone->SetStrictness(strictness()); clone->SetFlowControl(flow_control()); diff --git a/xls/ir/channel.h b/xls/ir/channel.h index ff2d681d69..2018f73307 100644 --- a/xls/ir/channel.h +++ b/xls/ir/channel.h @@ -496,7 +496,8 @@ class SendChannelInterface : public ChannelInterface { : ChannelInterface(name, type, kind) {} ~SendChannelInterface() override = default; std::unique_ptr Clone( - std::optional new_name = std::nullopt) const; + std::optional new_name = std::nullopt, + Type* new_ty = nullptr) const; ChannelDirection direction() const override { return ChannelDirection::kSend; } @@ -509,7 +510,8 @@ class ReceiveChannelInterface : public ChannelInterface { : ChannelInterface(name, type, kind) {} ~ReceiveChannelInterface() override = default; std::unique_ptr Clone( - std::optional new_name = std::nullopt) const; + std::optional new_name = std::nullopt, + Type* new_ty = nullptr) const; ChannelDirection direction() const override { return ChannelDirection::kReceive; } diff --git a/xls/ir/proc.cc b/xls/ir/proc.cc index bb29c2ed06..5c1e5a0dd0 100644 --- a/xls/ir/proc.cc +++ b/xls/ir/proc.cc @@ -339,19 +339,24 @@ absl::StatusOr Proc::Clone( } if (is_new_style_proc()) { for (ChannelInterface* channel_interface : interface()) { + XLS_ASSIGN_OR_RETURN( + Type * new_ty, + target_package->MapTypeFromOtherPackage(channel_interface->type())); if (channel_interface->direction() == ChannelDirection::kSend) { XLS_RETURN_IF_ERROR( cloned_proc ->AddOutputChannelInterface( dynamic_cast(channel_interface) - ->Clone(new_chan_name(channel_interface->name()))) + ->Clone(new_chan_name(channel_interface->name()), + new_ty)) .status()); } else { XLS_RETURN_IF_ERROR( cloned_proc ->AddInputChannelInterface( dynamic_cast(channel_interface) - ->Clone(new_chan_name(channel_interface->name()))) + ->Clone(new_chan_name(channel_interface->name()), + new_ty)) .status()); } } @@ -394,7 +399,9 @@ absl::StatusOr Proc::Clone( XLS_ASSIGN_OR_RETURN( ChannelRef channel_ref, cloned_proc->GetChannelRef(channel, ChannelDirection::kReceive)); - Type* payload_type = ChannelRefType(channel_ref); + XLS_ASSIGN_OR_RETURN(Type * payload_type, + cloned_proc->package()->MapTypeFromOtherPackage( + ChannelRefType(channel_ref))); if (is_new_style_proc()) { XLS_ASSIGN_OR_RETURN( original_to_clone[node], diff --git a/xls/ir/proc_test.cc b/xls/ir/proc_test.cc index 6e12c1d2c1..3d57c0ec62 100644 --- a/xls/ir/proc_test.cc +++ b/xls/ir/proc_test.cc @@ -264,6 +264,56 @@ TEST_F(ProcTest, Clone) { )"); } +TEST_F(ProcTest, CloneProcScopedChannel) { + auto p = CreatePackage(); + + ProcBuilder pb(NewStyleProc(), "p", p.get()); + XLS_ASSERT_OK_AND_ASSIGN( + auto inp, pb.AddInputChannel("input_chan", p->GetBitsType(32), {})); + XLS_ASSERT_OK_AND_ASSIGN(auto out, + pb.AddOutputChannel("chan", p->GetBitsType(32), {})); + BValue tkn = pb.StateElement("tkn", Value::Token()); + BValue state = pb.StateElement("st", Value(UBits(42, 32))); + BValue recv = pb.Receive(inp, tkn); + BValue add1 = pb.Add(pb.Literal(UBits(1, 32)), state); + BValue add2 = pb.Add(add1, pb.TupleIndex(recv, 1)); + BValue send = pb.Send(out, pb.TupleIndex(recv, 0), add2); + XLS_ASSERT_OK_AND_ASSIGN(Proc * proc, pb.Build({send, add2})); + + auto p2 = CreatePackage(); + + XLS_ASSERT_OK_AND_ASSIGN( + Proc * clone, proc->Clone("cloned", p2.get(), + /*channel_remapping=*/{}, + /*call_remapping=*/{}, + /*state_name_remapping=*/{{"st", "state"}})); + + EXPECT_FALSE(clone->IsFunction()); + EXPECT_TRUE(clone->IsProc()); + + RecordProperty("p2", p2->DumpIr()); + + EXPECT_EQ(p2->DumpIr(), + R"IR(package CloneProcScopedChannel + +proc cloned(tkn: token, state: bits[32], init={token, 42}) { + chan_interface input_chan(direction=receive, kind=streaming, strictness=proven_mutually_exclusive, flow_control=ready_valid, flop_kind=none) + chan_interface chan(direction=send, kind=streaming, strictness=proven_mutually_exclusive, flow_control=ready_valid, flop_kind=none) + tkn: token = state_read(state_element=tkn, id=1) + literal.3: bits[32] = literal(value=1, id=3) + state: bits[32] = state_read(state_element=state, id=2) + receive_3: (token, bits[32]) = receive(tkn, channel=input_chan, id=4) + add.5: bits[32] = add(literal.3, state, id=5) + tuple_index.6: bits[32] = tuple_index(receive_3, index=1, id=6) + tuple_index.7: token = tuple_index(receive_3, index=0, id=7) + add.8: bits[32] = add(add.5, tuple_index.6, id=8) + send_9: token = send(tuple_index.7, add.8, channel=chan, id=9) + next_value.10: () = next_value(param=tkn, value=send_9, id=10) + next_value.11: () = next_value(param=state, value=add.8, id=11) +} +)IR"); +} + TEST_F(ProcTest, CloneNewStyle) { auto p = CreatePackage(); TokenlessProcBuilder pb(NewStyleProc(), "p", "tkn", p.get()); diff --git a/xls/passes/optimization_pass_pipeline.txtpb b/xls/passes/optimization_pass_pipeline.txtpb index c58980edfc..b88ff69c39 100644 --- a/xls/passes/optimization_pass_pipeline.txtpb +++ b/xls/passes/optimization_pass_pipeline.txtpb @@ -1,3 +1,4 @@ +# # Copyright 2025 The XLS Authors # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -190,6 +191,25 @@ compound_passes: [ fixedpoint: true comment: "Prepare proc state for further analysis by removing arrays and tuples." }, + { + long_name: "canonicalize proc state representation" + short_name: "canonicalize_proc_state" + passes: [ + # Flatten and optimize the proc state. Run tuple simplification to + # simplify tuple structures left over from flattening. + # TODO(meheff): Consider running proc state optimization more than once. + "fixedpoint_proc_state_flattening", + "proc_state_bits_shatter", + "proc_state_tuple_flat", + "ident_remove", + "dataflow", + "dce" + ] + comment: + "Bring proc-state representation to the canonical 'flat' representation" + "other passes expect." + fixedpoint: true + }, { long_name: "post-inlining optimization passes" short_name: "post-inlining-opt" @@ -200,6 +220,15 @@ compound_passes: [ # evidence that it is helpful for reducing memory usage, though, so we # still run it once here. "cond_spec(noBdd)", + # Separate out proc state then separate out non-synth stuff. + "canonicalize_proc_state", + "non_synth_separation", + "dce", + # Separate next values and do other simple optimization. + "next_value_opt", + "dce", + "fixedpoint_simp(2)", + # "dce", "bdd_simp(2)", "dce", @@ -240,13 +269,16 @@ compound_passes: [ # Flatten and optimize the proc state. Run tuple simplification to # simplify tuple structures left over from flattening. # TODO(meheff): Consider running proc state optimization more than once. - "fixedpoint_proc_state_flattening", - "proc_state_bits_shatter", - "proc_state_tuple_flat", - "ident_remove", - "dataflow", + # Separate out proc state then separate out non-synth stuff. + "canonicalize_proc_state", + "non_synth_separation", + "dce", + # Separate next values and do other simple optimization. "next_value_opt", "dce", + "fixedpoint_simp(2)", + # + "dce", # "proc_state_narrow", "dce", @@ -338,6 +370,13 @@ compound_passes: [ short_name: "scheduling-opt" passes: [ "fixedpoint_simp", + "dce", + # Undo non-synth separation. + "full-inlining", + "dce", + "dfe", + # Now that we can see more context actually remove dead asserts. + "useless_assert_remove", "dce" ] options: { @@ -353,11 +392,39 @@ compound_passes: [ "running optimization passes is an artifact of how these tools evolved " "which no longer makes too much sense. To do this will require making a " "decision on how to handle 'mutual-exclusion opt' however." + }, + { + long_name: "Prepare for scheduling optimization passes" + short_name: "prepare-for-scheduling" + passes: [ + # Undo non-synth separation. + "full-inlining", + "dce", + "dfe", + # TODO(allight): Unclear if fixedpoint simp is what we want to use here. + # This is mostly to clean up extraneous bit-slice/concats etc. + "fixedpoint_simp", + "dce" + ] + options: { + min_opt_level: 1 + } + comment: + "Passes performed at the very end of optimization.\n" + "\n" + "TODO(allight): We might want to move resource sharing into here for" + "organizational reasons.\n" + "\n" + "TODO(allight): The duplication between this and " + "[scheduling-opt](#scheduling-opt) is a massive code-smell. " + "Significant adjustments to codegen/sched pass pipelines are likely " + "required." } ] default_pipeline: [ "simplify-and-inline", - "post-inlining" + "post-inlining", + "prepare-for-scheduling" ] # LINT.End