diff --git a/dependency_support/llvm/workspace.bzl b/dependency_support/llvm/workspace.bzl index e5990d2fee..fe768c798b 100644 --- a/dependency_support/llvm/workspace.bzl +++ b/dependency_support/llvm/workspace.bzl @@ -20,8 +20,8 @@ load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe") def repo(): """Initialize the llvm-project repository.""" - LLVM_COMMIT = "14c00c05c13af8fa5c56852dce958b4259935fa8" - LLVM_SHA256 = "5831226924cd42e9fb535becd04ca7c2f2aa4049f2877b45c80248c6e1429477" + LLVM_COMMIT = "1e8f1749aa2717c9370da02a86779c52b4a2af16" + LLVM_SHA256 = "f3db10419deaf0f6cf8f2ac40dd435572cf508b87ccbb27d52b07957026c72bc" maybe( http_archive, diff --git a/xls/codegen_v_1_5/BUILD b/xls/codegen_v_1_5/BUILD index 2cceef3c91..5eb74e6a0f 100644 --- a/xls/codegen_v_1_5/BUILD +++ b/xls/codegen_v_1_5/BUILD @@ -41,15 +41,20 @@ cc_library( hdrs = ["block_conversion_pass_pipeline.h"], deps = [ ":block_conversion_pass", + ":block_conversion_wrapper_pass", ":block_finalization_pass", ":channel_to_port_io_lowering_pass", ":flow_control_insertion_pass", ":function_io_lowering_pass", ":idle_insertion_pass", ":pipeline_register_insertion_pass", + ":register_cleanup_pass", ":scheduled_block_conversion_pass", ":scheduling_pass", ":state_to_register_io_lowering_pass", + "//xls/passes:dataflow_simplification_pass", + "//xls/passes:dce_pass", + "//xls/passes:optimization_pass", ], ) @@ -93,6 +98,65 @@ cc_test( ], ) +cc_library( + name = "register_cleanup_pass", + srcs = ["register_cleanup_pass.cc"], + hdrs = ["register_cleanup_pass.h"], + deps = [ + ":block_conversion_pass", + "//xls/common/status:status_macros", + "//xls/data_structures:transitive_closure", + "//xls/ir", + "//xls/ir:register", + "//xls/ir:value", + "//xls/ir:value_utils", + "//xls/passes:node_dependency_analysis", + "//xls/passes:partial_info_query_engine", + "//xls/passes:pass_base", + "//xls/passes:query_engine", + "@com_google_absl//absl/algorithm:container", + "@com_google_absl//absl/container:flat_hash_map", + "@com_google_absl//absl/container:flat_hash_set", + "@com_google_absl//absl/status:statusor", + "@com_google_absl//absl/types:span", + ], +) + +cc_library( + name = "block_conversion_wrapper_pass", + srcs = ["block_conversion_wrapper_pass.cc"], + hdrs = ["block_conversion_wrapper_pass.h"], + deps = [ + ":block_conversion_pass", + "//xls/ir", + "//xls/passes:optimization_pass", + "//xls/passes:pass_base", + "@com_google_absl//absl/status:statusor", + "@com_google_absl//absl/strings:str_format", + "@com_google_absl//absl/types:span", + ], +) + +cc_test( + name = "block_conversion_wrapper_pass_test", + srcs = ["block_conversion_wrapper_pass_test.cc"], + deps = [ + ":block_conversion_pass", + ":block_conversion_wrapper_pass", + "//xls/common:xls_gunit_main", + "//xls/common/status:matchers", + "//xls/ir", + "//xls/ir:function_builder", + "//xls/ir:ir_matcher", + "//xls/ir:ir_test_base", + "//xls/passes:dce_pass", + "//xls/passes:optimization_pass", + "//xls/passes:pass_base", + "@com_google_absl//absl/status:statusor", + "@googletest//:gtest", + ], +) + cc_library( name = "channel_to_port_io_lowering_pass", srcs = ["channel_to_port_io_lowering_pass.cc"], @@ -170,6 +234,7 @@ cc_library( "//xls/common/status:status_macros", "//xls/estimators/delay_model:delay_estimator", "//xls/ir", + "//xls/passes:optimization_pass", "//xls/passes:pass_base", "//xls/scheduling:pipeline_schedule_cc_proto", "//xls/scheduling:scheduling_options", diff --git a/xls/codegen_v_1_5/block_conversion_pass_pipeline.cc b/xls/codegen_v_1_5/block_conversion_pass_pipeline.cc index ea3f42c842..52d6eaa968 100644 --- a/xls/codegen_v_1_5/block_conversion_pass_pipeline.cc +++ b/xls/codegen_v_1_5/block_conversion_pass_pipeline.cc @@ -20,20 +20,25 @@ #include #include "xls/codegen_v_1_5/block_conversion_pass.h" +#include "xls/codegen_v_1_5/block_conversion_wrapper_pass.h" #include "xls/codegen_v_1_5/block_finalization_pass.h" #include "xls/codegen_v_1_5/channel_to_port_io_lowering_pass.h" #include "xls/codegen_v_1_5/flow_control_insertion_pass.h" #include "xls/codegen_v_1_5/function_io_lowering_pass.h" #include "xls/codegen_v_1_5/idle_insertion_pass.h" #include "xls/codegen_v_1_5/pipeline_register_insertion_pass.h" +#include "xls/codegen_v_1_5/register_cleanup_pass.h" #include "xls/codegen_v_1_5/scheduled_block_conversion_pass.h" #include "xls/codegen_v_1_5/scheduling_pass.h" #include "xls/codegen_v_1_5/state_to_register_io_lowering_pass.h" +#include "xls/passes/dataflow_simplification_pass.h" +#include "xls/passes/dce_pass.h" +#include "xls/passes/optimization_pass.h" namespace xls::codegen { -std::unique_ptr -CreateBlockConversionPassPipeline() { +std::unique_ptr CreateBlockConversionPassPipeline( + OptimizationContext& opt_context) { auto top = std::make_unique( "block_conversion", "Top level codegen v1.5 block conversion pipeline"); @@ -64,6 +69,18 @@ CreateBlockConversionPassPipeline() { // Lower scheduled block to standard block, inlining each stage. top->Add(); + // Clean up unused registers & load-enable bits (including flow-control + // registers). + top->Add(); + + // Clean up unnecessary array/tuple manipulation. + top->Add( + std::make_unique(), opt_context); + + // Remove anything we created & then left dead. + top->Add( + std::make_unique(), opt_context); + return top; } diff --git a/xls/codegen_v_1_5/block_conversion_pass_pipeline.h b/xls/codegen_v_1_5/block_conversion_pass_pipeline.h index 7541593a34..37d20dcbeb 100644 --- a/xls/codegen_v_1_5/block_conversion_pass_pipeline.h +++ b/xls/codegen_v_1_5/block_conversion_pass_pipeline.h @@ -18,13 +18,14 @@ #include #include "xls/codegen_v_1_5/block_conversion_pass.h" +#include "xls/passes/optimization_pass.h" namespace xls::codegen { // Returns a pipeline which converts an unscheduled IR package into a standard // block. -std::unique_ptr -CreateBlockConversionPassPipeline(); +std::unique_ptr CreateBlockConversionPassPipeline( + OptimizationContext& opt_context); } // namespace xls::codegen diff --git a/xls/codegen_v_1_5/block_conversion_pass_pipeline_test.cc b/xls/codegen_v_1_5/block_conversion_pass_pipeline_test.cc index 5bff3c171c..12f7b3e567 100644 --- a/xls/codegen_v_1_5/block_conversion_pass_pipeline_test.cc +++ b/xls/codegen_v_1_5/block_conversion_pass_pipeline_test.cc @@ -54,7 +54,6 @@ #include "xls/common/status/matchers.h" #include "xls/common/status/ret_check.h" #include "xls/common/status/status_macros.h" -#include "xls/estimators/delay_model/delay_estimator.h" #include "xls/interpreter/block_evaluator.h" #include "xls/interpreter/block_interpreter.h" #include "xls/ir/bits.h" @@ -97,6 +96,7 @@ using ::testing::ElementsAre; using ::testing::Eq; using ::testing::Ge; using ::testing::HasSubstr; +using ::testing::IsEmpty; using ::testing::Optional; using ::testing::Pair; using ::testing::SizeIs; @@ -282,7 +282,7 @@ TEST_F(BlockConversionTest, SimpleFunction) { m::OutputPort("out", m::Add(m::InputPort("x"), m::InputPort("y")))); } -TEST_F(BlockConversionTest, DISABLED_SimpleFunctionWithNamedOutput) { +TEST_F(BlockConversionTest, SimpleFunctionWithNamedOutput) { auto p = CreatePackage(); FunctionBuilder fb(TestName(), p.get()); BValue x = fb.Param("x", p->GetBitsType(32)); @@ -331,7 +331,7 @@ TEST_F(BlockConversionTest, ZeroWidthInputsAndOutput) { EXPECT_EQ(block->GetPorts().size(), 4); } -TEST_F(BlockConversionTest, DISABLED_SimplePipelinedFunction) { +TEST_F(BlockConversionTest, SimplePipelinedFunction) { auto p = CreatePackage(); FunctionBuilder fb(TestName(), p.get()); BValue x = fb.Param("x", p->GetBitsType(32)); @@ -348,11 +348,13 @@ TEST_F(BlockConversionTest, DISABLED_SimplePipelinedFunction) { SchedulingOptions().pipeline_stages(3))); EXPECT_THAT(GetOutputPort(block), - m::OutputPort(m::Neg(m::Register(m::Not(m::Register( - m::Add(m::InputPort("x"), m::InputPort("y")))))))); + m::OutputPort(m::Neg(m::Register(m::Not( + m::Register(m::Add(m::InputPort("x"), m::InputPort("y")))))))) + << "\n\nIR:\n" + << block->DumpIr(); } -TEST_F(BlockConversionTest, DISABLED_TrivialPipelinedFunctionNoFlopping) { +TEST_F(BlockConversionTest, TrivialPipelinedFunctionNoFlopping) { auto p = CreatePackage(); FunctionBuilder fb(TestName(), p.get()); BValue x = fb.Param("x", p->GetBitsType(32)); @@ -373,7 +375,7 @@ TEST_F(BlockConversionTest, DISABLED_TrivialPipelinedFunctionNoFlopping) { m::Add(m::InputPort("x"), m::InputPort("y")))))))); } -TEST_F(BlockConversionTest, DISABLED_TrivialPipelinedFunctionFloppedInputs) { +TEST_F(BlockConversionTest, TrivialPipelinedFunctionFloppedInputs) { auto p = CreatePackage(); FunctionBuilder fb(TestName(), p.get()); BValue x = fb.Param("x", p->GetBitsType(32)); @@ -395,7 +397,7 @@ TEST_F(BlockConversionTest, DISABLED_TrivialPipelinedFunctionFloppedInputs) { m::Register(m::InputPort("x")), m::Register(m::InputPort("y"))))))))); } -TEST_F(BlockConversionTest, DISABLED_TrivialPipelinedFunctionFloppedOutputs) { +TEST_F(BlockConversionTest, TrivialPipelinedFunctionFloppedOutputs) { auto p = CreatePackage(); FunctionBuilder fb(TestName(), p.get()); BValue x = fb.Param("x", p->GetBitsType(32)); @@ -416,7 +418,7 @@ TEST_F(BlockConversionTest, DISABLED_TrivialPipelinedFunctionFloppedOutputs) { m::Add(m::InputPort("x"), m::InputPort("y"))))))))); } -TEST_F(BlockConversionTest, DISABLED_TrivialPipelinedFunctionFloppedIo) { +TEST_F(BlockConversionTest, TrivialPipelinedFunctionFloppedIo) { auto p = CreatePackage(); FunctionBuilder fb(TestName(), p.get()); BValue x = fb.Param("x", p->GetBitsType(32)); @@ -438,7 +440,7 @@ TEST_F(BlockConversionTest, DISABLED_TrivialPipelinedFunctionFloppedIo) { m::Register(m::InputPort("y")))))))))); } -TEST_F(BlockConversionTest, DISABLED_ZeroWidthPipeline) { +TEST_F(BlockConversionTest, ZeroWidthPipeline) { auto p = CreatePackage(); FunctionBuilder fb(TestName(), p.get()); BValue x = fb.Param("x", p->GetTupleType({})); @@ -454,7 +456,28 @@ TEST_F(BlockConversionTest, DISABLED_ZeroWidthPipeline) { "clk"), SchedulingOptions().pipeline_stages(3))); - EXPECT_EQ(block->GetRegisters().size(), 4); + EXPECT_THAT(block->GetRegisters(), IsEmpty()); +} + +TEST_F(BlockConversionTest, ZeroWidthPipelineWithValidControl) { + auto p = CreatePackage(); + FunctionBuilder fb(TestName(), p.get()); + BValue x = fb.Param("x", p->GetTupleType({})); + BValue y = fb.Param("y", p->GetBitsType(0)); + XLS_ASSERT_OK_AND_ASSIGN(Function * f, + fb.BuildWithReturnValue(fb.Tuple({x, y}))); + + XLS_ASSERT_OK_AND_ASSIGN( + Block * block, + ConvertToBlock(f, + CodegenOptions() + .flop_inputs(false) + .flop_outputs(false) + .clock_name("clk") + .valid_control("inputs_valid", "output_valid"), + SchedulingOptions().pipeline_stages(3))); + + EXPECT_THAT(block->GetRegisters(), SizeIs(2)); } // Verifies that an implicit token, as generated by the DSLX IR converter, is @@ -473,11 +496,10 @@ fn __itok__implicit_token__main(__token: token, __activated: bits[1]) -> fn __implicit_token__main() -> () { after_all.9: token = after_all(id=9) literal.10: bits[1] = literal(value=1, id=10) - invoke.11: (token, ()) = invoke(after_all.9, literal.10, - to_apply=__itok__implicit_token__main, id=11) tuple_index.12: token = - tuple_index(invoke.11, index=0, id=12) invoke.13: (token, ()) = - invoke(tuple_index.12, literal.10, to_apply=__itok__implicit_token__main, - id=13) ret tuple_index.14: () = tuple_index(invoke.13, index=1, id=14) + invoke.11: (token, ()) = invoke(after_all.9, literal.10, to_apply=__itok__implicit_token__main, id=11) + tuple_index.12: token = tuple_index(invoke.11, index=0, id=12) + invoke.13: (token, ()) = invoke(tuple_index.12, literal.10, to_apply=__itok__implicit_token__main, id=13) + ret tuple_index.14: () = tuple_index(invoke.13, index=1, id=14) } )"; XLS_ASSERT_OK_AND_ASSIGN(auto p, Parser::ParsePackage(kIrText)); @@ -489,7 +511,7 @@ fn __implicit_token__main() -> () { XLS_ASSERT_OK(VerifyBlock(block)); } -TEST_F(BlockConversionTest, DISABLED_SimpleProc) { +TEST_F(BlockConversionTest, SimpleProc) { const std::string ir_text = R"(package test chan in(bits[32], id=0, kind=single_value, ops=receive_only) @@ -513,7 +535,9 @@ proc my_proc(my_state: (), init={()}) { Block * block, ConvertToBlock(proc, codegen_options().generate_combinational(true))); EXPECT_THAT(FindNode("out", block), - m::OutputPort("out", m::Neg(m::InputPort("in")))); + m::OutputPort("out", m::Neg(m::InputPort("in")))) + << "\n\nIR:\n" + << block->DumpIr(); } TEST_F(BlockConversionTest, DISABLED_StreamingChannelMetadataForSimpleProc) { @@ -6394,7 +6418,7 @@ TEST_F(ProcConversionTestFixture, } } -TEST_F(ProcConversionTestFixture, DISABLED_SimpleFunctionWithProcsPresent) { +TEST_F(ProcConversionTestFixture, SimpleFunctionWithProcsPresent) { XLS_ASSERT_OK_AND_ASSIGN(std::unique_ptr p, CreateMultiProcPackage(/*with_functions=*/true)); XLS_ASSERT_OK_AND_ASSIGN(Function * f0, p->GetFunction("f0")); diff --git a/xls/codegen_v_1_5/block_conversion_wrapper_pass.cc b/xls/codegen_v_1_5/block_conversion_wrapper_pass.cc new file mode 100644 index 0000000000..a3ce2b6054 --- /dev/null +++ b/xls/codegen_v_1_5/block_conversion_wrapper_pass.cc @@ -0,0 +1,32 @@ +// Copyright 2021 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. + +#include "xls/codegen_v_1_5/block_conversion_wrapper_pass.h" + +#include "absl/status/statusor.h" +#include "xls/codegen_v_1_5/block_conversion_pass.h" +#include "xls/ir/package.h" +#include "xls/passes/optimization_pass.h" +#include "xls/passes/pass_base.h" + +namespace xls::codegen { + +absl::StatusOr BlockConversionWrapperPass::RunInternal( + Package* package, const BlockConversionPassOptions& options, + PassResults* results) const { + return wrapped_pass_->Run(package, OptimizationPassOptions(options), results, + opt_context_); +} + +} // namespace xls::codegen diff --git a/xls/codegen_v_1_5/block_conversion_wrapper_pass.h b/xls/codegen_v_1_5/block_conversion_wrapper_pass.h new file mode 100644 index 0000000000..caa9025638 --- /dev/null +++ b/xls/codegen_v_1_5/block_conversion_wrapper_pass.h @@ -0,0 +1,74 @@ +// Copyright 2021 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. + +#ifndef XLS_CODEGEN_V_1_5_BLOCK_CONVERSION_WRAPPER_PASS_H_ +#define XLS_CODEGEN_V_1_5_BLOCK_CONVERSION_WRAPPER_PASS_H_ + +#include +#include + +#include "absl/status/statusor.h" +#include "absl/strings/str_format.h" +#include "absl/types/span.h" +#include "xls/codegen_v_1_5/block_conversion_pass.h" +#include "xls/ir/package.h" +#include "xls/passes/optimization_pass.h" +#include "xls/passes/pass_base.h" + +namespace xls::codegen { + +// A codegen pass wrapper which wraps a OptimizationFunctionBasePass. This is +// useful for adding an optimization or transformation pass (most passes in +// xls/passes are OptimizationFunctionBasePasses) to the codegen pipeline. The +// wrapped pass is run on the block being lowered to Verilog. +// +// Takes the OptimizationContext object at construction, since it's specific to +// optimization passes & cannot be passed via a codegen pass's Run function. +class BlockConversionWrapperPass : public BlockConversionPass { + public: + explicit BlockConversionWrapperPass( + std::unique_ptr wrapped_pass, + OptimizationContext& opt_context) + : BlockConversionPass( + absl::StrFormat("codegen_%s", wrapped_pass->short_name()), + absl::StrFormat("%s (codegen)", wrapped_pass->long_name())), + wrapped_pass_(std::move(wrapped_pass)), + opt_context_(opt_context) {} + ~BlockConversionWrapperPass() override = default; + + bool IsCompound() const override { return wrapped_pass_->IsCompound(); } + + absl::StatusOr RunInternal(Package* package, + const BlockConversionPassOptions& options, + PassResults* results) const final; + + absl::StatusOr RunNested(Package* package, + const BlockConversionPassOptions& options, + PassResults* results, + PassInvocation& invocation, + absl::Span + invariant_checkers) const override { + return wrapped_pass_->RunNested(package, OptimizationPassOptions(options), + results, opt_context_, invocation, + /*invariant_checkers=*/{}); + } + + private: + std::unique_ptr wrapped_pass_; + OptimizationContext& opt_context_; +}; + +} // namespace xls::codegen + +#endif // XLS_CODEGEN_V_1_5_BLOCK_CONVERSION_WRAPPER_PASS_H_ diff --git a/xls/codegen_v_1_5/block_conversion_wrapper_pass_test.cc b/xls/codegen_v_1_5/block_conversion_wrapper_pass_test.cc new file mode 100644 index 0000000000..45600011a9 --- /dev/null +++ b/xls/codegen_v_1_5/block_conversion_wrapper_pass_test.cc @@ -0,0 +1,76 @@ +// Copyright 2021 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. + +#include "xls/codegen_v_1_5/block_conversion_wrapper_pass.h" + +#include + +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "absl/status/statusor.h" +#include "xls/codegen_v_1_5/block_conversion_pass.h" +#include "xls/common/status/matchers.h" +#include "xls/ir/block.h" +#include "xls/ir/function_builder.h" +#include "xls/ir/ir_matcher.h" +#include "xls/ir/ir_test_base.h" +#include "xls/passes/dce_pass.h" +#include "xls/passes/optimization_pass.h" +#include "xls/passes/pass_base.h" + +namespace m = ::xls::op_matchers; + +namespace xls::codegen { +namespace { + +using ::absl_testing::IsOkAndHolds; + +class BlockConversionWrapperPassTest : public IrTestBase { + protected: + absl::StatusOr Run(Block* block) { + PassResults results; + OptimizationContext optimization_context; + return BlockConversionWrapperPass( + std::make_unique(), + optimization_context) + .Run(block->package(), BlockConversionPassOptions(), &results); + } +}; + +TEST_F(BlockConversionWrapperPassTest, WrappedDce) { + auto p = CreatePackage(); + + BlockBuilder bb(TestName(), p.get()); + XLS_ASSERT_OK(bb.block()->AddClockPort("clk")); + BValue a = bb.InputPort("a", p->GetBitsType(32)); + BValue b = bb.InputPort("b", p->GetBitsType(32)); + bb.Add(a, b); + bb.OutputPort("c", bb.Subtract(a, b)); + XLS_ASSERT_OK_AND_ASSIGN(Block * block, bb.Build()); + + // The add should be eliminated. + EXPECT_EQ(block->node_count(), 5); + EXPECT_THAT(Run(block), IsOkAndHolds(true)); + EXPECT_EQ(block->node_count(), 4); + + EXPECT_THAT(FindNode("c", block), + m::OutputPort(m::Sub(m::InputPort("a"), m::InputPort("b")))); + + // Pass should be idempotent. + EXPECT_THAT(Run(block), IsOkAndHolds(false)); + EXPECT_EQ(block->node_count(), 4); +} + +} // namespace +} // namespace xls::codegen diff --git a/xls/codegen_v_1_5/channel_to_port_io_lowering_pass.cc b/xls/codegen_v_1_5/channel_to_port_io_lowering_pass.cc index 243894a632..e6c66e1cc2 100644 --- a/xls/codegen_v_1_5/channel_to_port_io_lowering_pass.cc +++ b/xls/codegen_v_1_5/channel_to_port_io_lowering_pass.cc @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -641,6 +642,7 @@ absl::Status ConnectReceivesToConnector( Stage& stage = block->stages()[stage_index]; Node* token = receive->As()->token(); std::optional predicate = receive->As()->predicate(); + bool is_blocking = receive->As()->is_blocking(); if (connector.ready.has_value()) { // The ready signal from this receive is: @@ -679,11 +681,54 @@ absl::Status ConnectReceivesToConnector( .status()); } - XLS_RETURN_IF_ERROR( - receive - ->ReplaceUsesWithNewInStage( - stage_index, absl::MakeConstSpan({token, connector.data})) - .status()); + Node* data = connector.data; + if (options.codegen_options.gate_recvs()) { + std::vector gate_conditions; + gate_conditions.reserve(2); + if (predicate.has_value()) { + gate_conditions.push_back(*predicate); + } + if (!is_blocking && connector.valid.has_value()) { + gate_conditions.push_back(*connector.valid); + } + + Node* gate_condition = nullptr; + if (gate_conditions.size() == 1) { + gate_condition = gate_conditions.front(); + } else if (gate_conditions.size() > 1) { + XLS_ASSIGN_OR_RETURN(gate_condition, block->MakeNodeInStage( + stage_index, receive->loc(), + gate_conditions, Op::kAnd)); + } + + if (gate_condition != nullptr) { + XLS_ASSIGN_OR_RETURN(Node * zero, + block->MakeNodeInStage( + stage_index, receive->loc(), + ZeroOfType(connector.data->GetType()))); + XLS_ASSIGN_OR_RETURN(data, + block->MakeNodeInStage