Skip to content

Commit

Permalink
proc_rmdead: use explicit pattern set when there are no wildcards
Browse files Browse the repository at this point in the history
If width of a case expression was large, explicit patterns could cause
the existing logic to take an extremely long time, or exhaust the
maximum size of the underlying set. For cases where all of the patterns
are fully defined and there are no constants in the case expression,
this change uses a simple set to track which patterns have been seen.
  • Loading branch information
zachjs committed Jul 30, 2021
1 parent 4fec3a8 commit c016f6a
Show file tree
Hide file tree
Showing 4 changed files with 386 additions and 2 deletions.
65 changes: 63 additions & 2 deletions passes/proc/proc_rmdead.cc
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,62 @@
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

void proc_rmdead(RTLIL::SwitchRule *sw, int &counter, int &full_case_counter)
static bool can_use_fully_defined_pool(RTLIL::SwitchRule *sw)
{
if (!GetSize(sw->signal))
return false;

for (const RTLIL::SigBit &bit : sw->signal)
if (bit.wire == NULL)
return false;

for (const RTLIL::CaseRule *cas : sw->cases)
for (const RTLIL::SigSpec &sig : cas->compare)
if (!sig.is_fully_def())
return false;

return true;
}

// This replicates the necessary parts of BitPatternPool's interface, but rather
// than storing remaining patterns, this explicitly stores which fully-defined
// constants have already been matched.
struct FullyDefinedPool
{
FullyDefinedPool(const RTLIL::SigSpec &signal)
: max_patterns{signal.size() >= 32 ? 0ul : 1ul << signal.size()}
{}

bool take(RTLIL::SigSpec sig)
{
if (default_reached || patterns.count(sig))
return false;
patterns.insert(sig);
return true;
}

void take_all()
{
default_reached = true;
}

bool empty()
{
return default_reached ||
(max_patterns && max_patterns == patterns.size());
}

pool<RTLIL::SigSpec> patterns;
bool default_reached = false;
size_t max_patterns;
};

void proc_rmdead(RTLIL::SwitchRule *sw, int &counter, int &full_case_counter);

template <class Pool>
static void proc_rmdead_impl(RTLIL::SwitchRule *sw, int &counter, int &full_case_counter)
{
BitPatternPool pool(sw->signal);
Pool pool(sw->signal);

for (size_t i = 0; i < sw->cases.size(); i++)
{
Expand Down Expand Up @@ -68,6 +121,14 @@ void proc_rmdead(RTLIL::SwitchRule *sw, int &counter, int &full_case_counter)
}
}

void proc_rmdead(RTLIL::SwitchRule *sw, int &counter, int &full_case_counter)
{
if (can_use_fully_defined_pool(sw))
proc_rmdead_impl<FullyDefinedPool>(sw, counter, full_case_counter);
else
proc_rmdead_impl<BitPatternPool>(sw, counter, full_case_counter);
}

struct ProcRmdeadPass : public Pass {
ProcRmdeadPass() : Pass("proc_rmdead", "eliminate dead trees in decision trees") { }
void help() override
Expand Down
46 changes: 46 additions & 0 deletions tests/proc/rmdead.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
module top (
input wire signed x,
output reg [31:0] y
);
wire signed fail = ~x;

always @*
case (x)
1'b0: y = 0;
1'b1: y = 1;
default: y = fail;
endcase

always @*
case (x)
2'sb00: y = 0;
2'sb00: y = fail;
endcase

always @*
case (x)
2'sb00: y = 0;
default: y = fail;
2'sb01: y = 1;
2'sb10: y = 2;
2'sb11: y = 3;
2'sb00: y = fail;
2'sb01: y = fail;
2'sb10: y = fail;
2'sb11: y = fail;
endcase


always @*
case ({x, x})
2'b00: y = 0;
2'b01: y = 1;
2'b10: y = 2;
2'b11: y = 3;
default: y = fail;
2'b00: y = fail;
2'b01: y = fail;
2'b10: y = fail;
2'b11: y = fail;
endcase
endmodule
4 changes: 4 additions & 0 deletions tests/proc/rmdead.ys
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
read_verilog rmdead.v
proc
opt_clean
select -assert-count 0 w:fail
Loading

0 comments on commit c016f6a

Please sign in to comment.