Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wreduce: Optimize signedness when possible #4819

Merged
merged 2 commits into from
Jan 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions passes/opt/wreduce.cc
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,19 @@ struct WreduceWorker
}
}

int reduced_opsize(const SigSpec &inp, bool signed_)
{
int size = GetSize(inp);
if (signed_) {
while (size >= 2 && inp[size - 1] == inp[size - 2])
size--;
} else {
while (size >= 1 && inp[size - 1] == State::S0)
size--;
}
return size;
}

void run_cell(Cell *cell)
{
bool did_something = false;
Expand Down Expand Up @@ -295,6 +308,45 @@ struct WreduceWorker
bool port_a_signed = false;
bool port_b_signed = false;

// For some operations if the output is no wider than either of the inputs
// we are free to choose the signedness of the operands
if (cell->type.in(ID($mul), ID($add), ID($sub)) &&
max_port_a_size == GetSize(sig) &&
max_port_b_size == GetSize(sig)) {
SigSpec sig_a = mi.sigmap(cell->getPort(ID::A)), sig_b = mi.sigmap(cell->getPort(ID::B));

// Remove top bits from sig_a and sig_b which are not visible on the output
sig_a.extend_u0(max_port_a_size);
sig_b.extend_u0(max_port_b_size);

int signed_cost, unsigned_cost;
if (cell->type == ID($mul)) {
signed_cost = reduced_opsize(sig_a, true) * reduced_opsize(sig_b, true);
unsigned_cost = reduced_opsize(sig_a, false) * reduced_opsize(sig_b, false);
} else {
signed_cost = max(reduced_opsize(sig_a, true), reduced_opsize(sig_b, true));
unsigned_cost = max(reduced_opsize(sig_a, false), reduced_opsize(sig_b, false));
}

if (!port_a_signed && !port_b_signed && signed_cost < unsigned_cost) {
log("Converting cell %s.%s (%s) from unsigned to signed.\n",
log_id(module), log_id(cell), log_id(cell->type));
cell->setParam(ID::A_SIGNED, 1);
cell->setParam(ID::B_SIGNED, 1);
port_a_signed = true;
port_b_signed = true;
did_something = true;
} else if (port_a_signed && port_b_signed && unsigned_cost < signed_cost) {
log("Converting cell %s.%s (%s) from signed to unsigned.\n",
log_id(module), log_id(cell), log_id(cell->type));
cell->setParam(ID::A_SIGNED, 0);
cell->setParam(ID::B_SIGNED, 0);
port_a_signed = false;
port_b_signed = false;
did_something = true;
}
}

if (max_port_a_size >= 0 && cell->type != ID($shiftx))
run_reduce_inport(cell, 'A', max_port_a_size, port_a_signed, did_something);

Expand Down
22 changes: 22 additions & 0 deletions tests/various/wreduce2.ys
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
read_verilog <<EOF
module top(a, b, y);
parameter awidth = 6;
parameter bwidth = 8;
parameter ywidth = 14;

input [awidth-1:0] a;
input [bwidth-1:0] b;
output [ywidth-1:0] y;

wire [ywidth-1:0] aext = {{(ywidth-awidth){a[awidth-1]}}, a};
wire [ywidth-1:0] bext = {{(ywidth-bwidth){b[bwidth-1]}}, b};

assign y = aext*bext;
endmodule
EOF

opt_clean
wreduce
select -assert-count 1 t:$mul
select -assert-count 1 t:$mul r:A_SIGNED=1 r:B_SIGNED=1 %i %i
select -assert-count 1 t:$mul r:A_WIDTH=6 r:B_WIDTH=8 %i %i
Loading