Skip to content

Commit 2ae55db

Browse files
ericastorcopybara-github
authored andcommitted
[codegen 1.5] Make channel lowering respect placeholders
Our node utility function ReplaceWithAnd previously unconditionally dropped all-ones literals - which caused some substantial errors in context of Codegen 1.5's use of literals as placeholders. We instead explicitly block this behavior, while still leaving the utility functions fully flexible for convenience. While we're at it, we upgrade the utility functions to be able to combine arbitrary literals into a single literal when requested. PiperOrigin-RevId: 851840930
1 parent 86836a9 commit 2ae55db

File tree

6 files changed

+204
-79
lines changed

6 files changed

+204
-79
lines changed

xls/codegen_v_1_5/BUILD

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,9 +321,9 @@ cc_library(
321321
"//xls/common/status:ret_check",
322322
"//xls/common/status:status_macros",
323323
"//xls/ir",
324+
"//xls/ir:node_util",
324325
"//xls/ir:op",
325326
"//xls/ir:register",
326-
"//xls/ir:value",
327327
"//xls/ir:value_utils",
328328
"//xls/passes:pass_base",
329329
"@com_google_absl//absl/algorithm:container",

xls/codegen_v_1_5/block_conversion_pass_pipeline_test.cc

Lines changed: 83 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -732,7 +732,7 @@ TEST_F(BlockConversionTest, ProcWithVariousNextStateNodes) {
732732
IsOkAndHolds(ElementsAre(10, 20, 30)));
733733
}
734734

735-
TEST_F(BlockConversionTest, DISABLED_ProcWithNextStateNodeBeforeParam) {
735+
TEST_F(BlockConversionTest, ProcWithNextStateNodeBeforeParam) {
736736
// A block with the next-state node scheduled before the param.
737737
auto p = CreatePackage();
738738
Type* u32 = p->GetBitsType(32);
@@ -1077,10 +1077,12 @@ proc my_proc(st: (), init={()}) {
10771077
EXPECT_THAT(FindNode("in_vld", block), m::InputPort("in_vld"));
10781078
EXPECT_THAT(
10791079
FindNode("in_rdy", block),
1080-
m::OutputPort("in_rdy",
1081-
m::And(m::And(m::Literal(1), m::Or(m::InputPort("in_vld"),
1082-
m::Not(m::Literal(1)))),
1083-
m::Literal(1), m::Literal(1))));
1080+
m::OutputPort(
1081+
"in_rdy",
1082+
m::And(m::And(m::Literal(1),
1083+
m::And(m::Literal(1), m::Or(m::InputPort("in_vld"),
1084+
m::Not(m::Literal(1))))),
1085+
m::Literal(1), m::Literal(1))));
10841086
}
10851087

10861088
TEST_F(BlockConversionTest, OnlyFIFOInProcGateRecvsFalse) {
@@ -1113,10 +1115,12 @@ proc my_proc(st: (), init={()}) {
11131115
EXPECT_THAT(FindNode("in_vld", block), m::InputPort("in_vld"));
11141116
EXPECT_THAT(
11151117
FindNode("in_rdy", block),
1116-
m::OutputPort("in_rdy",
1117-
m::And(m::And(m::Literal(1), m::Or(m::InputPort("in_vld"),
1118-
m::Not(m::Literal(1)))),
1119-
m::Literal(1), m::Literal(1))));
1118+
m::OutputPort(
1119+
"in_rdy",
1120+
m::And(m::And(m::Literal(1),
1121+
m::And(m::Literal(1), m::Or(m::InputPort("in_vld"),
1122+
m::Not(m::Literal(1))))),
1123+
m::Literal(1), m::Literal(1))));
11201124
}
11211125

11221126
TEST_F(BlockConversionTest, UnconditionalSendRdyVldProc) {
@@ -1569,7 +1573,7 @@ TEST_F(BlockConversionTest, OneToTwoProc) {
15691573
block,
15701574
{{"dir", 1}, {"in", 123}, {"in_vld", 0}, {"a_rdy", 1}, {"b_rdy", 1}}),
15711575
IsOkAndHolds(UnorderedElementsAre(Pair("a", 123), Pair("b_vld", 0),
1572-
Pair("in_rdy", 1), Pair("a_vld", 0),
1576+
Pair("in_rdy", 0), Pair("a_vld", 0),
15731577
Pair("b", 123))));
15741578

15751579
// Output A selected. Input valid and output ready *not* asserted.
@@ -2541,7 +2545,7 @@ class MultiInputPipelinedProcTestSweepFixture
25412545
}
25422546
};
25432547

2544-
TEST_P(MultiInputPipelinedProcTestSweepFixture, DISABLED_RandomStalling) {
2548+
TEST_P(MultiInputPipelinedProcTestSweepFixture, RandomStalling) {
25452549
int64_t stage_count = std::get<0>(GetParam());
25462550
bool flop_inputs = std::get<1>(GetParam());
25472551
bool flop_outputs = std::get<2>(GetParam());
@@ -3290,8 +3294,7 @@ class MultiInputWithStatePipelinedProcTestSweepFixture
32903294
}
32913295
};
32923296

3293-
TEST_P(MultiInputWithStatePipelinedProcTestSweepFixture,
3294-
DISABLED_RandomStalling) {
3297+
TEST_P(MultiInputWithStatePipelinedProcTestSweepFixture, RandomStalling) {
32953298
int64_t stage_count = std::get<0>(GetParam());
32963299
bool flop_inputs = std::get<1>(GetParam());
32973300
bool flop_outputs = std::get<2>(GetParam());
@@ -3893,7 +3896,72 @@ proc pipelined_proc(tkn: token, st: bits[32], init={token, 1}) {
38933896
IsOkAndHolds(testing::ElementsAreArray(expected_output)));
38943897
}
38953898

3896-
TEST_F(ProcConversionTestFixture, DISABLED_ProcIIGreaterThanOne) {
3899+
TEST_F(ProcConversionTestFixture, SimpleProcIIGreaterThanOne) {
3900+
const std::string ir_text = R"(package test
3901+
chan in(bits[32], id=0, kind=streaming, ops=receive_only, flow_control=ready_valid)
3902+
chan out(bits[32], id=1, kind=streaming, ops=send_only, flow_control=ready_valid)
3903+
3904+
#[initiation_interval(2)]
3905+
proc pipelined_proc(tkn: token, st: bits[32], init={token, 0}) {
3906+
send.1: token = send(tkn, st, channel=out, id=1)
3907+
min_delay.2: token = min_delay(send.1, delay=1, id=2)
3908+
receive.3: (token, bits[32]) = receive(min_delay.2, channel=in, id=3)
3909+
tuple_index.4: token = tuple_index(receive.3, index=0, id=4)
3910+
tuple_index.5: bits[32] = tuple_index(receive.3, index=1, id=5)
3911+
next_st: () = next_value(param=st, value=tuple_index.5)
3912+
next_tkn: () = next_value(param=tkn, value=tuple_index.4)
3913+
}
3914+
)";
3915+
3916+
XLS_ASSERT_OK_AND_ASSIGN(std::unique_ptr<Package> package,
3917+
Parser::ParsePackage(ir_text));
3918+
3919+
XLS_ASSERT_OK_AND_ASSIGN(Proc * proc, package->GetProc("pipelined_proc"));
3920+
3921+
CodegenOptions options;
3922+
options.flop_inputs(false).flop_outputs(false).clock_name("clk");
3923+
options.valid_control("input_valid", "output_valid");
3924+
options.reset("rst", false, false, true);
3925+
options.streaming_channel_data_suffix("_data");
3926+
options.streaming_channel_valid_suffix("_valid");
3927+
options.streaming_channel_ready_suffix("_ready");
3928+
options.module_name("pipelined_proc");
3929+
3930+
XLS_ASSERT_OK_AND_ASSIGN(
3931+
Block * block,
3932+
ConvertToBlock(proc, options, SchedulingOptions().pipeline_stages(3)));
3933+
3934+
std::vector<ChannelSource> sources{
3935+
ChannelSource("in_data", "in_valid", "in_ready", 1.0, block),
3936+
};
3937+
XLS_ASSERT_OK(sources.front().SetDataSequence({10, 20, 30}));
3938+
std::vector<ChannelSink> sinks{
3939+
ChannelSink(
3940+
"out_data", "out_valid", "out_ready", 1.0, block,
3941+
/*reset_behavior=*/ChannelSink::BehaviorDuringReset::kIgnoreValid),
3942+
};
3943+
3944+
std::string reset_name = options.reset()->name();
3945+
uint64_t reset_active = options.reset()->active_low() ? 0 : 1;
3946+
uint64_t reset_inactive = options.reset()->active_low() ? 1 : 0;
3947+
std::vector<absl::flat_hash_map<std::string, uint64_t>> inputs(
3948+
20, {{reset_name, reset_inactive}});
3949+
XLS_ASSERT_OK(
3950+
SetSignalsOverCycles(0, 9, {{reset_name, reset_active}}, inputs));
3951+
XLS_ASSERT_OK_AND_ASSIGN(BlockIOResultsAsUint64 results,
3952+
InterpretChannelizedSequentialBlockWithUint64(
3953+
block, absl::MakeSpan(sources),
3954+
absl::MakeSpan(sinks), inputs, options.reset()));
3955+
EXPECT_THAT(
3956+
sinks.at(0).GetOutputCycleSequenceAsUint64(),
3957+
IsOkAndHolds(Skipping(
3958+
10, ElementsAre(0, std::nullopt, 10, std::nullopt, 20, std::nullopt,
3959+
30, std::nullopt, std::nullopt, std::nullopt))));
3960+
EXPECT_THAT(sinks.at(0).GetOutputSequenceAsUint64(),
3961+
IsOkAndHolds(ElementsAre(0, 10, 20, 30)));
3962+
}
3963+
3964+
TEST_F(ProcConversionTestFixture, ProcIIGreaterThanOne) {
38973965
const std::string ir_text = R"(package test
38983966
chan in(bits[32], id=0, kind=streaming, ops=receive_only, flow_control=ready_valid)
38993967
chan out(bits[32], id=1, kind=streaming, ops=send_only, flow_control=ready_valid)
@@ -3959,18 +4027,11 @@ proc pipelined_proc(tkn: token, st: bits[32], init={token, 0}) {
39594027
IsOkAndHolds(Skipping(
39604028
10, ElementsAre(0, std::nullopt, 10, std::nullopt, 20, std::nullopt,
39614029
30, std::nullopt, std::nullopt, std::nullopt))));
3962-
EXPECT_THAT(sinks.at(1).GetOutputCycleSequenceAsUint64(),
3963-
IsOkAndHolds(Skipping(
3964-
10, ElementsAre(std::nullopt, 10, std::nullopt, 20,
3965-
std::nullopt, 30, std::nullopt, std::nullopt,
3966-
std::nullopt, std::nullopt))));
39674030
EXPECT_THAT(sinks.at(0).GetOutputSequenceAsUint64(),
39684031
IsOkAndHolds(ElementsAre(0, 10, 20, 30)));
3969-
EXPECT_THAT(sinks.at(1).GetOutputSequenceAsUint64(),
3970-
IsOkAndHolds(ElementsAre(10, 20, 30)));
39714032
}
39724033

3973-
TEST_F(ProcConversionTestFixture, DISABLED_ProcIIGreaterThanOneRandomStalls) {
4034+
TEST_F(ProcConversionTestFixture, ProcIIGreaterThanOneRandomStalls) {
39744035
const std::string ir_text = R"(package test
39754036
chan in(bits[32], id=0, kind=streaming, ops=receive_only, flow_control=ready_valid)
39764037
chan out(bits[32], id=1, kind=streaming, ops=send_only, flow_control=ready_valid)

xls/codegen_v_1_5/channel_to_port_io_lowering_pass.cc

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -707,9 +707,11 @@ absl::Status ConnectReceivesToConnector(
707707
absl::MakeConstSpan({*connector.valid, recv_inactive}),
708708
Op::kOr));
709709
}
710-
XLS_RETURN_IF_ERROR(
711-
ReplaceWithAnd(stage.active_inputs_valid(), recv_valid_or_inactive)
712-
.status());
710+
711+
XLS_RETURN_IF_ERROR(ReplaceWithAnd(stage.active_inputs_valid(),
712+
recv_valid_or_inactive,
713+
/*combine_literals=*/false)
714+
.status());
713715
}
714716

715717
Node* data = connector.data;
@@ -763,13 +765,10 @@ absl::Status ConnectReceivesToConnector(
763765
XLS_RETURN_IF_ERROR(block->RemoveNode(receive));
764766
}
765767
if (connector.ready.has_value()) {
766-
if (ready_signals.size() == 1) {
767-
XLS_RETURN_IF_ERROR(connector.ReplaceReadySignal(ready_signals.front()));
768-
} else {
769-
XLS_ASSIGN_OR_RETURN(Node * ready_signal,
770-
JoinWithOr(block, ready_signals));
771-
XLS_RETURN_IF_ERROR(connector.ReplaceReadySignal(ready_signal));
772-
}
768+
XLS_ASSIGN_OR_RETURN(
769+
Node * ready_signal,
770+
JoinWithOr(block, ready_signals, /*combine_literals=*/false));
771+
XLS_RETURN_IF_ERROR(connector.ReplaceReadySignal(ready_signal));
773772
}
774773

775774
return absl::OkStatus();
@@ -850,9 +849,17 @@ absl::Status ConnectSendsToConnector(
850849
absl::MakeConstSpan({*connector.ready, send_inactive}),
851850
Op::kOr));
852851
}
853-
XLS_RETURN_IF_ERROR(
854-
ReplaceWithAnd(stage.outputs_valid(), send_done_or_inactive)
855-
.status());
852+
853+
if (stage.outputs_valid()->Is<Literal>() &&
854+
stage.outputs_valid()->As<Literal>()->value().IsAllOnes()) {
855+
XLS_RETURN_IF_ERROR(
856+
stage.outputs_valid()->ReplaceUsesWith(send_done_or_inactive));
857+
} else {
858+
XLS_RETURN_IF_ERROR(ReplaceWithAnd(stage.outputs_valid(),
859+
send_done_or_inactive,
860+
/*combine_literals=*/false)
861+
.status());
862+
}
856863
}
857864

858865
if (connector.valid.has_value()) {

xls/codegen_v_1_5/function_io_lowering_pass.cc

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -35,32 +35,17 @@
3535
#include "xls/ir/block.h"
3636
#include "xls/ir/function_base.h"
3737
#include "xls/ir/node.h"
38+
#include "xls/ir/node_util.h"
3839
#include "xls/ir/nodes.h"
3940
#include "xls/ir/op.h"
4041
#include "xls/ir/package.h"
4142
#include "xls/ir/register.h"
42-
#include "xls/ir/value.h"
4343
#include "xls/ir/value_utils.h"
4444
#include "xls/passes/pass_base.h"
4545

4646
namespace xls::codegen {
4747
namespace {
4848

49-
absl::StatusOr<Node*> ReplaceWithAnd(Node* original, Node* new_operand) {
50-
if (original->Is<Literal>() && original->As<Literal>()->value().IsAllOnes()) {
51-
XLS_RETURN_IF_ERROR(original->ReplaceUsesWith(new_operand));
52-
return new_operand;
53-
}
54-
if (original->Is<NaryOp>() && original->As<NaryOp>()->op() == Op::kAnd) {
55-
std::vector<Node*> operands(original->operands().begin(),
56-
original->operands().end());
57-
operands.push_back(new_operand);
58-
return original->ReplaceUsesWithNew<NaryOp>(operands, Op::kAnd);
59-
}
60-
return original->ReplaceUsesWithNew<NaryOp>(
61-
absl::MakeConstSpan({original, new_operand}), Op::kAnd);
62-
}
63-
6449
absl::StatusOr<Node*> FlopNode(
6550
ScheduledBlock* block, std::string_view name, Node* input,
6651
int64_t stage_index, std::optional<Node*> load_enable = std::nullopt) {
@@ -119,9 +104,9 @@ absl::StatusOr<bool> FunctionIOLoweringPass::LowerParams(
119104
// which will stop the pipeline from running new activations when the input
120105
// is invalid. This also automatically propagates validity to the output in
121106
// case an output-valid signal was requested.
122-
XLS_RETURN_IF_ERROR(
123-
ReplaceWithAnd(block->stages()[0].active_inputs_valid(), *input_valid)
124-
.status());
107+
XLS_RETURN_IF_ERROR(ReplaceWithAnd(block->stages()[0].active_inputs_valid(),
108+
*input_valid, /*combine_literals=*/false)
109+
.status());
125110
}
126111

127112
std::vector<Param*> params_to_remove;

0 commit comments

Comments
 (0)