mirror of
https://github.com/YosysHQ/yosys
synced 2026-07-25 16:42:35 +00:00
Merge pull request #134 from Silimate/negopt_runtime_fix
[ENG-1692] negopt runtime fix + small cleanup
This commit is contained in:
commit
b2e7c10bb7
8 changed files with 130 additions and 12 deletions
|
|
@ -24,6 +24,33 @@ PRIVATE_NAMESPACE_BEGIN
|
||||||
|
|
||||||
bool did_something;
|
bool did_something;
|
||||||
|
|
||||||
|
// Normalize top-end sign/zero extension for PMG prefiltering.
|
||||||
|
// Strips any redundant high bits so that a sign- or zero-extended SigSpec
|
||||||
|
// and its narrower original compare equal under index lookups.
|
||||||
|
// - top == prev: sign extension (MSB replicated)
|
||||||
|
// - top == SigBit(State::S0): zero extension (constant-zero padding)
|
||||||
|
// Only the prefilter key is stripped; exact legality is re-checked in the
|
||||||
|
// code block, so false-positive index hits are safe.
|
||||||
|
static SigSpec strip_ext_for_match(SigSpec sig)
|
||||||
|
{
|
||||||
|
int n = GetSize(sig);
|
||||||
|
if (n <= 1)
|
||||||
|
return sig;
|
||||||
|
|
||||||
|
while (n > 1) {
|
||||||
|
SigBit top = sig[n-1];
|
||||||
|
SigBit prev = sig[n-2];
|
||||||
|
// Strip sign-extended (repeated MSB) or zero-extended (S0) bits
|
||||||
|
if (top == prev || top == SigBit(State::S0)) {
|
||||||
|
n--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sig.extract(0, n);
|
||||||
|
}
|
||||||
|
|
||||||
#include "passes/silimate/peepopt_negopt.h"
|
#include "passes/silimate/peepopt_negopt.h"
|
||||||
|
|
||||||
struct NegoptPass : public Pass {
|
struct NegoptPass : public Pass {
|
||||||
|
|
@ -51,7 +78,7 @@ struct NegoptPass : public Pass {
|
||||||
log(" - muxneg: s?(-a):(-b) => -(s?a:b)\n");
|
log(" - muxneg: s?(-a):(-b) => -(s?a:b)\n");
|
||||||
log(" - neg2sub: a + (-b) => a - b\n" );
|
log(" - neg2sub: a + (-b) => a - b\n" );
|
||||||
log("\n");
|
log("\n");
|
||||||
log("When called without options, both -pre and -post are executed.\n");
|
log("Specify exactly one of -pre or -post.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -169,8 +169,8 @@ code root_add inner_add_B not_gate_B minuend subtrahend result_sig is_signed
|
||||||
|
|
||||||
// Verify inner_add_B has the form (~b + 1): one port is constant 1,
|
// Verify inner_add_B has the form (~b + 1): one port is constant 1,
|
||||||
// the other is the NOT output
|
// the other is the NOT output
|
||||||
SigSpec pa = inner_add_B->getPort(ID::A);
|
SigSpec pa = port(inner_add_B, \A);
|
||||||
SigSpec pb = inner_add_B->getPort(ID::B);
|
SigSpec pb = port(inner_add_B, \B);
|
||||||
SigSpec not_y = port(not_gate_B, \Y);
|
SigSpec not_y = port(not_gate_B, \Y);
|
||||||
|
|
||||||
auto is_one = [](SigSpec s) {
|
auto is_one = [](SigSpec s) {
|
||||||
|
|
@ -191,7 +191,7 @@ code root_add inner_add_B not_gate_B minuend subtrahend result_sig is_signed
|
||||||
|
|
||||||
// The minuend is whichever root_add port is NOT the inner_add_B output
|
// The minuend is whichever root_add port is NOT the inner_add_B output
|
||||||
subtrahend = port(not_gate_B, \A);
|
subtrahend = port(not_gate_B, \A);
|
||||||
if (inner_add_B->getPort(ID::Y) == root_add->getPort(ID::A))
|
if (port(inner_add_B, \Y) == port(root_add, \A))
|
||||||
minuend = root_b;
|
minuend = root_b;
|
||||||
else
|
else
|
||||||
minuend = root_a;
|
minuend = root_a;
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ code mux_a mux_b mux_s mux_y neg_a_in neg_a_y neg_b_in neg_b_y neg_a_signed neg_
|
||||||
SigSpec neg_a_rs = neg_a_in;
|
SigSpec neg_a_rs = neg_a_in;
|
||||||
SigSpec neg_b_rs = neg_b_in;
|
SigSpec neg_b_rs = neg_b_in;
|
||||||
neg_a_rs.extend_u0(width, neg_a_signed);
|
neg_a_rs.extend_u0(width, neg_a_signed);
|
||||||
neg_b_rs.extend_u0(width, neg_a_signed);
|
neg_b_rs.extend_u0(width, neg_b_signed);
|
||||||
|
|
||||||
SigSpec mux_out = module->addWire(NEW_ID2_SUFFIX("y"), width);
|
SigSpec mux_out = module->addWire(NEW_ID2_SUFFIX("y"), width);
|
||||||
Cell *new_mux = module->addMux(NEW_ID2_SUFFIX("mux"), neg_a_rs, neg_b_rs, mux_s, mux_out);
|
Cell *new_mux = module->addMux(NEW_ID2_SUFFIX("mux"), neg_a_rs, neg_b_rs, mux_s, mux_out);
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ pattern negmux
|
||||||
// -(s ? a : b) ===> s ? (-a) : (-b)
|
// -(s ? a : b) ===> s ? (-a) : (-b)
|
||||||
//
|
//
|
||||||
|
|
||||||
state <SigSpec> neg_a neg_y mux_a mux_b mux_s mux_y
|
state <SigSpec> neg_a neg_y neg_a_norm mux_a mux_b mux_s mux_y
|
||||||
state <bool> a_signed
|
state <bool> a_signed
|
||||||
|
|
||||||
match neg
|
match neg
|
||||||
|
|
@ -15,11 +15,13 @@ match neg
|
||||||
set neg_a port(neg, \A)
|
set neg_a port(neg, \A)
|
||||||
set neg_y port(neg, \Y)
|
set neg_y port(neg, \Y)
|
||||||
set a_signed neg->getParam(\A_SIGNED).as_bool()
|
set a_signed neg->getParam(\A_SIGNED).as_bool()
|
||||||
|
set neg_a_norm strip_ext_for_match(neg_a)
|
||||||
endmatch
|
endmatch
|
||||||
|
|
||||||
match mux
|
match mux
|
||||||
select mux->type == $mux
|
select mux->type == $mux
|
||||||
select nusers(port(mux, \Y)) == 2
|
index <SigSpec> strip_ext_for_match(port(mux, \Y)) === neg_a_norm
|
||||||
|
filter nusers(port(mux, \Y)) == 2
|
||||||
set mux_a port(mux, \A)
|
set mux_a port(mux, \A)
|
||||||
set mux_b port(mux, \B)
|
set mux_b port(mux, \B)
|
||||||
set mux_s port(mux, \S)
|
set mux_s port(mux, \S)
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ match neg2
|
||||||
endmatch
|
endmatch
|
||||||
|
|
||||||
code neg1_a neg1_y neg2_a
|
code neg1_a neg1_y neg2_a
|
||||||
// Reject if inner negation truncates
|
// Reject if the inner negation widens its output
|
||||||
if (GetSize(neg1_a) > GetSize(neg2_a))
|
if (GetSize(neg1_a) > GetSize(neg2_a))
|
||||||
reject;
|
reject;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@ pattern negrebuild
|
||||||
// (-a) + (-b) ===> -(a + b)
|
// (-a) + (-b) ===> -(a + b)
|
||||||
//
|
//
|
||||||
|
|
||||||
state <SigSpec> add_a add_b add_y neg1_a neg1_y neg2_a neg2_y
|
state <SigSpec> add_a add_b add_y add_a_norm add_b_norm neg1_a neg1_y neg2_a neg2_y
|
||||||
state <bool> add_signed add_b_signed neg1_signed neg2_signed
|
state <bool> add_signed add_b_signed neg1_signed neg2_signed neg1_on_a
|
||||||
|
|
||||||
match add
|
match add
|
||||||
select add->type == $add
|
select add->type == $add
|
||||||
|
|
@ -17,11 +17,20 @@ match add
|
||||||
set add_y port(add, \Y)
|
set add_y port(add, \Y)
|
||||||
set add_signed add->getParam(\A_SIGNED).as_bool()
|
set add_signed add->getParam(\A_SIGNED).as_bool()
|
||||||
set add_b_signed add->getParam(\B_SIGNED).as_bool()
|
set add_b_signed add->getParam(\B_SIGNED).as_bool()
|
||||||
|
set add_a_norm strip_ext_for_match(add_a)
|
||||||
|
set add_b_norm strip_ext_for_match(add_b)
|
||||||
endmatch
|
endmatch
|
||||||
|
|
||||||
|
code neg1_on_a
|
||||||
|
neg1_on_a = true;
|
||||||
|
branch;
|
||||||
|
neg1_on_a = false;
|
||||||
|
endcode
|
||||||
|
|
||||||
match neg1
|
match neg1
|
||||||
select neg1->type == $neg
|
select neg1->type == $neg
|
||||||
select nusers(port(neg1, \Y)) == 2
|
index <SigSpec> strip_ext_for_match(port(neg1, \Y)) === (neg1_on_a ? add_a_norm : add_b_norm)
|
||||||
|
filter nusers(port(neg1, \Y)) == 2
|
||||||
set neg1_a port(neg1, \A)
|
set neg1_a port(neg1, \A)
|
||||||
set neg1_y port(neg1, \Y)
|
set neg1_y port(neg1, \Y)
|
||||||
set neg1_signed neg1->getParam(\A_SIGNED).as_bool()
|
set neg1_signed neg1->getParam(\A_SIGNED).as_bool()
|
||||||
|
|
@ -29,7 +38,8 @@ endmatch
|
||||||
|
|
||||||
match neg2
|
match neg2
|
||||||
select neg2->type == $neg
|
select neg2->type == $neg
|
||||||
select nusers(port(neg2, \Y)) == 2
|
index <SigSpec> strip_ext_for_match(port(neg2, \Y)) === (neg1_on_a ? add_b_norm : add_a_norm)
|
||||||
|
filter nusers(port(neg2, \Y)) == 2
|
||||||
set neg2_a port(neg2, \A)
|
set neg2_a port(neg2, \A)
|
||||||
set neg2_y port(neg2, \Y)
|
set neg2_y port(neg2, \Y)
|
||||||
set neg2_signed neg2->getParam(\A_SIGNED).as_bool()
|
set neg2_signed neg2->getParam(\A_SIGNED).as_bool()
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,56 @@ select -assert-count 2 t:$neg
|
||||||
design -reset
|
design -reset
|
||||||
log -pop
|
log -pop
|
||||||
|
|
||||||
|
log -header "Positive case: neg input is sign extension of mux output"
|
||||||
|
log -push
|
||||||
|
design -reset
|
||||||
|
read_verilog <<EOF
|
||||||
|
module top(a, b, s, y);
|
||||||
|
input wire signed [7:0] a;
|
||||||
|
input wire signed [7:0] b;
|
||||||
|
input wire s;
|
||||||
|
output wire signed [11:0] y;
|
||||||
|
wire signed [7:0] m;
|
||||||
|
wire signed [11:0] m_ext;
|
||||||
|
assign m = s ? a : b;
|
||||||
|
assign m_ext = m;
|
||||||
|
assign y = -m_ext;
|
||||||
|
endmodule
|
||||||
|
EOF
|
||||||
|
proc; opt
|
||||||
|
check -assert
|
||||||
|
equiv_opt -assert negopt -pre
|
||||||
|
design -load postopt
|
||||||
|
select -assert-count 1 t:$mux
|
||||||
|
select -assert-count 2 t:$neg
|
||||||
|
design -reset
|
||||||
|
log -pop
|
||||||
|
|
||||||
|
log -header "Positive case: neg input is zero extension of mux output"
|
||||||
|
log -push
|
||||||
|
design -reset
|
||||||
|
read_verilog <<EOF
|
||||||
|
module top(a, b, s, y);
|
||||||
|
input wire [7:0] a;
|
||||||
|
input wire [7:0] b;
|
||||||
|
input wire s;
|
||||||
|
output wire [11:0] y;
|
||||||
|
wire [7:0] m;
|
||||||
|
wire [11:0] m_ext;
|
||||||
|
assign m = s ? a : b;
|
||||||
|
assign m_ext = m;
|
||||||
|
assign y = -m_ext;
|
||||||
|
endmodule
|
||||||
|
EOF
|
||||||
|
proc; opt
|
||||||
|
check -assert
|
||||||
|
equiv_opt -assert negopt -pre
|
||||||
|
design -load postopt
|
||||||
|
select -assert-count 1 t:$mux
|
||||||
|
select -assert-count 2 t:$neg
|
||||||
|
design -reset
|
||||||
|
log -pop
|
||||||
|
|
||||||
log -header "Negative case: mux output has extra fanout"
|
log -header "Negative case: mux output has extra fanout"
|
||||||
log -push
|
log -push
|
||||||
design -reset
|
design -reset
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,35 @@ select -assert-none t:$sub
|
||||||
design -reset
|
design -reset
|
||||||
log -pop
|
log -pop
|
||||||
|
|
||||||
|
log -header "Negative case: add inputs are sign-extended neg outputs"
|
||||||
|
log -push
|
||||||
|
design -reset
|
||||||
|
read_verilog <<EOF
|
||||||
|
module top(a, b, y);
|
||||||
|
input wire signed [7:0] a;
|
||||||
|
input wire signed [7:0] b;
|
||||||
|
output wire signed [11:0] y;
|
||||||
|
wire signed [7:0] na;
|
||||||
|
wire signed [7:0] nb;
|
||||||
|
wire signed [11:0] na_ext;
|
||||||
|
wire signed [11:0] nb_ext;
|
||||||
|
assign na = -a;
|
||||||
|
assign nb = -b;
|
||||||
|
assign na_ext = na;
|
||||||
|
assign nb_ext = nb;
|
||||||
|
assign y = na_ext + nb_ext;
|
||||||
|
endmodule
|
||||||
|
EOF
|
||||||
|
proc; opt
|
||||||
|
check -assert
|
||||||
|
equiv_opt -assert negopt -post
|
||||||
|
design -load postopt
|
||||||
|
select -assert-count 1 t:$add
|
||||||
|
select -assert-count 2 t:$neg
|
||||||
|
select -assert-none t:$sub
|
||||||
|
design -reset
|
||||||
|
log -pop
|
||||||
|
|
||||||
log -header "Anchor case: neg branches with different widths"
|
log -header "Anchor case: neg branches with different widths"
|
||||||
log -push
|
log -push
|
||||||
design -reset
|
design -reset
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue