mirror of https://github.com/YosysHQ/yosys.git
wreduce: Optimize signedness when possible
This commit is contained in:
parent
4581f75b03
commit
08778917db
|
@ -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)
|
void run_cell(Cell *cell)
|
||||||
{
|
{
|
||||||
bool did_something = false;
|
bool did_something = false;
|
||||||
|
@ -295,6 +308,44 @@ struct WreduceWorker
|
||||||
bool port_a_signed = false;
|
bool port_a_signed = false;
|
||||||
bool port_b_signed = false;
|
bool port_b_signed = false;
|
||||||
|
|
||||||
|
// Under certain conditions 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_size, unsigned_size;
|
||||||
|
if (cell->type == ID($mul)) {
|
||||||
|
signed_size = reduced_opsize(sig_a, true) * reduced_opsize(sig_b, true);
|
||||||
|
unsigned_size = reduced_opsize(sig_a, false) * reduced_opsize(sig_b, false);
|
||||||
|
} else {
|
||||||
|
signed_size = max(reduced_opsize(sig_a, true), reduced_opsize(sig_b, true));
|
||||||
|
unsigned_size = max(reduced_opsize(sig_a, false), reduced_opsize(sig_b, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!port_a_signed && !port_b_signed && signed_size < unsigned_size) {
|
||||||
|
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_size < signed_size) {
|
||||||
|
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))
|
if (max_port_a_size >= 0 && cell->type != ID($shiftx))
|
||||||
run_reduce_inport(cell, 'A', max_port_a_size, port_a_signed, did_something);
|
run_reduce_inport(cell, 'A', max_port_a_size, port_a_signed, did_something);
|
||||||
|
|
||||||
|
|
|
@ -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…
Reference in New Issue