aboutsummaryrefslogtreecommitdiffstats
path: root/tests/opt
diff options
context:
space:
mode:
Diffstat (limited to 'tests/opt')
-rw-r--r--tests/opt/.gitignore1
-rw-r--r--tests/opt/bug1854.ys17
-rw-r--r--tests/opt/bug2221.ys16
-rw-r--r--tests/opt/bug2311.ys14
-rw-r--r--tests/opt/bug2318.ys12
-rw-r--r--tests/opt/bug2623.ys14
-rw-r--r--tests/opt/bug2765.ys34
-rw-r--r--tests/opt/bug2766.ys101
-rw-r--r--tests/opt/bug2824.ys7
-rw-r--r--tests/opt/bug2920.ys42
-rw-r--r--tests/opt/bug3047.ys12
-rw-r--r--tests/opt/bug3117.ys34
-rw-r--r--tests/opt/memory_dff_trans.ys874
-rw-r--r--tests/opt/memory_map_offset.ys100
-rw-r--r--tests/opt/opt_clean_init.ys31
-rw-r--r--tests/opt/opt_clean_mem.ys48
-rw-r--r--tests/opt/opt_dff_arst.ys101
-rw-r--r--tests/opt/opt_dff_clk.ys45
-rw-r--r--tests/opt/opt_dff_const.ys49
-rw-r--r--tests/opt/opt_dff_dffmux.ys129
-rw-r--r--tests/opt/opt_dff_en.ys157
-rw-r--r--tests/opt/opt_dff_mux.ys86
-rw-r--r--tests/opt/opt_dff_qd.ys56
-rw-r--r--tests/opt/opt_dff_sr.ys309
-rw-r--r--tests/opt/opt_dff_srst.ys113
-rw-r--r--tests/opt/opt_expr_constconn.v8
-rw-r--r--tests/opt/opt_expr_constconn.ys7
-rw-r--r--tests/opt/opt_mem_feedback.ys189
-rw-r--r--tests/opt/opt_mem_priority.ys209
-rw-r--r--tests/opt/opt_merge_init.ys2
-rw-r--r--tests/opt/opt_reduce_bmux.ys117
-rw-r--r--tests/opt/opt_reduce_demux.ys91
-rw-r--r--tests/opt/opt_rmdff.ys3
-rw-r--r--tests/opt/opt_rmdff_sat.ys4
-rw-r--r--tests/opt/opt_share_bug2334.ys13
-rw-r--r--tests/opt/opt_share_bug2335.ys27
-rw-r--r--tests/opt/opt_share_bug2336.ys14
-rw-r--r--tests/opt/opt_share_bug2538.ys20
-rwxr-xr-xtests/opt/run-test.sh8
39 files changed, 3093 insertions, 21 deletions
diff --git a/tests/opt/.gitignore b/tests/opt/.gitignore
index 397b4a762..8355de9dc 100644
--- a/tests/opt/.gitignore
+++ b/tests/opt/.gitignore
@@ -1 +1,2 @@
*.log
+run-test.mk
diff --git a/tests/opt/bug1854.ys b/tests/opt/bug1854.ys
new file mode 100644
index 000000000..00a36ae94
--- /dev/null
+++ b/tests/opt/bug1854.ys
@@ -0,0 +1,17 @@
+read_verilog << EOT
+module top(input clk, input [3:0] addr, output reg [0:0] dout);
+ reg [1:0] mem[0:15];
+ initial begin
+ mem[0] = 2'b00;
+ mem[1] = 2'b01;
+ mem[2] = 2'b10;
+ mem[3] = 2'b11;
+ end
+ always @(posedge clk)
+ dout <= mem[addr];
+endmodule
+EOT
+
+prep -rdff
+
+select -assert-none t:$dff
diff --git a/tests/opt/bug2221.ys b/tests/opt/bug2221.ys
new file mode 100644
index 000000000..8ac380243
--- /dev/null
+++ b/tests/opt/bug2221.ys
@@ -0,0 +1,16 @@
+read_verilog <<EOT
+module test (
+ input [1:0] a,
+ input [1:0] b,
+ output [5:0] y
+);
+
+wire [5:0] aa = {a, 4'h0};
+wire [5:0] bb = {b, 4'h0};
+
+assign y = aa * bb;
+
+endmodule
+EOT
+
+equiv_opt -assert opt_expr
diff --git a/tests/opt/bug2311.ys b/tests/opt/bug2311.ys
new file mode 100644
index 000000000..455147cd3
--- /dev/null
+++ b/tests/opt/bug2311.ys
@@ -0,0 +1,14 @@
+read_verilog -icells << EOT
+
+module top(...);
+
+input A;
+output Y;
+
+$_XNOR_ x (.A(A), .B(A), .Y(Y));
+
+endmodule
+
+EOT
+
+equiv_opt -assert opt_expr
diff --git a/tests/opt/bug2318.ys b/tests/opt/bug2318.ys
new file mode 100644
index 000000000..9de6f88ec
--- /dev/null
+++ b/tests/opt/bug2318.ys
@@ -0,0 +1,12 @@
+read_verilog <<EOT
+module t(input [3:0] A, input [3:0] B, output signed [3:0] Y);
+
+wire [7:0] P = A * B;
+wire signed [7:0] SP = P;
+wire signed [3:0] SB = B;
+assign Y = SP / SB;
+
+endmodule
+EOT
+
+equiv_opt -assert peepopt
diff --git a/tests/opt/bug2623.ys b/tests/opt/bug2623.ys
new file mode 100644
index 000000000..2ff23ea6f
--- /dev/null
+++ b/tests/opt/bug2623.ys
@@ -0,0 +1,14 @@
+read_rtlil << EOT
+
+module \top
+ wire output 1 \a
+ wire width 0 $dummy
+ cell \abc \abc
+ connect \a \a
+ connect \b $dummy
+ end
+end
+
+EOT
+
+opt_clean
diff --git a/tests/opt/bug2765.ys b/tests/opt/bug2765.ys
new file mode 100644
index 000000000..7cb790bd7
--- /dev/null
+++ b/tests/opt/bug2765.ys
@@ -0,0 +1,34 @@
+read_verilog << EOT
+
+module top(...);
+
+input clk;
+input [3:0] wa;
+input [15:0] wd;
+input [3:0] ra;
+output [15:0] rd;
+
+reg [15:0] mem[0:15];
+
+integer i;
+reg x;
+
+always @(posedge clk) begin
+ for (i = 0; i < 2; i = i + 1) begin
+ x = i == 1;
+ if (x)
+ mem[wa] <= wd;
+ end
+end
+
+assign rd = mem[ra];
+
+endmodule
+
+EOT
+
+proc
+opt
+select -assert-count 2 t:$memwr_v2
+opt_mem
+select -assert-count 1 t:$memwr_v2
diff --git a/tests/opt/bug2766.ys b/tests/opt/bug2766.ys
new file mode 100644
index 000000000..c7aa916f4
--- /dev/null
+++ b/tests/opt/bug2766.ys
@@ -0,0 +1,101 @@
+# Case 1.
+
+read_verilog << EOT
+
+module top(...);
+
+input clk;
+input sel;
+input [3:0] ra;
+input [3:0] wa;
+input wd;
+output [3:0] rd;
+
+reg [3:0] mem[0:15];
+
+integer i;
+initial begin
+ for (i = 0; i < 16; i = i + 1)
+ mem[i] <= i;
+end
+
+assign rd = mem[ra];
+
+always @(posedge clk) begin
+ mem[wa] <= {4{sel ? wd : mem[wa][0]}};
+end
+
+endmodule
+
+EOT
+
+hierarchy -auto-top
+proc
+opt_clean
+
+design -save start
+memory_map
+design -save preopt
+
+design -load start
+opt_mem_feedback
+memory_map
+design -save postopt
+
+equiv_opt -assert -run prepare: :
+
+
+
+design -reset
+
+# Case 2.
+
+read_verilog << EOT
+
+module top(...);
+
+input clk;
+input s1;
+input s2;
+input s3;
+input [3:0] ra;
+input [3:0] wa;
+input wd;
+output rd;
+
+reg mem[0:15];
+
+integer i;
+initial begin
+ for (i = 0; i < 16; i = i + 1)
+ mem[i] <= ^i;
+end
+
+assign rd = mem[ra];
+
+wire ta = s1 ? wd : mem[wa];
+wire tb = s2 ? wd : ta;
+wire tc = s3 ? tb : ta;
+
+always @(posedge clk) begin
+ mem[wa] <= tc;
+end
+
+endmodule
+
+EOT
+
+hierarchy -auto-top
+proc
+opt_clean
+
+design -save start
+memory_map
+design -save preopt
+
+design -load start
+opt_mem_feedback
+memory_map
+design -save postopt
+
+equiv_opt -assert -run prepare: :
diff --git a/tests/opt/bug2824.ys b/tests/opt/bug2824.ys
new file mode 100644
index 000000000..9d0d1e9e5
--- /dev/null
+++ b/tests/opt/bug2824.ys
@@ -0,0 +1,7 @@
+read_verilog -icells << EOT
+module top(input I, output O);
+$pmux #(.WIDTH(1), .S_WIDTH(2)) m (.S({I, 1'b0}), .A(1'b0), .B({I, 1'b0}), .Y(O));
+endmodule
+EOT
+
+equiv_opt -assert opt_muxtree
diff --git a/tests/opt/bug2920.ys b/tests/opt/bug2920.ys
new file mode 100644
index 000000000..a8281a73a
--- /dev/null
+++ b/tests/opt/bug2920.ys
@@ -0,0 +1,42 @@
+read_ilang <<EOT
+
+module \mod
+ wire input 1 \clk
+ attribute \init 2'00
+ wire width 2 $q1
+ attribute \init 2'00
+ wire width 2 $q2
+ wire output 2 width 4 \q
+ cell $dff $ff1
+ parameter \CLK_POLARITY 1'1
+ parameter \WIDTH 1
+ connect \CLK \clk
+ connect \D 1'0
+ connect \Q $q1 [0]
+ end
+ cell $dff $ff2
+ parameter \CLK_POLARITY 1'1
+ parameter \WIDTH 1
+ connect \CLK \clk
+ connect \D 1'0
+ connect \Q $q2 [0]
+ end
+ cell $dff $ff3
+ parameter \CLK_POLARITY 1'1
+ parameter \WIDTH 2
+ connect \CLK \clk
+ connect \D 2'00
+ connect \Q { $q1 [1] $q2 [1] }
+ end
+ connect \q [0] $q1 [0]
+ connect \q [1] $q2 [0]
+ connect \q [2] $q1 [1]
+ connect \q [3] $q2 [1]
+end
+
+EOT
+
+opt_clean
+opt_merge
+opt_dff
+opt_clean
diff --git a/tests/opt/bug3047.ys b/tests/opt/bug3047.ys
new file mode 100644
index 000000000..6713877ce
--- /dev/null
+++ b/tests/opt/bug3047.ys
@@ -0,0 +1,12 @@
+read_verilog << EOT
+
+module test (A, B, C, D, Y);
+ input A, B, C, D;
+ output Y;
+ assign Y = A^B^C^D^A;
+endmodule
+
+EOT
+
+techmap
+equiv_opt -assert extract_reduce
diff --git a/tests/opt/bug3117.ys b/tests/opt/bug3117.ys
new file mode 100644
index 000000000..177b3ab9a
--- /dev/null
+++ b/tests/opt/bug3117.ys
@@ -0,0 +1,34 @@
+read_verilog << EOT
+
+module test (...);
+
+input [7:1] wa1;
+input [7:1] wa2;
+input [7:0] ra;
+output [7:0] rd;
+input clk;
+input we1, we2;
+input [15:0] wd1, wd2;
+
+reg [7:0] mem [0:255];
+
+assign rd = mem[ra];
+
+always @(posedge clk) begin
+ if (we1) begin
+ mem[{wa1, 1'b0}] <= wd1[7:0];
+ mem[{wa1, 1'b1}] <= wd1[15:8];
+ end else begin
+ mem[{wa2, 1'b0}] <= wd2[7:0];
+ mem[{wa2, 1'b1}] <= wd2[15:8];
+ end
+end
+
+endmodule
+
+EOT
+
+proc
+opt
+memory_share
+select -assert-count 1 t:$memwr_v2
diff --git a/tests/opt/memory_dff_trans.ys b/tests/opt/memory_dff_trans.ys
new file mode 100644
index 000000000..102b36f26
--- /dev/null
+++ b/tests/opt/memory_dff_trans.ys
@@ -0,0 +1,874 @@
+# Good case 1: single port.
+
+read_verilog << EOT
+
+module top(
+ input [3:0] addr,
+ input [3:0] wd,
+ input we,
+ input clk,
+ output reg [3:0] rd,
+);
+
+reg [3:0] mem[0:15];
+
+always @(posedge clk) begin
+ if (we) begin
+ mem[addr] <= wd;
+ rd <= wd;
+ end else begin
+ rd <= mem[addr];
+ end
+end
+
+endmodule
+
+EOT
+
+hierarchy -auto-top
+proc
+opt_dff
+opt_clean
+memory_dff
+memory_collect
+select -assert-count 1 t:$mem_v2
+select -assert-count 1 t:$mem_v2 r:RD_TRANSPARENCY_MASK=1'b1 r:RD_COLLISION_X_MASK=1'b0 %i %i
+
+design -reset
+
+# Good case 2: single port, exclusive.
+
+read_verilog << EOT
+
+module top(
+ input [3:0] addr,
+ input [3:0] wd,
+ input we,
+ input clk,
+ output reg [3:0] rd,
+);
+
+reg [3:0] mem[0:15];
+
+always @(posedge clk) begin
+ if (we) begin
+ mem[addr] <= wd;
+ end else begin
+ rd <= mem[addr];
+ end
+end
+
+endmodule
+
+EOT
+
+hierarchy -auto-top
+proc
+opt_dff
+opt_clean
+memory_dff
+memory_collect
+select -assert-count 1 t:$mem_v2
+select -assert-count 1 t:$mem_v2 r:RD_TRANSPARENCY_MASK=1'b0 r:RD_COLLISION_X_MASK=1'b1 %i %i
+
+design -reset
+
+# Good case 3: proper bypass muxes.
+
+read_verilog << EOT
+
+module top(
+ input [3:0] ra,
+ input [3:0] wa1,
+ input [3:0] wa2,
+ input [3:0] wd1,
+ input [3:0] wd2,
+ input we1, we2,
+ input re,
+ input clk,
+ output reg [3:0] rd,
+);
+
+reg [3:0] mem[0:15];
+
+always @(posedge clk) begin
+ if (we1)
+ mem[wa1] <= wd1;
+ if (we2)
+ mem[wa2] <= wd2;
+ if (re) begin
+ rd <= mem[ra];
+ if (we1 && wa1 == ra)
+ rd <= wd1;
+ if (we2 && wa2 == ra)
+ rd <= wd2;
+ end
+end
+
+endmodule
+
+EOT
+
+hierarchy -auto-top
+proc
+opt_dff
+opt_clean
+memory_dff
+memory_collect
+select -assert-count 1 t:$mem_v2
+select -assert-count 1 t:$mem_v2 r:RD_TRANSPARENCY_MASK=2'b11 r:RD_COLLISION_X_MASK=2'b00 %i %i
+
+design -reset
+
+# Good case 4: proper bypass mux, but only one.
+
+read_verilog << EOT
+
+module top(
+ input [3:0] ra,
+ input [3:0] wa1,
+ input [3:0] wa2,
+ input [3:0] wd1,
+ input [3:0] wd2,
+ input we1, we2,
+ input re,
+ input clk,
+ output reg [3:0] rd,
+);
+
+reg [3:0] mem[0:15];
+
+always @(posedge clk) begin
+ if (we1)
+ mem[wa1] <= wd1;
+ if (we2)
+ mem[wa2] <= wd2;
+ if (re) begin
+ rd <= mem[ra];
+ if (we1 && wa1 == ra)
+ rd <= wd1;
+ end
+end
+
+endmodule
+
+EOT
+
+hierarchy -auto-top
+proc
+opt_dff
+opt_clean
+memory_dff
+memory_collect
+select -assert-count 1 t:$mem_v2
+select -assert-count 1 t:$mem_v2 r:RD_TRANSPARENCY_MASK=2'b01 r:RD_COLLISION_X_MASK=2'b00 %i %i
+
+design -reset
+
+# Good case 5: proper bypass mux, but the other one.
+
+read_verilog << EOT
+
+module top(
+ input [3:0] ra,
+ input [3:0] wa1,
+ input [3:0] wa2,
+ input [3:0] wd1,
+ input [3:0] wd2,
+ input we1, we2,
+ input re,
+ input clk,
+ output reg [3:0] rd,
+);
+
+reg [3:0] mem[0:15];
+
+always @(posedge clk) begin
+ if (we1)
+ mem[wa1] <= wd1;
+ if (we2)
+ mem[wa2] <= wd2;
+ if (re) begin
+ rd <= mem[ra];
+ if (we2 && wa2 == ra)
+ rd <= wd2;
+ end
+end
+
+endmodule
+
+EOT
+
+hierarchy -auto-top
+proc
+opt_dff
+opt_clean
+memory_dff
+memory_collect
+select -assert-count 1 t:$mem_v2
+select -assert-count 1 t:$mem_v2 r:RD_TRANSPARENCY_MASK=2'b10 r:RD_COLLISION_X_MASK=2'b00 %i %i
+
+design -reset
+
+# Good case 6: 'x mux.
+
+read_verilog << EOT
+
+module top(
+ input [3:0] ra,
+ input [3:0] wa1,
+ input [3:0] wa2,
+ input [3:0] wd1,
+ input [3:0] wd2,
+ input we1, we2,
+ input re,
+ input clk,
+ output reg [3:0] rd,
+);
+
+reg [3:0] mem[0:15];
+
+always @(posedge clk) begin
+ if (we1)
+ mem[wa1] <= wd1;
+ if (we2)
+ mem[wa2] <= wd2;
+ if (re) begin
+ rd <= mem[ra];
+ if (we1 && wa1 == ra)
+ rd <= 4'hx;
+ if (we2 && wa2 == ra)
+ rd <= wd2;
+ end
+end
+
+endmodule
+
+EOT
+
+hierarchy -auto-top
+proc
+opt_dff
+opt_clean
+memory_dff
+memory_collect
+select -assert-count 1 t:$mem_v2
+select -assert-count 1 t:$mem_v2 r:RD_TRANSPARENCY_MASK=2'b10 r:RD_COLLISION_X_MASK=2'b01 %i %i
+
+design -reset
+
+# Good case 7: uncollidable addresses.
+
+read_verilog << EOT
+
+module top(
+ input [3:0] addr,
+ input [3:0] wd1,
+ input [3:0] wd2,
+ input we1, we2,
+ input re,
+ input clk,
+ output reg [3:0] rd,
+);
+
+reg [3:0] mem[0:15];
+
+wire [3:0] wa1 = addr;
+wire [3:0] wa2 = addr + 1;
+wire [3:0] ra = addr + 2;
+
+always @(posedge clk) begin
+ if (we1)
+ mem[wa1] <= wd1;
+ if (we2)
+ mem[wa2] <= wd2;
+ if (re) begin
+ rd <= mem[ra];
+ end
+end
+
+endmodule
+
+EOT
+
+hierarchy -auto-top
+proc
+opt_dff
+opt_clean
+memory_dff
+memory_collect
+select -assert-count 1 t:$mem_v2
+select -assert-count 1 t:$mem_v2 r:RD_TRANSPARENCY_MASK=2'b00 r:RD_COLLISION_X_MASK=2'b11 %i %i
+
+design -reset
+
+# Good case 8: uncollidable addresses, but still have soft transparency logic.
+
+read_verilog << EOT
+
+module top(
+ input [3:0] addr,
+ input [3:0] wd1,
+ input [3:0] wd2,
+ input we1, we2,
+ input re,
+ input clk,
+ output reg [3:0] rd,
+);
+
+reg [3:0] mem[0:15];
+
+wire [3:0] wa1 = addr;
+wire [3:0] wa2 = addr + 1;
+wire [3:0] ra = addr + 2;
+
+always @(posedge clk) begin
+ if (we1)
+ mem[wa1] <= wd1;
+ if (we2)
+ mem[wa2] <= wd2;
+ if (re) begin
+ rd <= mem[ra];
+ if (we1 && wa1 == ra)
+ rd <= wd1;
+ if (we2 && wa2 == ra)
+ rd <= wd2;
+ end
+end
+
+endmodule
+
+EOT
+
+hierarchy -auto-top
+proc
+opt_dff
+opt_clean
+memory_dff
+memory_collect
+select -assert-count 1 t:$mem_v2
+select -assert-count 1 t:$mem_v2 r:RD_TRANSPARENCY_MASK=2'b00 r:RD_COLLISION_X_MASK=2'b11 %i %i
+
+design -reset
+
+# Bad case 1: broken bypass signal.
+
+read_verilog << EOT
+
+module top(
+ input [3:0] ra,
+ input [3:0] wa1,
+ input [3:0] wa2,
+ input [3:0] wd1,
+ input [3:0] wd2,
+ input we1, we2,
+ input re,
+ input clk,
+ output reg [3:0] rd,
+);
+
+reg [3:0] mem[0:15];
+
+always @(posedge clk) begin
+ if (we1)
+ mem[wa1] <= wd1;
+ if (we2)
+ mem[wa2] <= wd2;
+ if (re) begin
+ rd <= mem[ra];
+ if (we1 && wa1 == ra)
+ rd <= wd1;
+ if (we2 && wa2 == ra && we1)
+ rd <= wd2;
+ end
+end
+
+endmodule
+
+EOT
+
+hierarchy -auto-top
+proc
+opt_dff
+opt_clean
+logger -expect log "FF found, but with a mux select that doesn't seem to correspond to transparency logic" 1
+memory_dff
+logger -check-expected
+memory_collect
+select -assert-count 1 t:$mem_v2
+select -assert-count 1 t:$mem_v2 r:RD_CLK_ENABLE=1'b0 %i
+
+design -reset
+
+# Bad case 2: bad data signal.
+
+read_verilog << EOT
+
+module top(
+ input [3:0] ra,
+ input [3:0] wa1,
+ input [3:0] wa2,
+ input [3:0] wd1,
+ input [3:0] wd2,
+ input we1, we2,
+ input re,
+ input clk,
+ output reg [3:0] rd,
+);
+
+reg [3:0] mem[0:15];
+
+always @(posedge clk) begin
+ if (we1)
+ mem[wa1] <= wd1;
+ if (we2)
+ mem[wa2] <= wd2;
+ if (re) begin
+ rd <= mem[ra];
+ if (we1 && wa1 == ra)
+ rd <= wd1;
+ if (we2 && wa2 == ra)
+ rd <= wd1;
+ end
+end
+
+endmodule
+
+EOT
+
+hierarchy -auto-top
+proc
+opt_dff
+opt_clean
+logger -expect log "FF found, but with a mux data input that doesn't seem to correspond to transparency logic" 1
+memory_dff
+logger -check-expected
+memory_collect
+select -assert-count 1 t:$mem_v2
+select -assert-count 1 t:$mem_v2 r:RD_CLK_ENABLE=1'b0 %i
+
+design -reset
+
+# Bad case 3: priority mismatch.
+
+read_verilog << EOT
+
+module top(
+ input [3:0] ra,
+ input [3:0] wa1,
+ input [3:0] wa2,
+ input [3:0] wd1,
+ input [3:0] wd2,
+ input we1, we2,
+ input re,
+ input clk,
+ output reg [3:0] rd,
+);
+
+reg [3:0] mem[0:15];
+
+always @(posedge clk) begin
+ if (we1)
+ mem[wa1] <= wd1;
+ if (we2)
+ mem[wa2] <= wd2;
+ if (re) begin
+ rd <= mem[ra];
+ if (we2 && wa2 == ra)
+ rd <= wd2;
+ if (we1 && wa1 == ra)
+ rd <= wd1;
+ end
+end
+
+endmodule
+
+EOT
+
+hierarchy -auto-top
+proc
+opt_dff
+opt_clean
+logger -expect log "FF found, but transparency logic priority doesn't match write priority." 1
+memory_dff
+logger -check-expected
+memory_collect
+select -assert-count 1 t:$mem_v2
+select -assert-count 1 t:$mem_v2 r:RD_CLK_ENABLE=1'b0 %i
+
+design -reset
+
+# Good case 10: priority mismatch, but since the second value is 'x, it's still OK.
+
+read_verilog << EOT
+
+module top(
+ input [3:0] ra,
+ input [3:0] wa1,
+ input [3:0] wa2,
+ input [3:0] wd1,
+ input [3:0] wd2,
+ input we1, we2,
+ input re,
+ input clk,
+ output reg [3:0] rd,
+);
+
+reg [3:0] mem[0:15];
+
+always @(posedge clk) begin
+ if (we1)
+ mem[wa1] <= wd1;
+ if (we2)
+ mem[wa2] <= wd2;
+ if (re) begin
+ rd <= mem[ra];
+ if (we2 && wa2 == ra)
+ rd <= wd2;
+ if (we1 && wa1 == ra)
+ rd <= 4'hx;
+ end
+end
+
+endmodule
+
+EOT
+
+hierarchy -auto-top
+proc
+opt_dff
+opt_clean
+memory_dff
+memory_collect
+select -assert-count 1 t:$mem_v2
+select -assert-count 1 t:$mem_v2 r:RD_TRANSPARENCY_MASK=2'b10 r:RD_COLLISION_X_MASK=2'b01 %i %i
+
+design -reset
+
+# Good case 11: priority mismatch, but since three-way collision cannot happen, it's still OK.
+
+read_verilog << EOT
+
+module top(
+ input [3:0] addr,
+ input [1:0] mode,
+ input [3:0] wd1,
+ input [3:0] wd2,
+ input we1, we2,
+ input re,
+ input clk,
+ output reg [3:0] rd,
+);
+
+reg [3:0] wa1, wa2, ra;
+
+always @* begin
+ case (mode)
+ 0: begin
+ wa1 = addr+1;
+ wa2 = addr;
+ ra = addr;
+ end
+ 1: begin
+ wa1 = addr;
+ wa2 = addr+1;
+ ra = addr;
+ end
+ 2: begin
+ wa1 = addr;
+ wa2 = addr;
+ ra = addr+1;
+ end
+ 3: begin
+ wa1 = addr;
+ wa2 = addr+1;
+ ra = addr+2;
+ end
+ endcase
+end
+
+reg [3:0] mem[0:15];
+
+always @(posedge clk) begin
+ if (we1)
+ mem[wa1] <= wd1;
+ if (we2)
+ mem[wa2] <= wd2;
+ if (re) begin
+ rd <= mem[ra];
+ if (we2 && wa2 == ra)
+ rd <= wd2;
+ if (we1 && wa1 == ra)
+ rd <= wd1;
+ end
+end
+
+endmodule
+
+EOT
+
+hierarchy -auto-top
+proc
+opt_dff
+opt_clean
+memory_dff
+memory_collect
+select -assert-count 1 t:$mem_v2
+select -assert-count 1 t:$mem_v2 r:RD_TRANSPARENCY_MASK=2'b11 r:RD_COLLISION_X_MASK=2'b00 %i %i
+
+design -reset
+
+# Bad case 4: half of the port is transparent.
+
+read_verilog << EOT
+
+module top(
+ input [3:0] ra,
+ input [3:0] wa1,
+ input [3:0] wa2,
+ input [3:0] wd1,
+ input [3:0] wd2,
+ input we1, we2,
+ input re,
+ input clk,
+ output reg [3:0] rd,
+);
+
+reg [3:0] mem[0:15];
+
+always @(posedge clk) begin
+ if (we1)
+ mem[wa1] <= wd1;
+ if (we2)
+ mem[wa2] <= wd2;
+ if (re) begin
+ rd <= mem[ra];
+ if (we1 && wa1 == ra)
+ rd <= wd1;
+ if (we2 && wa2 == ra)
+ rd[3:2] <= wd2[3:2];
+ end
+end
+
+endmodule
+
+EOT
+
+hierarchy -auto-top
+proc
+opt_dff
+opt_clean
+logger -expect log "FF found, but soft transparency logic is inconsistent for port 1." 1
+memory_dff
+logger -check-expected
+memory_collect
+select -assert-count 1 t:$mem_v2
+select -assert-count 1 t:$mem_v2 r:RD_CLK_ENABLE=1'b0 %i
+
+design -reset
+
+# Good case 12: like above, but the other bits aren't changed by the port anyway.
+
+read_verilog << EOT
+
+module top(
+ input [3:0] ra,
+ input [3:0] wa1,
+ input [3:0] wa2,
+ input [3:0] wd1,
+ input [3:0] wd2,
+ input we1, we2,
+ input re,
+ input clk,
+ output reg [3:0] rd,
+);
+
+reg [3:0] mem[0:15];
+
+always @(posedge clk) begin
+ if (we1)
+ mem[wa1] <= wd1;
+ if (we2)
+ mem[wa2][3:2] <= wd2[3:2];
+ if (re) begin
+ rd <= mem[ra];
+ if (we1 && wa1 == ra)
+ rd <= wd1;
+ if (we2 && wa2 == ra)
+ rd[3:2] <= wd2[3:2];
+ end
+end
+
+endmodule
+
+EOT
+
+hierarchy -auto-top
+proc
+opt_dff
+opt_clean
+memory_dff
+memory_collect
+select -assert-count 1 t:$mem_v2
+select -assert-count 1 t:$mem_v2 r:RD_TRANSPARENCY_MASK=2'b11 r:RD_COLLISION_X_MASK=2'b00 %i %i
+
+design -reset
+
+# Good case 13: wide read, narrow write.
+
+read_verilog << EOT
+
+module top(
+ input [7:0] addr,
+ input [7:0] wd,
+ input we,
+ input re,
+ input clk,
+ output reg [31:0] rd,
+);
+
+reg [7:0] mem[0:255];
+
+always @(posedge clk) begin
+ if (we)
+ mem[addr] <= wd;
+ if (re) begin
+ rd[7:0] <= mem[{addr[7:2], 2'b00}];
+ rd[15:8] <= mem[{addr[7:2], 2'b01}];
+ rd[23:16] <= mem[{addr[7:2], 2'b10}];
+ rd[31:24] <= mem[{addr[7:2], 2'b11}];
+ case ({we, addr[1:0]})
+ 3'b100: rd[7:0] <= wd;
+ 3'b101: rd[15:8] <= wd;
+ 3'b110: rd[23:16] <= wd;
+ 3'b111: rd[31:24] <= wd;
+ endcase
+ end
+end
+
+endmodule
+
+EOT
+
+hierarchy -auto-top
+proc
+opt_dff
+opt_clean
+dump
+memory_dff
+memory_collect
+select -assert-count 1 t:$mem_v2
+select -assert-count 1 t:$mem_v2 r:RD_TRANSPARENCY_MASK=4'b1111 r:RD_COLLISION_X_MASK=4'b0000 %i %i
+memory_share
+select -assert-count 1 t:$mem_v2
+select -assert-count 1 t:$mem_v2 r:RD_TRANSPARENCY_MASK=4'b1111 r:RD_COLLISION_X_MASK=4'b0000 %i %i
+select -assert-count 1 t:$mem_v2 r:RD_WIDE_CONTINUATION=4'b1110 %i
+
+design -reset
+
+# Good case 14: narrow read, wide write.
+
+read_verilog << EOT
+
+module top(
+ input [7:0] addr,
+ input [31:0] wd,
+ input we,
+ input re,
+ input clk,
+ output reg [7:0] rd,
+);
+
+reg [7:0] mem[0:255];
+
+always @(posedge clk) begin
+ if (we) begin
+ mem[{addr[7:2], 2'b00}] <= wd[7:0];
+ mem[{addr[7:2], 2'b01}] <= wd[15:8];
+ mem[{addr[7:2], 2'b10}] <= wd[23:16];
+ mem[{addr[7:2], 2'b11}] <= wd[31:24];
+ end
+ if (re) begin
+ rd <= mem[addr];
+ case ({we, addr[1:0]})
+ 3'b100: rd <= wd[7:0];
+ 3'b101: rd <= wd[15:8];
+ 3'b110: rd <= wd[23:16];
+ 3'b111: rd <= wd[31:24];
+ endcase
+ end
+end
+
+endmodule
+
+EOT
+
+hierarchy -auto-top
+proc
+opt_dff
+opt_clean
+dump
+memory_dff
+memory_collect
+select -assert-count 1 t:$mem_v2
+select -assert-count 1 t:$mem_v2 r:RD_TRANSPARENCY_MASK=4'b1111 r:RD_COLLISION_X_MASK=4'b0000 %i %i
+memory_share
+select -assert-count 1 t:$mem_v2
+select -assert-count 1 t:$mem_v2 r:RD_TRANSPARENCY_MASK=4'b1111 r:RD_COLLISION_X_MASK=4'b0000 %i %i
+select -assert-count 1 t:$mem_v2 r:WR_WIDE_CONTINUATION=4'b1110 %i
+
+design -reset
+
+# Good case 15: wide read, wide write.
+
+read_verilog << EOT
+
+module top(
+ input [7:0] addr,
+ input [31:0] wd,
+ input we,
+ input re,
+ input clk,
+ output reg [31:0] rd,
+);
+
+reg [7:0] mem[0:255];
+
+always @(posedge clk) begin
+ if (we) begin
+ mem[{addr[7:2], 2'b00}] <= wd[7:0];
+ mem[{addr[7:2], 2'b01}] <= wd[15:8];
+ mem[{addr[7:2], 2'b10}] <= wd[23:16];
+ mem[{addr[7:2], 2'b11}] <= wd[31:24];
+ end
+ if (re) begin
+ rd[7:0] <= mem[{addr[7:2], 2'b00}];
+ rd[15:8] <= mem[{addr[7:2], 2'b01}];
+ rd[23:16] <= mem[{addr[7:2], 2'b10}];
+ rd[31:24] <= mem[{addr[7:2], 2'b11}];
+ if (we)
+ rd <= wd;
+ end
+end
+
+endmodule
+
+EOT
+
+hierarchy -auto-top
+proc
+opt_dff
+opt_clean
+dump
+memory_dff
+select -assert-count 4 t:$memrd_v2
+select -assert-count 1 t:$memrd_v2 r:TRANSPARENCY_MASK=4'b0001 r:COLLISION_X_MASK=4'b1110 %i %i
+select -assert-count 1 t:$memrd_v2 r:TRANSPARENCY_MASK=4'b0010 r:COLLISION_X_MASK=4'b1101 %i %i
+select -assert-count 1 t:$memrd_v2 r:TRANSPARENCY_MASK=4'b0100 r:COLLISION_X_MASK=4'b1011 %i %i
+select -assert-count 1 t:$memrd_v2 r:TRANSPARENCY_MASK=4'b1000 r:COLLISION_X_MASK=4'b0111 %i %i
+memory_share
+select -assert-count 1 t:$memrd_v2
+select -assert-count 1 t:$memwr_v2
+select -assert-count 1 t:$memrd_v2 r:TRANSPARENCY_MASK=1'b1 r:COLLISION_X_MASK=1'b0 %i %i
+
+design -reset
diff --git a/tests/opt/memory_map_offset.ys b/tests/opt/memory_map_offset.ys
new file mode 100644
index 000000000..06969922d
--- /dev/null
+++ b/tests/opt/memory_map_offset.ys
@@ -0,0 +1,100 @@
+read_verilog << EOT
+
+module top(...);
+
+input [3:0] ra;
+input [3:0] wa;
+
+input [15:0] wd;
+output [15:0] rd;
+input en, clk;
+
+reg [15:0] mem[3:9];
+
+always @(posedge clk)
+ if (en)
+ mem[wa] <= wd;
+
+assign rd = mem[ra];
+
+endmodule
+
+EOT
+
+hierarchy -auto-top
+proc
+opt_clean
+memory_map
+
+design -stash gate
+
+read_verilog << EOT
+
+module top(...);
+
+input [3:0] ra;
+input [3:0] wa;
+
+input [15:0] wd;
+output reg [15:0] rd;
+input en, clk;
+
+reg [15:0] \mem[3] ;
+reg [15:0] \mem[4] ;
+reg [15:0] \mem[5] ;
+reg [15:0] \mem[6] ;
+reg [15:0] \mem[7] ;
+reg [15:0] \mem[8] ;
+reg [15:0] \mem[9] ;
+
+always @(posedge clk) begin
+ if (en && wa == 3)
+ \mem[3] <= wd;
+ if (en && wa == 4)
+ \mem[4] <= wd;
+ if (en && wa == 5)
+ \mem[5] <= wd;
+ if (en && wa == 6)
+ \mem[6] <= wd;
+ if (en && wa == 7)
+ \mem[7] <= wd;
+ if (en && wa == 8)
+ \mem[8] <= wd;
+ if (en && wa == 9)
+ \mem[9] <= wd;
+end
+
+always @* begin
+ rd = 16'bx;
+ if (ra == 3)
+ rd = \mem[3] ;
+ if (ra == 4)
+ rd = \mem[4] ;
+ if (ra == 5)
+ rd = \mem[5] ;
+ if (ra == 6)
+ rd = \mem[6] ;
+ if (ra == 7)
+ rd = \mem[7] ;
+ if (ra == 8)
+ rd = \mem[8] ;
+ if (ra == 9)
+ rd = \mem[9] ;
+end
+
+endmodule
+
+EOT
+
+hierarchy -auto-top
+proc
+opt_clean
+
+design -stash gold
+
+design -copy-from gold -as gold A:top
+design -copy-from gate -as gate A:top
+
+equiv_make gold gate equiv
+equiv_induct -undef equiv
+equiv_status -assert equiv
diff --git a/tests/opt/opt_clean_init.ys b/tests/opt/opt_clean_init.ys
index 0d567608d..7933f3e17 100644
--- a/tests/opt/opt_clean_init.ys
+++ b/tests/opt/opt_clean_init.ys
@@ -1,13 +1,22 @@
-logger -expect warning "Initial value conflict for \\y resolving to 1'0 but with init 1'1" 1
-logger -expect-no-warnings
-read_verilog <<EOT
-module top;
-(* init=1'b0 *) wire w = 1'b0;
-(* init=1'bx *) wire x = 1'b0;
-(* init=1'b1 *) wire y = 1'b0;
-(* init=1'b0 *) wire z = 1'bx;
+read_verilog << EOT
+module top(...);
+
+input [1:0] D;
+input C;
+output O;
+reg [1:0] Q;
+
+initial Q = 0;
+
+always @(posedge C)
+ Q <= D;
+
+assign O = Q[1];
+
endmodule
EOT
-clean
-select -assert-count 1 a:init
-select -assert-count 1 w:y a:init %i
+
+synth
+check -assert -initdrv
+
+select -assert-count 1 a:init=2'b0x
diff --git a/tests/opt/opt_clean_mem.ys b/tests/opt/opt_clean_mem.ys
new file mode 100644
index 000000000..71f9e0d7b
--- /dev/null
+++ b/tests/opt/opt_clean_mem.ys
@@ -0,0 +1,48 @@
+read_verilog <<EOT
+module top(...);
+
+input [7:0] wa;
+input [7:0] ra1;
+input [7:0] ra2;
+input [7:0] wd;
+input clk;
+wire [7:0] rd1;
+wire [7:0] rd2;
+
+reg [7:0] mem[0:7];
+
+always @(posedge clk)
+ mem[wa] <= wd;
+assign rd1 = mem[ra1];
+assign rd2 = mem[ra2];
+
+initial mem[8'h12] = 8'h34;
+
+endmodule
+EOT
+
+proc
+
+select -assert-count 2 t:$memrd
+select -assert-count 1 t:$memwr_v2
+select -assert-count 1 t:$meminit_v2
+design -save orig
+
+opt_clean
+select -assert-none t:$memrd
+select -assert-none t:$memwr_v2
+select -assert-none t:$meminit_v2
+
+design -load orig
+expose top/rd1
+opt_clean
+select -assert-count 1 t:$memrd
+select -assert-count 1 t:$memwr_v2
+select -assert-count 1 t:$meminit_v2
+
+design -load orig
+expose top/rd1 top/rd2
+opt_clean
+select -assert-count 2 t:$memrd
+select -assert-count 1 t:$memwr_v2
+select -assert-count 1 t:$meminit_v2
diff --git a/tests/opt/opt_dff_arst.ys b/tests/opt/opt_dff_arst.ys
new file mode 100644
index 000000000..2aa3b7a26
--- /dev/null
+++ b/tests/opt/opt_dff_arst.ys
@@ -0,0 +1,101 @@
+### Always-active ARST removal.
+
+read_verilog -icells <<EOT
+
+module top(...);
+
+input CLK;
+input [1:0] D;
+output [11:0] Q;
+input ARST;
+input EN;
+
+$adff #(.CLK_POLARITY(1'b1), .ARST_POLARITY(1'b1), .ARST_VALUE(2'h2), .WIDTH(2)) ff0 (.CLK(CLK), .ARST(1'b1), .D(D), .Q(Q[1:0]));
+$adffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .ARST_POLARITY(1'b0), .ARST_VALUE(2'h2), .WIDTH(2)) ff1 (.CLK(CLK), .ARST(1'b0), .EN(EN), .D(D), .Q(Q[3:2]));
+$adlatch #(.EN_POLARITY(1'b1), .ARST_POLARITY(1'b1), .ARST_VALUE(2'h2), .WIDTH(2)) ff2 (.EN(EN), .ARST(1'b1), .D(D), .Q(Q[5:4]));
+$adff #(.CLK_POLARITY(1'b1), .ARST_POLARITY(1'b1), .ARST_VALUE(2'h2), .WIDTH(2)) ff3 (.CLK(CLK), .ARST(1'bx), .D(D), .Q(Q[7:6]));
+$adffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .ARST_POLARITY(1'b0), .ARST_VALUE(2'h2), .WIDTH(2)) ff4 (.CLK(CLK), .ARST(1'bx), .EN(EN), .D(D), .Q(Q[9:8]));
+$adlatch #(.EN_POLARITY(1'b1), .ARST_POLARITY(1'b1), .ARST_VALUE(2'h2), .WIDTH(2)) ff5 (.EN(EN), .ARST(1'bx), .D(D), .Q(Q[11:10]));
+
+
+endmodule
+
+EOT
+
+design -save orig
+
+equiv_opt -undef -assert -multiclock opt_dff
+design -load postopt
+select -assert-none t:*
+
+design -load orig
+
+equiv_opt -undef -assert -multiclock opt_dff -keepdc
+design -load postopt
+select -assert-count 1 t:$adff
+select -assert-count 1 t:$adffe
+select -assert-count 1 t:$adlatch
+
+design -load orig
+simplemap
+
+equiv_opt -undef -assert -multiclock opt_dff
+design -load postopt
+select -assert-none t:*
+
+design -load orig
+simplemap
+
+equiv_opt -undef -assert -multiclock opt_dff -keepdc
+design -load postopt
+select -assert-count 2 t:$_DFF_???_
+select -assert-count 2 t:$_DFFE_????_
+select -assert-count 2 t:$_DLATCH_???_
+
+design -reset
+
+
+### Never-active ARST removal.
+
+read_verilog -icells <<EOT
+
+module top(...);
+
+input CLK;
+input [1:0] D;
+output [5:0] Q;
+input ARST;
+input EN;
+
+$adff #(.CLK_POLARITY(1'b1), .ARST_POLARITY(1'b1), .ARST_VALUE(2'h2), .WIDTH(2)) ff0 (.CLK(CLK), .ARST(1'b0), .D(D), .Q(Q[1:0]));
+$adffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .ARST_POLARITY(1'b0), .ARST_VALUE(2'h2), .WIDTH(2)) ff1 (.CLK(CLK), .ARST(1'b1), .EN(EN), .D(D), .Q(Q[3:2]));
+$adlatch #(.EN_POLARITY(1'b1), .ARST_POLARITY(1'b1), .ARST_VALUE(2'h2), .WIDTH(2)) ff2 (.EN(EN), .ARST(1'b0), .D(D), .Q(Q[5:4]));
+
+endmodule
+
+EOT
+
+design -save orig
+
+equiv_opt -undef -assert -multiclock opt_dff
+design -load postopt
+select -assert-none t:$adff
+select -assert-none t:$adffe
+select -assert-none t:$adlatch
+select -assert-count 1 t:$dff
+select -assert-count 1 t:$dffe
+select -assert-count 1 t:$dlatch
+
+design -load orig
+simplemap
+
+equiv_opt -undef -assert -multiclock opt_dff
+design -load postopt
+select -assert-none t:$_DFF_???_
+select -assert-none t:$_DFFE_????_
+select -assert-none t:$_DLATCH_???_
+select -assert-count 2 t:$_DFF_P_
+select -assert-count 2 t:$_DFFE_PP_
+select -assert-count 2 t:$_DLATCH_P_
+
+design -reset
diff --git a/tests/opt/opt_dff_clk.ys b/tests/opt/opt_dff_clk.ys
new file mode 100644
index 000000000..f3aefa406
--- /dev/null
+++ b/tests/opt/opt_dff_clk.ys
@@ -0,0 +1,45 @@
+### Never-toggling CLK removal.
+
+read_verilog -icells <<EOT
+
+module top(...);
+
+input EN;
+input [1:0] D;
+(* init = 18'h15555 *)
+output [17:0] Q;
+input SRST;
+input ARST;
+input [1:0] CLR;
+input [1:0] SET;
+
+$dff #(.CLK_POLARITY(1'b1), .WIDTH(2)) ff0 (.CLK(1'b0), .D(D), .Q(Q[1:0]));
+$dffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .WIDTH(2)) ff1 (.CLK(1'b1), .EN(EN), .D(D), .Q(Q[3:2]));
+$adff #(.CLK_POLARITY(1'b1), .ARST_POLARITY(1'b1), .ARST_VALUE(2'h2), .WIDTH(2)) ff2 (.CLK(1'bx), .ARST(ARST), .D(D), .Q(Q[5:4]));
+$adffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b0), .ARST_POLARITY(1'b1), .ARST_VALUE(2'h2), .WIDTH(2)) ff3 (.CLK(1'b0), .EN(EN), .ARST(ARST), .D(D), .Q(Q[7:6]));
+$sdff #(.CLK_POLARITY(1'b1), .SRST_POLARITY(1'b1), .SRST_VALUE(2'h2), .WIDTH(2)) ff4 (.CLK(1'b1), .SRST(SRST), .D(D), .Q(Q[9:8]));
+$sdffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .SRST_POLARITY(1'b1), .SRST_VALUE(2'h2), .WIDTH(2)) ff5 (.CLK(1'bx), .EN(EN), .SRST(SRST), .D(D), .Q(Q[11:10]));
+$sdffce #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .SRST_POLARITY(1'b1), .SRST_VALUE(2'h2), .WIDTH(2)) ff6 (.CLK(1'bx), .EN(EN), .SRST(SRST), .D(D), .Q(Q[13:12]));
+$dffsr #(.CLK_POLARITY(1'b1), .CLR_POLARITY(1'b1), .SET_POLARITY(1'b0), .WIDTH(2)) ff7 (.CLK(1'b1), .SET(SET), .CLR(CLR), .D(D), .Q(Q[15:14]));
+$dffsre #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b0), .CLR_POLARITY(1'b1), .SET_POLARITY(1'b0), .WIDTH(2)) ff8 (.CLK(1'bx), .EN(EN), .SET(SET), .CLR(CLR), .D(D), .Q(Q[17:16]));
+
+endmodule
+
+EOT
+
+design -save orig
+
+equiv_opt -undef -assert -multiclock opt_dff -keepdc
+design -load postopt
+select -assert-count 2 t:$dlatch
+select -assert-count 2 t:$sr
+select -assert-none t:$dlatch t:$sr %% %n t:* %i
+
+design -load orig
+simplemap
+
+equiv_opt -undef -assert -multiclock opt_dff -keepdc
+design -load postopt
+select -assert-count 4 t:$_DLATCH_?_
+select -assert-count 4 t:$_SR_??_
+select -assert-none t:$_DLATCH_?_ t:$_SR_??_ %% %n t:* %i
diff --git a/tests/opt/opt_dff_const.ys b/tests/opt/opt_dff_const.ys
new file mode 100644
index 000000000..6a7dec7fa
--- /dev/null
+++ b/tests/opt/opt_dff_const.ys
@@ -0,0 +1,49 @@
+### Replace FFs with a const.
+
+read_verilog -icells <<EOT
+
+module top(...);
+
+input CLK;
+input EN;
+(* init=84'haaaaaaaaaaaaaaaaaaaaa *)
+output [83:0] Q;
+input SRST;
+input ARST;
+input [3:0] CLR;
+input [3:0] SET;
+
+$dff #(.CLK_POLARITY(1'b1), .WIDTH(4)) ff0 (.CLK(CLK), .D(4'hc), .Q(Q[3:0]));
+$dffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .WIDTH(4)) ff1 (.CLK(CLK), .EN(EN), .D(4'hc), .Q(Q[7:4]));
+$adff #(.CLK_POLARITY(1'b1), .ARST_POLARITY(1'b1), .ARST_VALUE(8'hf0), .WIDTH(8)) ff2 (.CLK(CLK), .ARST(ARST), .D(8'hcc), .Q(Q[15:8]));
+$adffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b0), .ARST_POLARITY(1'b1), .ARST_VALUE(8'hf0), .WIDTH(8)) ff3 (.CLK(CLK), .EN(EN), .ARST(ARST), .D(8'hcc), .Q(Q[23:16]));
+$sdff #(.CLK_POLARITY(1'b1), .SRST_POLARITY(1'b1), .SRST_VALUE(8'hf0), .WIDTH(8)) ff4 (.CLK(CLK), .SRST(SRST), .D(8'hcc), .Q(Q[31:24]));
+$sdffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .SRST_POLARITY(1'b1), .SRST_VALUE(8'hf0), .WIDTH(8)) ff5 (.CLK(CLK), .EN(EN), .SRST(SRST), .D(8'hcc), .Q(Q[39:32]));
+$sdffce #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .SRST_POLARITY(1'b1), .SRST_VALUE(8'hf0), .WIDTH(8)) ff6 (.CLK(CLK), .EN(EN), .SRST(SRST), .D(8'hcc), .Q(Q[47:40]));
+$dffsr #(.CLK_POLARITY(1'b1), .CLR_POLARITY(1'b1), .SET_POLARITY(1'b0), .WIDTH(8)) ff7 (.CLK(CLK), .SET({SET, 4'hf}), .CLR({4'h0, CLR}), .D(8'hcc), .Q(Q[55:48]));
+$dffsre #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b0), .CLR_POLARITY(1'b0), .SET_POLARITY(1'b1), .WIDTH(8)) ff8 (.CLK(CLK), .EN(EN), .SET({SET, 4'h0}), .CLR({4'hf, CLR}), .D(8'hcc), .Q(Q[63:56]));
+
+$dlatch #(.EN_POLARITY(1'b1), .WIDTH(4)) ff9 (.EN(EN), .D(4'hc), .Q(Q[67:64]));
+$adlatch #(.EN_POLARITY(1'b0), .ARST_POLARITY(1'b1), .ARST_VALUE(8'hf0), .WIDTH(8)) ff10 (.EN(EN), .ARST(ARST), .D(8'hcc), .Q(Q[75:68]));
+$dlatchsr #(.EN_POLARITY(1'b0), .CLR_POLARITY(1'b1), .SET_POLARITY(1'b1), .WIDTH(8)) ff11 (.EN(EN), .SET({SET, 4'h0}), .CLR({4'h0, CLR}), .D(8'hcc), .Q(Q[83:76]));
+
+endmodule
+
+EOT
+
+design -save orig
+
+equiv_opt -undef -assert -multiclock opt_dff
+design -load postopt
+select -assert-count 1 t:$dff r:WIDTH=2 %i
+select -assert-count 1 t:$dffe r:WIDTH=2 %i
+select -assert-count 1 t:$adff r:WIDTH=6 %i
+select -assert-count 1 t:$adffe r:WIDTH=6 %i
+select -assert-count 1 t:$sdff r:WIDTH=6 %i
+select -assert-count 1 t:$sdffe r:WIDTH=6 %i
+select -assert-count 1 t:$sdffce r:WIDTH=6 %i
+select -assert-count 1 t:$dffsr r:WIDTH=6 %i
+select -assert-count 1 t:$dffsre r:WIDTH=6 %i
+select -assert-count 1 t:$dlatch r:WIDTH=2 %i
+select -assert-count 1 t:$adlatch r:WIDTH=6 %i
+select -assert-count 1 t:$dlatchsr r:WIDTH=6 %i
diff --git a/tests/opt/opt_dff_dffmux.ys b/tests/opt/opt_dff_dffmux.ys
new file mode 100644
index 000000000..43190cc31
--- /dev/null
+++ b/tests/opt/opt_dff_dffmux.ys
@@ -0,0 +1,129 @@
+design -reset
+read_verilog <<EOT
+module opt_dffmuxext_unsigned(input clk, ce, input [1:0] i, output reg [3:0] o);
+ always @(posedge clk) if (ce) o <= i;
+endmodule
+EOT
+
+proc
+equiv_opt -assert opt
+design -load postopt
+select -assert-count 1 t:$dffe r:WIDTH=2 %i
+select -assert-count 0 t:$dffe %% t:* %D
+
+####################
+
+design -reset
+read_verilog <<EOT
+module opt_dffmuxext_signed(input clk, ce, input signed [1:0] i, output reg signed [3:0] o);
+ always @(posedge clk) if (ce) o <= i;
+endmodule
+EOT
+
+proc
+equiv_opt -assert opt
+design -load postopt
+wreduce
+select -assert-count 1 t:$dffe r:WIDTH=2 %i
+select -assert-count 0 t:$dffe %% t:* %D
+
+###################
+
+design -reset
+read_verilog <<EOT
+module opt_dffmuxext_const(input clk, ce, input [1:0] i, output reg [5:0] o);
+ always @(posedge clk) if (ce) o <= {1'b0, i[1], 2'b1x, i[0], 1'bz};
+endmodule
+EOT
+
+proc
+equiv_opt -assert opt
+design -load postopt
+select -assert-count 1 t:$dffe r:WIDTH=2 %i
+select -assert-count 0 t:$dffe %% t:* %D
+
+###################
+
+design -reset
+read_verilog <<EOT
+module opt_dffmuxext_const_init(input clk, ce, input [1:0] i, (* init=6'b0x00x1 *) output reg [5:0] o);
+ always @(posedge clk) if (ce) o <= {1'b0, i[1], 2'b1x, i[0], 1'bz};
+endmodule
+EOT
+
+proc
+equiv_opt -assert opt
+design -load postopt
+select -assert-count 1 t:$dffe r:WIDTH=4 %i
+select -assert-count 0 t:$dffe %% t:* %D
+
+####################
+
+design -reset
+read_verilog <<EOT
+module opt_dffmuxext_unsigned_rst(input clk, ce, rst, input [1:0] i, output reg [3:0] o);
+ always @(posedge clk) if (rst) o <= 0; else if (ce) o <= i;
+endmodule
+EOT
+
+proc
+equiv_opt -assert opt
+design -load postopt
+wreduce
+select -assert-count 1 t:$sdffe r:WIDTH=2 %i
+select -assert-count 0 t:$sdffe %% t:* %D
+
+####################
+
+design -reset
+read_verilog <<EOT
+module opt_dffmuxext_signed_rst(input clk, ce, rstn, input signed [1:0] i, output reg signed [3:0] o);
+ always @(posedge clk) begin
+ if (ce) o <= i;
+ if (!rstn) o <= 4'b1111;
+ end
+endmodule
+EOT
+
+proc
+equiv_opt -assert opt
+design -load postopt
+wreduce
+select -assert-count 1 t:$sdffe r:WIDTH=2 %i
+select -assert-count 0 t:$sdffe %% t:* %D
+
+####################
+
+design -reset
+read_verilog <<EOT
+module opt_dffmuxext_signed_rst_init(input clk, ce, rstn, input signed [1:0] i, output reg signed [3:0] o);
+ initial o <= 4'b0010;
+ always @(posedge clk) begin
+ if (ce) o <= i;
+ if (!rstn) o <= 4'b1111;
+ end
+endmodule
+EOT
+
+proc
+# NB: equiv_opt uses equiv_induct which covers
+# only the induction half of temporal induction
+# --- missing the base-case half
+# This makes it akin to `sat -tempinduct-inductonly`
+# instead of `sat -tempinduct-baseonly` or
+# `sat -tempinduct` which is necessary for this
+# testcase
+#equiv_opt -assert opt
+
+design -save gold
+opt
+wreduce
+design -stash gate
+design -import gold -as gold
+design -import gate -as gate
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -tempinduct -verify -prove-asserts -show-ports miter
+
+design -load gate
+select -assert-count 1 t:$sdffe r:WIDTH=3 %i
+select -assert-count 0 t:$sdffe %% t:* %D
diff --git a/tests/opt/opt_dff_en.ys b/tests/opt/opt_dff_en.ys
new file mode 100644
index 000000000..06ee6c63d
--- /dev/null
+++ b/tests/opt/opt_dff_en.ys
@@ -0,0 +1,157 @@
+### Always-active EN removal.
+
+read_verilog -icells <<EOT
+
+module top(...);
+
+input CLK;
+input [1:0] D;
+output [15:0] Q;
+input SRST;
+input ARST;
+input [1:0] CLR;
+input [1:0] SET;
+
+$dffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .WIDTH(2)) ff0 (.CLK(CLK), .EN(1'b1), .D(D), .Q(Q[1:0]));
+$adffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b0), .ARST_POLARITY(1'b1), .ARST_VALUE(2'h2), .WIDTH(2)) ff1 (.CLK(CLK), .EN(1'b0), .ARST(ARST), .D(D), .Q(Q[3:2]));
+$sdffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .SRST_POLARITY(1'b1), .SRST_VALUE(2'h2), .WIDTH(2)) ff2 (.CLK(CLK), .EN(1'b1), .SRST(SRST), .D(D), .Q(Q[5:4]));
+$sdffce #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .SRST_POLARITY(1'b1), .SRST_VALUE(2'h2), .WIDTH(2)) ff3 (.CLK(CLK), .EN(1'b1), .SRST(SRST), .D(D), .Q(Q[7:6]));
+$dffsre #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b0), .CLR_POLARITY(1'b1), .SET_POLARITY(1'b0), .WIDTH(2)) ff4 (.CLK(CLK), .EN(1'b0), .SET(SET), .CLR(CLR), .D(D), .Q(Q[9:8]));
+
+$dlatch #(.EN_POLARITY(1'b1), .WIDTH(2)) ff5 (.EN(1'b1), .D(D), .Q(Q[11:10]));
+$adlatch #(.EN_POLARITY(1'b0), .ARST_POLARITY(1'b1), .ARST_VALUE(2'h2), .WIDTH(2)) ff6 (.EN(1'b0), .ARST(ARST), .D(D), .Q(Q[13:12]));
+$dlatchsr #(.EN_POLARITY(1'b0), .CLR_POLARITY(1'b1), .SET_POLARITY(1'b0), .WIDTH(2)) ff7 (.EN(1'b0), .SET(SET), .CLR(CLR), .D(D), .Q(Q[15:14]));
+
+endmodule
+
+EOT
+
+design -save orig
+
+# Equivalence check will fail for unmapped adlatch and dlatchsr due to negative hold hack.
+delete top/ff6 top/ff7
+equiv_opt -undef -assert -multiclock opt_dff
+
+design -load orig
+delete top/ff6 top/ff7
+simplemap
+equiv_opt -undef -assert -multiclock opt_dff
+
+design -load orig
+opt_dff
+select -assert-count 0 t:$dffe
+select -assert-count 0 t:$adffe
+select -assert-count 0 t:$sdffe
+select -assert-count 0 t:$sdffce
+select -assert-count 0 t:$dffsre
+select -assert-count 0 t:$dlatch
+select -assert-count 0 t:$adlatch
+select -assert-count 0 t:$dlatchsr
+select -assert-count 1 t:$dff
+select -assert-count 2 t:$sdff
+select -assert-count 1 t:$adff
+select -assert-count 1 t:$dffsr
+
+design -load orig
+simplemap
+opt_dff
+select -assert-count 0 t:$_DFFE_*
+select -assert-count 0 t:$_SDFFE_*
+select -assert-count 0 t:$_SDFFCE_*
+select -assert-count 0 t:$_DFFSRE_*
+select -assert-count 0 t:$_DLATCH*
+select -assert-count 2 t:$_DFF_P_
+select -assert-count 4 t:$_SDFF_PP?_
+select -assert-count 2 t:$_DFF_PP?_
+select -assert-count 2 t:$_DFFSR_PNP_
+
+design -reset
+
+
+
+### Never-active EN removal.
+
+read_verilog -icells <<EOT
+
+module top(...);
+
+input CLK;
+input [1:0] D;
+(* init = 32'h55555555 *)
+output [31:0] Q;
+input SRST;
+input ARST;
+input [1:0] CLR;
+input [1:0] SET;
+
+$dffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .WIDTH(2)) ff0 (.CLK(CLK), .EN(1'b0), .D(D), .Q(Q[1:0]));
+$adffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b0), .ARST_POLARITY(1'b1), .ARST_VALUE(2'h2), .WIDTH(2)) ff1 (.CLK(CLK), .EN(1'b1), .ARST(ARST), .D(D), .Q(Q[3:2]));
+$sdffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .SRST_POLARITY(1'b1), .SRST_VALUE(2'h2), .WIDTH(2)) ff2 (.CLK(CLK), .EN(1'b0), .SRST(SRST), .D(D), .Q(Q[5:4]));
+$sdffce #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .SRST_POLARITY(1'b1), .SRST_VALUE(2'h2), .WIDTH(2)) ff3 (.CLK(CLK), .EN(1'b0), .SRST(SRST), .D(D), .Q(Q[7:6]));
+$dffsre #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b0), .CLR_POLARITY(1'b1), .SET_POLARITY(1'b0), .WIDTH(2)) ff4 (.CLK(CLK), .EN(1'b1), .SET(SET), .CLR(CLR), .D(D), .Q(Q[9:8]));
+
+$dlatch #(.EN_POLARITY(1'b1), .WIDTH(2)) ff5 (.EN(1'b0), .D(D), .Q(Q[11:10]));
+$adlatch #(.EN_POLARITY(1'b0), .ARST_POLARITY(1'b1), .ARST_VALUE(2'h2), .WIDTH(2)) ff6 (.EN(1'b1), .ARST(ARST), .D(D), .Q(Q[13:12]));
+$dlatchsr #(.EN_POLARITY(1'b0), .CLR_POLARITY(1'b1), .SET_POLARITY(1'b0), .WIDTH(2)) ff7 (.EN(1'b1), .SET(SET), .CLR(CLR), .D(D), .Q(Q[15:14]));
+
+$dffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .WIDTH(2)) ff8 (.CLK(CLK), .EN(1'bx), .D(D), .Q(Q[17:16]));
+$adffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b0), .ARST_POLARITY(1'b1), .ARST_VALUE(2'h2), .WIDTH(2)) ff9 (.CLK(CLK), .EN(1'bx), .ARST(ARST), .D(D), .Q(Q[19:18]));
+$sdffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .SRST_POLARITY(1'b1), .SRST_VALUE(2'h2), .WIDTH(2)) ff10 (.CLK(CLK), .EN(1'bx), .SRST(SRST), .D(D), .Q(Q[21:20]));
+$sdffce #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .SRST_POLARITY(1'b1), .SRST_VALUE(2'h2), .WIDTH(2)) ff11 (.CLK(CLK), .EN(1'bx), .SRST(SRST), .D(D), .Q(Q[23:22]));
+$dffsre #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b0), .CLR_POLARITY(1'b1), .SET_POLARITY(1'b0), .WIDTH(2)) ff12 (.CLK(CLK), .EN(1'bx), .SET(SET), .CLR(CLR), .D(D), .Q(Q[25:24]));
+
+$dlatch #(.EN_POLARITY(1'b1), .WIDTH(2)) ff13 (.EN(1'bx), .D(D), .Q(Q[27:26]));
+$adlatch #(.EN_POLARITY(1'b0), .ARST_POLARITY(1'b1), .ARST_VALUE(2'h2), .WIDTH(2)) ff14 (.EN(1'bx), .ARST(ARST), .D(D), .Q(Q[29:28]));
+$dlatchsr #(.EN_POLARITY(1'b0), .CLR_POLARITY(1'b1), .SET_POLARITY(1'b0), .WIDTH(2)) ff15 (.EN(1'bx), .SET(SET), .CLR(CLR), .D(D), .Q(Q[31:30]));
+
+endmodule
+
+EOT
+
+design -save orig
+
+equiv_opt -undef -assert -multiclock opt_dff
+design -load postopt
+select -assert-count 2 t:$dffe
+select -assert-count 4 t:$dlatch
+select -assert-count 4 t:$sr
+select -assert-none t:$dffe t:$dlatch t:$sr %% %n t:* %i
+
+design -load orig
+
+equiv_opt -undef -assert -multiclock opt_dff -keepdc
+design -load postopt
+select -assert-count 2 t:$dffe
+select -assert-count 1 t:$adffe
+select -assert-count 1 t:$sdffe
+select -assert-count 1 t:$sdffce
+select -assert-count 1 t:$dffsre
+select -assert-count 3 t:$dlatch
+select -assert-count 1 t:$adlatch
+select -assert-count 1 t:$dlatchsr
+select -assert-count 2 t:$sr
+
+design -load orig
+simplemap
+
+equiv_opt -undef -assert -multiclock opt_dff
+design -load postopt
+select -assert-count 4 t:$_DFFE_??_
+select -assert-count 8 t:$_DLATCH_?_
+select -assert-count 8 t:$_SR_??_
+select -assert-none t:$_DFFE_??_ t:$_DLATCH_?_ t:$_SR_??_ %% %n t:* %i
+
+design -load orig
+simplemap
+
+equiv_opt -undef -assert -multiclock opt_dff -keepdc
+design -load postopt
+select -assert-count 4 t:$_DFFE_??_
+select -assert-count 2 t:$_DFFE_????_
+select -assert-count 2 t:$_SDFFE_????_
+select -assert-count 2 t:$_SDFFCE_????_
+select -assert-count 2 t:$_DFFSRE_????_
+select -assert-count 6 t:$_DLATCH_?_
+select -assert-count 2 t:$_DLATCH_???_
+select -assert-count 2 t:$_DLATCHSR_???_
+select -assert-count 4 t:$_SR_??_
diff --git a/tests/opt/opt_dff_mux.ys b/tests/opt/opt_dff_mux.ys
new file mode 100644
index 000000000..ed01bed59
--- /dev/null
+++ b/tests/opt/opt_dff_mux.ys
@@ -0,0 +1,86 @@
+### CE and SRST matching.
+
+read_verilog -icells <<EOT
+
+module top(...);
+
+input CLK;
+input NE, NS;
+input EN;
+output [23:0] Q;
+input [23:0] D;
+input SRST;
+input ARST;
+input [1:0] CLR;
+input [1:0] SET;
+
+$dff #(.CLK_POLARITY(1'b1), .WIDTH(2)) ff0 (.CLK(CLK), .D(NS ? 2'h2 : NE ? D[1:0] : Q[1:0]), .Q(Q[1:0]));
+$dffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .WIDTH(2)) ff1 (.CLK(CLK), .EN(EN), .D(NS ? 2'h2 : NE ? D[3:2] : Q[3:2]), .Q(Q[3:2]));
+$adff #(.CLK_POLARITY(1'b1), .ARST_POLARITY(1'b1), .ARST_VALUE(2'h2), .WIDTH(2)) ff2 (.CLK(CLK), .ARST(ARST), .D(NS ? 2'h2 : NE ? D[5:4] : Q[5:4]), .Q(Q[5:4]));
+$adffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b0), .ARST_POLARITY(1'b1), .ARST_VALUE(2'h2), .WIDTH(2)) ff3 (.CLK(CLK), .EN(EN), .ARST(ARST), .D(NS ? 2'h2 : NE ? D[7:6] : Q[7:6]), .Q(Q[7:6]));
+$sdff #(.CLK_POLARITY(1'b1), .SRST_POLARITY(1'b1), .SRST_VALUE(2'h2), .WIDTH(2)) ff4 (.CLK(CLK), .SRST(SRST), .D(NS ? 2'h2 : NE ? D[9:8] : Q[9:8]), .Q(Q[9:8]));
+$sdffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .SRST_POLARITY(1'b1), .SRST_VALUE(2'h2), .WIDTH(2)) ff5 (.CLK(CLK), .EN(EN), .SRST(SRST), .D(NS ? 2'h2 : NE ? D[11:10] : Q[11:10]), .Q(Q[11:10]));
+$sdffce #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .SRST_POLARITY(1'b1), .SRST_VALUE(2'h2), .WIDTH(2)) ff6 (.CLK(CLK), .EN(EN), .SRST(SRST), .D(NS ? 2'h2 : NE ? D[13:12] : Q[13:12]), .Q(Q[13:12]));
+$dffsr #(.CLK_POLARITY(1'b1), .CLR_POLARITY(1'b1), .SET_POLARITY(1'b0), .WIDTH(2)) ff7 (.CLK(CLK), .SET(SET), .CLR(CLR), .D(NS ? 2'h2 : NE ? D[15:14] : Q[15:14]), .Q(Q[15:14]));
+$dffsre #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b0), .CLR_POLARITY(1'b1), .SET_POLARITY(1'b0), .WIDTH(2)) ff8 (.CLK(CLK), .EN(EN), .SET(SET), .CLR(CLR), .D(NS ? 2'h2 : NE ? D[17:16] : Q[17:16]), .Q(Q[17:16]));
+
+endmodule
+
+EOT
+
+design -save orig
+
+equiv_opt -undef -assert -multiclock opt_dff -keepdc
+design -load postopt
+clean
+select -assert-count 0 t:$dff
+select -assert-count 0 t:$dffe
+select -assert-count 0 t:$adff
+select -assert-count 2 t:$adffe
+select -assert-count 0 t:$dffsr
+select -assert-count 2 t:$dffsre
+select -assert-count 0 t:$sdff
+select -assert-count 3 t:$sdffe
+select -assert-count 2 t:$sdffce
+
+design -load orig
+
+equiv_opt -undef -assert -multiclock opt_dff -nodffe -nosdff
+design -load postopt
+clean
+select -assert-count 1 t:$dff
+select -assert-count 1 t:$dffe
+select -assert-count 1 t:$adff
+select -assert-count 1 t:$adffe
+select -assert-count 1 t:$dffsr
+select -assert-count 1 t:$dffsre
+select -assert-count 1 t:$sdff
+select -assert-count 1 t:$sdffe
+select -assert-count 1 t:$sdffce
+equiv_opt -undef -assert -multiclock opt_dff -nodffe
+design -load postopt
+clean
+select -assert-count 0 t:$dff
+select -assert-count 0 t:$dffe
+select -assert-count 1 t:$adff
+select -assert-count 1 t:$adffe
+select -assert-count 1 t:$dffsr
+select -assert-count 1 t:$dffsre
+select -assert-count 2 t:$sdff
+select -assert-count 1 t:$sdffe
+select -assert-count 2 t:$sdffce
+
+design -load orig
+
+equiv_opt -undef -assert -multiclock opt_dff -nosdff
+design -load postopt
+clean
+select -assert-count 0 t:$dff
+select -assert-count 2 t:$dffe
+select -assert-count 0 t:$adff
+select -assert-count 2 t:$adffe
+select -assert-count 0 t:$dffsr
+select -assert-count 2 t:$dffsre
+select -assert-count 0 t:$sdff
+select -assert-count 2 t:$sdffe
+select -assert-count 1 t:$sdffce
diff --git a/tests/opt/opt_dff_qd.ys b/tests/opt/opt_dff_qd.ys
new file mode 100644
index 000000000..afc96c42f
--- /dev/null
+++ b/tests/opt/opt_dff_qd.ys
@@ -0,0 +1,56 @@
+### Q = D case.
+
+read_verilog -icells <<EOT
+
+module top(...);
+
+input CLK;
+input EN;
+(* init = 24'h555555 *)
+output [23:0] Q;
+input SRST;
+input ARST;
+input [1:0] CLR;
+input [1:0] SET;
+
+$dff #(.CLK_POLARITY(1'b1), .WIDTH(2)) ff0 (.CLK(CLK), .D(Q[1:0]), .Q(Q[1:0]));
+$dffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .WIDTH(2)) ff1 (.CLK(CLK), .EN(EN), .D(Q[3:2]), .Q(Q[3:2]));
+$adff #(.CLK_POLARITY(1'b1), .ARST_POLARITY(1'b1), .ARST_VALUE(2'h2), .WIDTH(2)) ff2 (.CLK(CLK), .ARST(ARST), .D(Q[5:4]), .Q(Q[5:4]));
+$adffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b0), .ARST_POLARITY(1'b1), .ARST_VALUE(2'h2), .WIDTH(2)) ff3 (.CLK(CLK), .EN(EN), .ARST(ARST), .D(Q[7:6]), .Q(Q[7:6]));
+$sdff #(.CLK_POLARITY(1'b1), .SRST_POLARITY(1'b1), .SRST_VALUE(2'h2), .WIDTH(2)) ff4 (.CLK(CLK), .SRST(SRST), .D(Q[9:8]), .Q(Q[9:8]));
+$sdffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .SRST_POLARITY(1'b1), .SRST_VALUE(2'h2), .WIDTH(2)) ff5 (.CLK(CLK), .EN(EN), .SRST(SRST), .D(Q[11:10]), .Q(Q[11:10]));
+$sdffce #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .SRST_POLARITY(1'b1), .SRST_VALUE(2'h2), .WIDTH(2)) ff6 (.CLK(CLK), .EN(EN), .SRST(SRST), .D(Q[13:12]), .Q(Q[13:12]));
+$dffsr #(.CLK_POLARITY(1'b1), .CLR_POLARITY(1'b1), .SET_POLARITY(1'b0), .WIDTH(2)) ff7 (.CLK(CLK), .SET(SET), .CLR(CLR), .D(Q[15:14]), .Q(Q[15:14]));
+$dffsre #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b0), .CLR_POLARITY(1'b1), .SET_POLARITY(1'b0), .WIDTH(2)) ff8 (.CLK(CLK), .EN(EN), .SET(SET), .CLR(CLR), .D(Q[17:16]), .Q(Q[17:16]));
+
+$dlatch #(.EN_POLARITY(1'b1), .WIDTH(2)) ff9 (.EN(EN), .D(Q[19:18]), .Q(Q[19:18]));
+$adlatch #(.EN_POLARITY(1'b0), .ARST_POLARITY(1'b1), .ARST_VALUE(2'h2), .WIDTH(2)) ff10 (.EN(EN), .ARST(ARST), .D(Q[21:20]), .Q(Q[21:20]));
+$dlatchsr #(.EN_POLARITY(1'b0), .CLR_POLARITY(1'b1), .SET_POLARITY(1'b0), .WIDTH(2)) ff11 (.EN(EN), .SET(SET), .CLR(CLR), .D(Q[23:22]), .Q(Q[23:22]));
+
+endmodule
+
+EOT
+
+design -save orig
+
+# Equivalence check will fail for unmapped adlatch and dlatchsr due to negative hold hack.
+delete top/ff10 top/ff11
+equiv_opt -undef -assert -multiclock opt_dff -keepdc
+
+design -load orig
+opt_dff -keepdc
+select -assert-count 1 t:$and
+select -assert-count 3 t:$dffe
+select -assert-count 3 t:$dlatch
+select -assert-count 3 t:$sr
+select -assert-none t:$and t:$dffe t:$dlatch t:$sr %% %n t:* %i
+
+design -load orig
+simplemap
+opt_dff -keepdc
+select -assert-count 2 t:$_AND_
+select -assert-count 6 t:$_DFFE_??_
+select -assert-count 6 t:$_DLATCH_?_
+select -assert-count 6 t:$_SR_??_
+select -assert-none t:$_AND_ t:$_DFFE_??_ t:$_DLATCH_?_ t:$_SR_??_ %% %n t:* %i
+
diff --git a/tests/opt/opt_dff_sr.ys b/tests/opt/opt_dff_sr.ys
new file mode 100644
index 000000000..0961cb11e
--- /dev/null
+++ b/tests/opt/opt_dff_sr.ys
@@ -0,0 +1,309 @@
+### Always-active SET/CLR removal.
+
+read_verilog -icells <<EOT
+
+module top(...);
+
+input CLK;
+input [5:0] D;
+output [23:0] Q;
+input CLR;
+input SET;
+input EN;
+
+$dffsr #(.CLK_POLARITY(1'b1), .SET_POLARITY(1'b1), .CLR_POLARITY(1'b1), .WIDTH(6)) ff0 (.CLK(CLK), .CLR({CLR, CLR, CLR, 1'b1, 1'b0, 1'bx}), .SET({1'b1, 1'b0, 1'bx, SET, SET, SET}), .D(D), .Q(Q[5:0]));
+$dffsre #(.CLK_POLARITY(1'b1), .SET_POLARITY(1'b0), .CLR_POLARITY(1'b0), .EN_POLARITY(1'b1), .WIDTH(6)) ff1 (.CLK(CLK), .EN(EN), .CLR({CLR, CLR, CLR, 1'b1, 1'b0, 1'bx}), .SET({1'b1, 1'b0, 1'bx, SET, SET, SET}), .D(D), .Q(Q[11:6]));
+$dlatchsr #(.SET_POLARITY(1'b0), .CLR_POLARITY(1'b1), .EN_POLARITY(1'b1), .WIDTH(6)) ff2 (.EN(EN), .CLR({CLR, CLR, CLR, 1'b1, 1'b0, 1'bx}), .SET({1'b1, 1'b0, 1'bx, SET, SET, SET}), .D(D), .Q(Q[17:12]));
+$sr #(.SET_POLARITY(1'b1), .CLR_POLARITY(1'b0), .WIDTH(6)) ff3 (.CLR({CLR, CLR, CLR, 1'b1, 1'b0, 1'bx}), .SET({1'b1, 1'b0, 1'bx, SET, SET, SET}), .Q(Q[23:18]));
+
+endmodule
+
+EOT
+
+design -save orig
+
+# Equivalence check will fail for unmapped adlatch and dlatchsr due to negative hold hack.
+#equiv_opt -undef -assert -multiclock opt_dff
+#design -load postopt
+opt_dff
+select -assert-count 1 t:$dffsr
+select -assert-count 1 t:$dffsr r:WIDTH=2 %i
+select -assert-count 1 t:$dffsre
+select -assert-count 1 t:$dffsre r:WIDTH=2 %i
+select -assert-count 1 t:$dlatchsr
+select -assert-count 1 t:$dlatchsr r:WIDTH=2 %i
+select -assert-none t:$sr
+
+design -load orig
+
+#equiv_opt -undef -assert -multiclock opt_dff -keepdc
+#design -load postopt
+opt_dff -keepdc
+select -assert-count 1 t:$dffsr
+select -assert-count 1 t:$dffsr r:WIDTH=4 %i
+select -assert-count 1 t:$dffsre
+select -assert-count 1 t:$dffsre r:WIDTH=4 %i
+select -assert-count 1 t:$dlatchsr
+select -assert-count 1 t:$dlatchsr r:WIDTH=4 %i
+select -assert-count 1 t:$sr
+select -assert-count 1 t:$sr r:WIDTH=4 %i
+
+design -load orig
+simplemap
+
+#equiv_opt -undef -assert -multiclock opt_dff
+#design -load postopt
+opt_dff
+select -assert-count 1 t:$_DFF_PP0_
+select -assert-count 1 t:$_DFF_PP1_
+select -assert-count 1 t:$_DFFE_PN0P_
+select -assert-count 1 t:$_DFFE_PN1P_
+select -assert-count 1 t:$_DLATCH_PP0_
+select -assert-count 1 t:$_DLATCH_PN1_
+select -assert-none t:$_DFF_PP0_ t:$_DFF_PP1_ t:$_DFFE_PN0P_ t:$_DFFE_PN1P_ t:$_DLATCH_PP0_ t:$_DLATCH_PN1_ t:$_NOT_ %% %n t:* %i
+
+design -load orig
+simplemap
+
+#equiv_opt -undef -assert -multiclock opt_dff -keepdc
+#design -load postopt
+opt_dff -keepdc
+select -assert-count 1 t:$_DFF_PP0_
+select -assert-count 1 t:$_DFF_PP1_
+select -assert-count 2 t:$_DFFSR_PPP_
+select -assert-count 1 t:$_DFFE_PN0P_
+select -assert-count 1 t:$_DFFE_PN1P_
+select -assert-count 2 t:$_DFFSRE_PNNP_
+select -assert-count 1 t:$_DLATCH_PP0_
+select -assert-count 1 t:$_DLATCH_PN1_
+select -assert-count 2 t:$_DLATCHSR_PNP_
+select -assert-count 1 t:$_DLATCH_P_
+select -assert-count 1 t:$_DLATCH_N_
+select -assert-count 2 t:$_SR_PN_
+select -assert-none t:$_DFF_PP0_ t:$_DFF_PP1_ t:$_DFFSR_PPP_ t:$_DFFE_PN0P_ t:$_DFFE_PN1P_ t:$_DFFSRE_PNNP_ t:$_DLATCH_PP0_ t:$_DLATCH_PN1_ t:$_DLATCHSR_PNP_ t:$_NOT_ t:$_DLATCH_N_ t:$_DLATCH_P_ t:$_SR_PN_ %% %n t:* %i
+
+design -reset
+
+
+
+### Never-active CLR removal.
+
+read_verilog -icells <<EOT
+
+module top(...);
+
+input CLK;
+input [5:0] D;
+output [23:0] Q;
+input CLR;
+input SET;
+input EN;
+
+$dffsr #(.CLK_POLARITY(1'b1), .SET_POLARITY(1'b1), .CLR_POLARITY(1'b1), .WIDTH(6)) ff0 (.CLK(CLK), .CLR(6'h00), .SET({6{SET}}), .D(D), .Q(Q[5:0]));
+$dffsre #(.CLK_POLARITY(1'b1), .SET_POLARITY(1'b0), .CLR_POLARITY(1'b0), .EN_POLARITY(1'b1), .WIDTH(6)) ff1 (.CLK(CLK), .EN(EN), .D(D), .CLR(6'h3f), .SET({6{SET}}), .Q(Q[11:6]));
+$dlatchsr #(.SET_POLARITY(1'b0), .CLR_POLARITY(1'b1), .EN_POLARITY(1'b1), .WIDTH(6)) ff2 (.EN(EN), .D(D), .CLR(6'h00), .SET({6{SET}}), .Q(Q[17:12]));
+$sr #(.SET_POLARITY(1'b1), .CLR_POLARITY(1'b0), .WIDTH(6)) ff3 (.CLR(6'h3f), .SET({6{SET}}), .Q(Q[23:18]));
+
+endmodule
+
+EOT
+
+design -save orig
+
+equiv_opt -undef -assert -multiclock opt_dff -keepdc
+design -load postopt
+select -assert-count 0 t:$dffsr
+select -assert-count 0 t:$dffsre
+select -assert-count 0 t:$dlatchsr
+select -assert-count 0 t:$sr
+select -assert-count 1 t:$adff
+select -assert-count 1 t:$adffe
+select -assert-count 1 t:$adlatch
+select -assert-count 1 t:$dlatch
+
+design -reset
+
+
+
+### Never-active CLR removal (not applicable).
+
+read_verilog -icells <<EOT
+
+module top(...);
+
+input CLK;
+input [5:0] D;
+output [23:0] Q;
+input CLR;
+input SET;
+input ALT;
+input EN;
+
+$dffsr #(.CLK_POLARITY(1'b1), .SET_POLARITY(1'b1), .CLR_POLARITY(1'b1), .WIDTH(6)) ff0 (.CLK(CLK), .CLR(6'h00), .SET({{5{SET}}, ALT}), .D(D), .Q(Q[5:0]));
+$dffsre #(.CLK_POLARITY(1'b1), .SET_POLARITY(1'b0), .CLR_POLARITY(1'b0), .EN_POLARITY(1'b1), .WIDTH(6)) ff1 (.CLK(CLK), .EN(EN), .D(D), .CLR(6'h3f), .SET({{5{SET}}, ALT}), .Q(Q[11:6]));
+$dlatchsr #(.SET_POLARITY(1'b0), .CLR_POLARITY(1'b1), .EN_POLARITY(1'b1), .WIDTH(6)) ff2 (.EN(EN), .D(D), .CLR(6'h00), .SET({{5{SET}}, ALT}), .Q(Q[17:12]));
+$sr #(.SET_POLARITY(1'b1), .CLR_POLARITY(1'b0), .WIDTH(6)) ff3 (.CLR(6'h3f), .SET({{5{SET}}, ALT}), .Q(Q[23:18]));
+
+endmodule
+
+EOT
+
+design -save orig
+
+equiv_opt -undef -assert -multiclock opt_dff -keepdc
+design -load postopt
+select -assert-count 1 t:$dffsr
+select -assert-count 1 t:$dffsre
+select -assert-count 1 t:$dlatchsr
+select -assert-count 1 t:$sr
+select -assert-count 0 t:$adff
+select -assert-count 0 t:$adffe
+select -assert-count 0 t:$adlatch
+select -assert-count 0 t:$dlatch
+
+design -load orig
+simplemap
+
+equiv_opt -undef -assert -multiclock opt_dff -keepdc
+design -load postopt
+select -assert-count 0 t:$_DFFSR_*
+select -assert-count 0 t:$_DFFSRE_*
+select -assert-count 0 t:$_DLATCHSR_*
+select -assert-count 0 t:$_SR_*
+select -assert-count 6 t:$_DFF_PP1_
+select -assert-count 6 t:$_DFFE_PN1P_
+select -assert-count 6 t:$_DLATCH_PN1_
+select -assert-count 6 t:$_DLATCH_P_
+
+design -reset
+
+
+
+### Never-active SET removal.
+
+read_verilog -icells <<EOT
+
+module top(...);
+
+input CLK;
+input [5:0] D;
+output [23:0] Q;
+input CLR;
+input SET;
+input EN;
+
+$dffsr #(.CLK_POLARITY(1'b1), .SET_POLARITY(1'b1), .CLR_POLARITY(1'b1), .WIDTH(6)) ff0 (.CLK(CLK), .CLR({6{CLR}}), .SET(6'h00), .D(D), .Q(Q[5:0]));
+$dffsre #(.CLK_POLARITY(1'b1), .SET_POLARITY(1'b0), .CLR_POLARITY(1'b0), .EN_POLARITY(1'b1), .WIDTH(6)) ff1 (.CLK(CLK), .EN(EN), .D(D), .CLR({6{CLR}}), .SET(6'h3f), .Q(Q[11:6]));
+$dlatchsr #(.SET_POLARITY(1'b0), .CLR_POLARITY(1'b1), .EN_POLARITY(1'b1), .WIDTH(6)) ff2 (.EN(EN), .D(D), .CLR({6{CLR}}), .SET(6'h3f), .Q(Q[17:12]));
+$sr #(.SET_POLARITY(1'b1), .CLR_POLARITY(1'b0), .WIDTH(6)) ff3 (.CLR({6{CLR}}), .SET(6'h00), .Q(Q[23:18]));
+
+endmodule
+
+EOT
+
+design -save orig
+
+equiv_opt -undef -assert -multiclock opt_dff -keepdc
+design -load postopt
+select -assert-count 0 t:$dffsr
+select -assert-count 0 t:$dffsre
+select -assert-count 0 t:$dlatchsr
+select -assert-count 0 t:$sr
+select -assert-count 1 t:$adff
+select -assert-count 1 t:$adffe
+select -assert-count 1 t:$adlatch
+select -assert-count 1 t:$dlatch
+
+design -reset
+
+
+
+### Never-active CLR removal (not applicable).
+
+read_verilog -icells <<EOT
+
+module top(...);
+
+input CLK;
+input [5:0] D;
+output [23:0] Q;
+input CLR;
+input SET;
+input ALT;
+input EN;
+
+$dffsr #(.CLK_POLARITY(1'b1), .SET_POLARITY(1'b1), .CLR_POLARITY(1'b1), .WIDTH(6)) ff0 (.CLK(CLK), .CLR({{5{CLR}}, ALT}), .SET(6'h00), .D(D), .Q(Q[5:0]));
+$dffsre #(.CLK_POLARITY(1'b1), .SET_POLARITY(1'b0), .CLR_POLARITY(1'b0), .EN_POLARITY(1'b1), .WIDTH(6)) ff1 (.CLK(CLK), .EN(EN), .D(D), .CLR({{5{CLR}}, ALT}), .SET(6'h3f), .Q(Q[11:6]));
+$dlatchsr #(.SET_POLARITY(1'b0), .CLR_POLARITY(1'b1), .EN_POLARITY(1'b1), .WIDTH(6)) ff2 (.EN(EN), .D(D), .CLR({{5{CLR}}, ALT}), .SET(6'h3f), .Q(Q[17:12]));
+$sr #(.SET_POLARITY(1'b1), .CLR_POLARITY(1'b0), .WIDTH(6)) ff3 (.CLR({{5{CLR}}, ALT}), .SET(6'h00), .Q(Q[23:18]));
+
+endmodule
+
+EOT
+
+design -save orig
+
+equiv_opt -undef -assert -multiclock opt_dff -keepdc
+design -load postopt
+select -assert-count 1 t:$dffsr
+select -assert-count 1 t:$dffsre
+select -assert-count 1 t:$dlatchsr
+select -assert-count 1 t:$sr
+select -assert-count 0 t:$adff
+select -assert-count 0 t:$adffe
+select -assert-count 0 t:$adlatch
+select -assert-count 0 t:$dlatch
+
+design -load orig
+simplemap
+
+equiv_opt -undef -assert -multiclock opt_dff -keepdc
+design -load postopt
+select -assert-count 0 t:$_DFFSR_*
+select -assert-count 0 t:$_DFFSRE_*
+select -assert-count 0 t:$_DLATCHSR_*
+select -assert-count 0 t:$_SR_*
+select -assert-count 6 t:$_DFF_PP0_
+select -assert-count 6 t:$_DFFE_PN0P_
+select -assert-count 6 t:$_DLATCH_PP0_
+select -assert-count 6 t:$_DLATCH_N_
+
+design -reset
+
+
+
+### SET/CLR merge into ARST.
+
+read_verilog -icells <<EOT
+
+module top(...);
+
+input CLK;
+input [5:0] D;
+output [23:0] Q;
+input ARST;
+input EN;
+
+$dffsr #(.CLK_POLARITY(1'b1), .SET_POLARITY(1'b1), .CLR_POLARITY(1'b1), .WIDTH(6)) ff0 (.CLK(CLK), .CLR({ARST, 5'h00}), .SET({1'b0, {5{ARST}}}), .D(D), .Q(Q[5:0]));
+$dffsre #(.CLK_POLARITY(1'b1), .SET_POLARITY(1'b0), .CLR_POLARITY(1'b0), .EN_POLARITY(1'b1), .WIDTH(6)) ff1 (.CLK(CLK), .EN(EN), .D(D), .CLR({ARST, 5'h1f}), .SET({1'b1, {5{ARST}}}), .Q(Q[11:6]));
+$dlatchsr #(.SET_POLARITY(1'b0), .CLR_POLARITY(1'b1), .EN_POLARITY(1'b1), .WIDTH(6)) ff2 (.EN(EN), .D(D), .CLR({ARST, 5'h00}), .SET({1'b1, {5{ARST}}}), .Q(Q[17:12]));
+$sr #(.SET_POLARITY(1'b1), .CLR_POLARITY(1'b0), .WIDTH(6)) ff3 (.CLR({ARST, 5'h1f}), .SET({1'b0, {5{ARST}}}), .Q(Q[23:18]));
+
+endmodule
+
+EOT
+
+design -save orig
+
+equiv_opt -undef -assert -multiclock opt_dff -keepdc
+design -load postopt
+select -assert-count 0 t:$dffsr
+select -assert-count 0 t:$dffsre
+select -assert-count 1 t:$dlatchsr
+select -assert-count 1 t:$sr
+select -assert-count 1 t:$adff
+select -assert-count 1 t:$adff r:ARST_VALUE=6'h1f %i
+select -assert-count 1 t:$adffe
+select -assert-count 1 t:$adffe r:ARST_VALUE=6'h1f %i
+select -assert-count 0 t:$adlatch
+select -assert-count 0 t:$dlatch
diff --git a/tests/opt/opt_dff_srst.ys b/tests/opt/opt_dff_srst.ys
new file mode 100644
index 000000000..4a77de0b8
--- /dev/null
+++ b/tests/opt/opt_dff_srst.ys
@@ -0,0 +1,113 @@
+### Always-active SRST removal.
+
+read_verilog -icells <<EOT
+
+module top(...);
+
+input CLK;
+input [1:0] D;
+(* init=12'h555 *)
+output [11:0] Q;
+input SRST;
+input EN;
+
+$sdff #(.CLK_POLARITY(1'b1), .SRST_POLARITY(1'b1), .SRST_VALUE(2'h2), .WIDTH(2)) ff0 (.CLK(CLK), .SRST(1'b1), .D(D), .Q(Q[1:0]));
+$sdffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .SRST_POLARITY(1'b0), .SRST_VALUE(2'h2), .WIDTH(2)) ff1 (.CLK(CLK), .SRST(1'b0), .EN(EN), .D(D), .Q(Q[3:2]));
+$sdffce #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .SRST_POLARITY(1'b0), .SRST_VALUE(2'h2), .WIDTH(2)) ff2 (.CLK(CLK), .SRST(1'b0), .EN(EN), .D(D), .Q(Q[5:4]));
+$sdff #(.CLK_POLARITY(1'b1), .SRST_POLARITY(1'b1), .SRST_VALUE(2'h2), .WIDTH(2)) ff3 (.CLK(CLK), .SRST(1'bx), .D(D), .Q(Q[7:6]));
+$sdffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .SRST_POLARITY(1'b0), .SRST_VALUE(2'h2), .WIDTH(2)) ff4 (.CLK(CLK), .SRST(1'bx), .EN(EN), .D(D), .Q(Q[9:8]));
+$sdffce #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .SRST_POLARITY(1'b0), .SRST_VALUE(2'h2), .WIDTH(2)) ff5 (.CLK(CLK), .SRST(1'bx), .EN(EN), .D(D), .Q(Q[11:10]));
+
+
+endmodule
+
+EOT
+
+design -save orig
+
+equiv_opt -undef -assert -multiclock opt_dff
+design -load postopt
+select -assert-count 0 t:$sdff
+select -assert-count 0 t:$sdffe
+select -assert-count 0 t:$sdffce
+select -assert-count 4 t:$dff
+select -assert-count 2 t:$dffe
+
+design -load orig
+
+equiv_opt -undef -assert -multiclock opt_dff -keepdc
+design -load postopt
+select -assert-count 1 t:$sdff
+select -assert-count 1 t:$sdffe
+select -assert-count 1 t:$sdffce
+select -assert-count 2 t:$dff
+select -assert-count 1 t:$dffe
+
+design -load orig
+simplemap
+
+equiv_opt -undef -assert -multiclock opt_dff
+design -load postopt
+select -assert-none t:$_SDFF_???_
+select -assert-none t:$_SDFFE_????_
+select -assert-none t:$_SDFFCE_????_
+select -assert-count 8 t:$_DFF_?_
+select -assert-count 4 t:$_DFFE_??_
+
+design -load orig
+simplemap
+
+equiv_opt -undef -assert -multiclock opt_dff -keepdc
+design -load postopt
+select -assert-count 2 t:$_SDFF_???_
+select -assert-count 2 t:$_SDFFE_????_
+select -assert-count 2 t:$_SDFFCE_????_
+select -assert-count 4 t:$_DFF_?_
+select -assert-count 2 t:$_DFFE_??_
+
+design -reset
+
+
+### Never-active SRST removal.
+
+read_verilog -icells <<EOT
+
+module top(...);
+
+input CLK;
+input [1:0] D;
+output [5:0] Q;
+input SRST;
+input EN;
+
+$sdff #(.CLK_POLARITY(1'b1), .SRST_POLARITY(1'b1), .SRST_VALUE(2'h2), .WIDTH(2)) ff0 (.CLK(CLK), .SRST(1'b0), .D(D), .Q(Q[1:0]));
+$sdffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .SRST_POLARITY(1'b0), .SRST_VALUE(2'h2), .WIDTH(2)) ff1 (.CLK(CLK), .SRST(1'b1), .EN(EN), .D(D), .Q(Q[3:2]));
+$sdffce #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .SRST_POLARITY(1'b0), .SRST_VALUE(2'h2), .WIDTH(2)) ff2 (.CLK(CLK), .SRST(1'b1), .EN(EN), .D(D), .Q(Q[5:4]));
+
+endmodule
+
+EOT
+
+design -save orig
+
+equiv_opt -undef -assert -multiclock opt_dff
+design -load postopt
+select -assert-none t:$sdff
+select -assert-none t:$sdffe
+select -assert-none t:$sdffce
+select -assert-count 1 t:$dff
+select -assert-count 2 t:$dffe
+
+design -load orig
+simplemap
+
+equiv_opt -undef -assert -multiclock opt_dff
+design -load postopt
+select -assert-none t:$_SDFF_???_
+select -assert-none t:$_SDFFE_????_
+select -assert-none t:$_SDFFCE_????_
+select -assert-count 2 t:$_DFF_P_
+select -assert-count 4 t:$_DFFE_PP_
+
+design -reset
+
diff --git a/tests/opt/opt_expr_constconn.v b/tests/opt/opt_expr_constconn.v
new file mode 100644
index 000000000..d18b120e3
--- /dev/null
+++ b/tests/opt/opt_expr_constconn.v
@@ -0,0 +1,8 @@
+module top(...);
+
+input [7:0] A;
+output [7:0] B;
+wire [7:0] C = 3;
+assign B = A + C;
+
+endmodule
diff --git a/tests/opt/opt_expr_constconn.ys b/tests/opt/opt_expr_constconn.ys
new file mode 100644
index 000000000..9dd848a4b
--- /dev/null
+++ b/tests/opt/opt_expr_constconn.ys
@@ -0,0 +1,7 @@
+read_verilog opt_expr_constconn.v
+select -assert-count 1 t:$add
+select -assert-count 1 t:$add %ci w:C %i
+equiv_opt -assert opt_expr
+design -load postopt
+select -assert-count 1 t:$add
+select -assert-count 0 t:$add %ci w:C %i
diff --git a/tests/opt/opt_mem_feedback.ys b/tests/opt/opt_mem_feedback.ys
new file mode 100644
index 000000000..06d6e7e77
--- /dev/null
+++ b/tests/opt/opt_mem_feedback.ys
@@ -0,0 +1,189 @@
+# Good case: proper feedback port.
+
+read_verilog << EOT
+
+module top(...);
+
+input clk;
+input en;
+input s;
+
+input [3:0] ra;
+output [15:0] rd;
+input [3:0] wa;
+input [15:0] wd;
+
+reg [15:0] mem[0:15];
+
+assign rd = mem[ra];
+
+always @(posedge clk) begin
+ if (en) begin
+ mem[wa] <= {mem[wa][15:8], s ? wd[7:0] : mem[wa][7:0]};
+ end
+end
+
+endmodule
+
+EOT
+
+hierarchy -auto-top
+proc
+opt_clean
+
+design -save start
+memory_map
+design -save preopt
+
+design -load start
+opt_mem_feedback
+select -assert-count 1 t:$memrd_v2
+memory_map
+design -save postopt
+
+equiv_opt -assert -run prepare: :
+
+
+
+design -reset
+
+# Bad case: read port also used for other things.
+
+read_verilog << EOT
+
+module top(...);
+
+input clk;
+input en;
+input s;
+
+output [15:0] rd;
+input [3:0] wa;
+input [15:0] wd;
+
+reg [15:0] mem[0:15];
+
+assign rd = mem[wa];
+
+always @(posedge clk) begin
+ if (en) begin
+ mem[wa] <= {s ? rd : wd[15:8], s ? wd[7:0] : rd};
+ end
+end
+
+endmodule
+
+EOT
+
+hierarchy -auto-top
+proc
+opt_clean
+
+design -save start
+memory_map
+design -save preopt
+
+design -load start
+select -assert-count 1 t:$memrd
+opt_mem_feedback
+select -assert-count 1 t:$memrd
+memory_map
+design -save postopt
+
+equiv_opt -assert -run prepare: :
+
+
+
+design -reset
+
+# Bad case: another user of the mux out.
+
+read_verilog << EOT
+
+module top(...);
+
+input clk;
+input en;
+input s;
+
+output [15:0] rd;
+input [3:0] wa;
+input [15:0] wd;
+
+reg [15:0] mem[0:15];
+
+assign rd = s ? wd : mem[wa];
+
+always @(posedge clk) begin
+ if (en) begin
+ mem[wa] <= rd;
+ end
+end
+
+endmodule
+
+EOT
+
+hierarchy -auto-top
+proc
+opt_clean
+
+design -save start
+memory_map
+design -save preopt
+
+design -load start
+select -assert-count 1 t:$memrd
+opt_mem_feedback
+select -assert-count 1 t:$memrd
+memory_map
+design -save postopt
+
+equiv_opt -assert -run prepare: :
+
+
+
+design -reset
+
+# Tricky case: legit feedback path, but priority needs to be preserved.
+
+read_verilog << EOT
+
+module top(...);
+
+input clk;
+input sel;
+input [3:0] wa1;
+input [3:0] wa2;
+input [15:0] wd1;
+input [3:0] ra;
+output [15:0] rd;
+
+reg [15:0] mem [0:15];
+
+always @(posedge clk) begin
+ mem[wa1] <= sel ? wd1 : mem[wa1];
+ mem[wa2] <= mem[wa2];
+end
+
+assign rd = mem[ra];
+
+endmodule
+
+EOT
+
+hierarchy -auto-top
+proc
+opt_clean
+
+design -save start
+memory_map
+design -save preopt
+
+design -load start
+opt_mem_feedback
+select -assert-count 1 t:$memrd_v2
+memory_map
+design -save postopt
+
+equiv_opt -assert -run prepare: :
diff --git a/tests/opt/opt_mem_priority.ys b/tests/opt/opt_mem_priority.ys
new file mode 100644
index 000000000..a4119e12a
--- /dev/null
+++ b/tests/opt/opt_mem_priority.ys
@@ -0,0 +1,209 @@
+# Bad case: independent write ports.
+
+read_verilog << EOT
+
+module top(
+ input [3:0] wa1, wa2, ra, wd1, wd2,
+ input clk, we1, we2,
+ output [3:0] rd);
+
+reg [3:0] mem[0:15];
+assign rd = mem[ra];
+
+always @(posedge clk) begin
+ if (we1)
+ mem[wa1] <= wd1;
+ if (we2)
+ mem[wa2] <= wd2;
+end
+
+endmodule
+
+EOT
+
+hierarchy -auto-top
+proc
+opt
+memory -nomap
+select -assert-count 1 t:$mem_v2
+select -assert-count 1 t:$mem_v2 r:WR_PRIORITY_MASK=4'b0100 %i
+
+
+design -reset
+
+# Good case: write ports with definitely different addresses.
+
+read_verilog << EOT
+
+module top(
+ input [3:0] wa, ra, wd1, wd2,
+ input clk, we1, we2,
+ output [3:0] rd);
+
+reg [3:0] mem[0:15];
+assign rd = mem[ra];
+
+always @(posedge clk) begin
+ if (we1)
+ mem[wa] <= wd1;
+ if (we2)
+ mem[wa ^ 1] <= wd2;
+end
+
+endmodule
+
+EOT
+
+hierarchy -auto-top
+proc
+opt
+memory -nomap
+select -assert-count 1 t:$mem_v2
+select -assert-count 1 t:$mem_v2 r:WR_PRIORITY_MASK=4'b0000 %i
+
+
+design -reset
+
+# Bad case 2: the above, but broken.
+
+read_verilog << EOT
+
+module top(
+ input [3:0] wa, ra, wd1, wd2,
+ input clk, we1, we2,
+ output [3:0] rd);
+
+reg [3:0] mem[0:15];
+assign rd = mem[ra];
+
+always @(posedge clk) begin
+ if (we1)
+ mem[wa] <= wd1;
+ if (we2)
+ mem[wa | 1] <= wd2;
+end
+
+endmodule
+
+EOT
+
+hierarchy -auto-top
+proc
+opt
+memory -nomap
+select -assert-count 1 t:$mem_v2
+select -assert-count 1 t:$mem_v2 r:WR_PRIORITY_MASK=4'b0100 %i
+
+
+design -reset
+
+# Good case 2: write ports with disjoint bit enables.
+
+read_verilog << EOT
+
+module top(
+ input [3:0] wa1, wa2, ra,
+ input [1:0] wd1, wd2,
+ input clk, we1, we2,
+ output [3:0] rd);
+
+reg [3:0] mem[0:15];
+assign rd = mem[ra];
+
+always @(posedge clk) begin
+ if (we1)
+ mem[wa1][1:0] <= wd1;
+ if (we2)
+ mem[wa2][3:2] <= wd2;
+end
+
+endmodule
+
+EOT
+
+hierarchy -auto-top
+proc
+opt
+memory -nomap
+select -assert-count 1 t:$mem_v2
+select -assert-count 1 t:$mem_v2 r:WR_PRIORITY_MASK=4'b0000 %i
+
+
+design -reset
+
+# Good case 3: write ports with soft priority logic already
+
+read_verilog << EOT
+
+module top(
+ input [3:0] wa1, wa2, ra, wd1, wd2,
+ input clk, we1, we2,
+ output [3:0] rd);
+
+reg [3:0] mem[0:15];
+assign rd = mem[ra];
+
+always @(posedge clk) begin
+ if (we1)
+ mem[wa1] <= wd1;
+ if (we2 && wa1 != wa2)
+ mem[wa2] <= wd2;
+end
+
+endmodule
+
+EOT
+
+hierarchy -auto-top
+proc
+opt
+memory -nomap
+select -assert-count 1 t:$mem_v2
+select -assert-count 1 t:$mem_v2 r:WR_PRIORITY_MASK=4'b0000 %i
+
+
+design -reset
+
+# Good case 4: two wide write ports
+
+read_verilog << EOT
+
+module top(
+ input [5:0] wa1, wa2,
+ input [7:0] ra,
+ input [31:0] wd1, wd2,
+ input clk, we1, we2,
+ output [7:0] rd);
+
+reg [7:0] mem[0:255];
+assign rd = mem[ra];
+
+always @(posedge clk) begin
+ if (we1) begin
+ mem[{wa1, 2'b00}] <= wd1[7:0];
+ mem[{wa1, 2'b01}] <= wd1[15:8];
+ mem[{wa1, 2'b10}] <= wd1[23:16];
+ mem[{wa1, 2'b11}] <= wd1[31:24];
+ end
+ if (we2) begin
+ mem[{wa2, 2'b00}] <= wd2[7:0];
+ mem[{wa2, 2'b01}] <= wd2[15:8];
+ mem[{wa2, 2'b10}] <= wd2[23:16];
+ mem[{wa2, 2'b11}] <= wd2[31:24];
+ end
+end
+
+endmodule
+
+EOT
+
+hierarchy -auto-top
+proc
+opt
+opt_mem_priority
+memory_collect
+select -assert-count 1 t:$mem_v2
+select -assert-count 1 t:$mem_v2 r:WR_PRIORITY_MASK=64'h0804020100000000 %i
+memory_share
+select -assert-count 1 t:$mem_v2 r:WR_PRIORITY_MASK=64'h0f0f0f0f00000000 %i
+select -assert-count 1 t:$mem_v2 r:WR_WIDE_CONTINUATION=8'hee %i
diff --git a/tests/opt/opt_merge_init.ys b/tests/opt/opt_merge_init.ys
index 0176f09c7..20b6cabee 100644
--- a/tests/opt/opt_merge_init.ys
+++ b/tests/opt/opt_merge_init.ys
@@ -48,7 +48,7 @@ EOT
opt_merge
select -assert-count 1 t:$dff
-select -assert-count 1 a:init=2'bx1
+select -assert-count 1 a:init=2'bx1 a:init=2'b1x
design -reset
diff --git a/tests/opt/opt_reduce_bmux.ys b/tests/opt/opt_reduce_bmux.ys
new file mode 100644
index 000000000..55e0b6d4b
--- /dev/null
+++ b/tests/opt/opt_reduce_bmux.ys
@@ -0,0 +1,117 @@
+read_ilang << EOT
+
+module \top
+ wire width 12 input 0 \A
+ wire width 2 input 1 \S
+ wire width 6 output 2 \Y
+
+ cell $bmux $0
+ parameter \WIDTH 6
+ parameter \S_WIDTH 2
+ connect \A { \A [11:10] \A [3:2] \A [10:9] \A [7] \A [7] \A [8] \A [2] \A [7:6] \A [5] \A [5] \A [3:2] \A [5:4] \A [1] \A [1] \A [3:0] }
+ connect \S \S
+ connect \Y \Y
+ end
+end
+
+EOT
+
+equiv_opt -assert opt_reduce -fine
+opt_reduce -fine
+select -assert-count 1 t:$bmux r:WIDTH=4 %i
+
+design -reset
+
+read_ilang << EOT
+
+module \top
+ wire width 6 input 0 \A
+ wire width 2 input 1 \S
+ wire width 6 output 2 \Y
+
+ cell $bmux $0
+ parameter \WIDTH 6
+ parameter \S_WIDTH 2
+ connect \A { \A [5:0] \A [5:0] \A [5:0] \A [5:0] }
+ connect \S \S
+ connect \Y \Y
+ end
+end
+
+EOT
+
+equiv_opt -assert opt_reduce -fine
+opt_reduce -fine
+select -assert-count 0 t:$bmux
+
+design -reset
+
+read_ilang << EOT
+
+module \top
+ wire width 160 input 0 \A
+ wire width 2 input 1 \S
+ wire width 5 output 2 \Y
+
+ cell $bmux $0
+ parameter \WIDTH 5
+ parameter \S_WIDTH 5
+ connect \A \A
+ connect \S { \S [1] 1'1 \S [0] \S [1] 1'0 }
+ connect \Y \Y
+ end
+end
+
+EOT
+
+equiv_opt -assert opt_reduce -fine
+opt_reduce -fine
+select -assert-count 1 t:$bmux r:S_WIDTH=2 %i
+
+design -reset
+
+read_ilang << EOT
+
+module \top
+ wire width 10 input 0 \A
+ wire input 1 \S
+ wire width 5 output 2 \Y
+
+ cell $bmux $0
+ parameter \WIDTH 5
+ parameter \S_WIDTH 1
+ connect \A \A
+ connect \S \S
+ connect \Y \Y
+ end
+end
+
+EOT
+
+equiv_opt -assert opt_reduce -fine
+opt_reduce -fine
+select -assert-count 0 t:$bmux
+select -assert-count 1 t:$mux
+
+design -reset
+
+read_ilang << EOT
+
+module \top
+ wire width 5 input 0 \A
+ wire width 5 output 1 \Y
+
+ cell $bmux $0
+ parameter \WIDTH 5
+ parameter \S_WIDTH 0
+ connect \A \A
+ connect \S { }
+ connect \Y \Y
+ end
+end
+
+EOT
+
+equiv_opt -assert opt_reduce -fine
+opt_reduce -fine
+select -assert-count 0 t:$bmux
diff --git a/tests/opt/opt_reduce_demux.ys b/tests/opt/opt_reduce_demux.ys
new file mode 100644
index 000000000..3c5bd7d43
--- /dev/null
+++ b/tests/opt/opt_reduce_demux.ys
@@ -0,0 +1,91 @@
+read_ilang << EOT
+
+module \top
+ wire width 4 input 0 \A
+ wire width 2 input 1 \S
+ wire width 24 output 2 \Y
+
+ cell $demux $0
+ parameter \WIDTH 6
+ parameter \S_WIDTH 2
+ connect \A { \A [3] \A [1] 1'0 \A [2:0] }
+ connect \S \S
+ connect \Y \Y
+ end
+end
+
+EOT
+
+equiv_opt -assert opt_reduce -fine
+opt_reduce -fine
+select -assert-count 1 t:$demux r:WIDTH=4 %i
+
+design -reset
+
+read_ilang << EOT
+
+module \top
+ wire width 2 input 1 \S
+ wire width 24 output 2 \Y
+
+ cell $demux $0
+ parameter \WIDTH 6
+ parameter \S_WIDTH 2
+ connect \A 6'000000
+ connect \S \S
+ connect \Y \Y
+ end
+end
+
+EOT
+
+equiv_opt -assert opt_reduce -fine
+opt_reduce -fine
+select -assert-count 0 t:$demux
+
+design -reset
+
+read_ilang << EOT
+
+module \top
+ wire width 5 input 0 \A
+ wire width 2 input 1 \S
+ wire width 160 output 2 \Y
+
+ cell $demux $0
+ parameter \WIDTH 5
+ parameter \S_WIDTH 5
+ connect \A \A
+ connect \S { \S [0] \S [1] 1'1 \S [0] 1'0 }
+ connect \Y \Y
+ end
+end
+
+EOT
+
+equiv_opt -assert opt_reduce -fine
+opt_reduce -fine
+select -assert-count 1 t:$demux r:S_WIDTH=2 %i
+
+design -reset
+
+read_ilang << EOT
+
+module \top
+ wire width 5 input 0 \A
+ wire width 20 output 2 \Y
+
+ cell $demux $0
+ parameter \WIDTH 5
+ parameter \S_WIDTH 2
+ connect \A \A
+ connect \S { 2'10 }
+ connect \Y \Y
+ end
+end
+
+EOT
+
+equiv_opt -assert opt_reduce -fine
+opt_reduce -fine
+select -assert-count 0 t:$demux
diff --git a/tests/opt/opt_rmdff.ys b/tests/opt/opt_rmdff.ys
index 7e11bc73f..998414597 100644
--- a/tests/opt/opt_rmdff.ys
+++ b/tests/opt/opt_rmdff.ys
@@ -4,7 +4,7 @@ design -stash gold
read_verilog -icells opt_rmdff.v
proc
-opt_rmdff
+opt_dff
select -assert-count 0 c:remove*
select -assert-min 7 c:keep*
@@ -23,7 +23,6 @@ connect -port remove6 EN 1'b1
connect -port remove15 E 1'b1
cd ..
-dff2dffe -unmap
clk2fflogic
opt_clean
diff --git a/tests/opt/opt_rmdff_sat.ys b/tests/opt/opt_rmdff_sat.ys
index 1c3dd9c05..231c43ecb 100644
--- a/tests/opt/opt_rmdff_sat.ys
+++ b/tests/opt/opt_rmdff_sat.ys
@@ -1,5 +1,5 @@
read_verilog opt_rmdff_sat.v
prep -flatten
-opt_rmdff -sat
-synth
+opt_dff -sat -nosdff
+simplemap
select -assert-count 5 t:$_DFF_P_
diff --git a/tests/opt/opt_share_bug2334.ys b/tests/opt/opt_share_bug2334.ys
new file mode 100644
index 000000000..004d98349
--- /dev/null
+++ b/tests/opt/opt_share_bug2334.ys
@@ -0,0 +1,13 @@
+read_verilog <<EOT
+
+module t(input [3:0] A, input [3:0] B, input [3:0] C, input S, output [3:0] Y);
+
+wire [3:0] t = A + C;
+
+assign Y = S ? A + B : {4{t[0]}};
+
+endmodule
+
+EOT
+
+equiv_opt -assert opt_share
diff --git a/tests/opt/opt_share_bug2335.ys b/tests/opt/opt_share_bug2335.ys
new file mode 100644
index 000000000..0846a9ec3
--- /dev/null
+++ b/tests/opt/opt_share_bug2335.ys
@@ -0,0 +1,27 @@
+read_verilog <<EOT
+
+module top(...);
+
+input [3:0] A, B, C;
+input S;
+input [1:0] T;
+output [3:0] X;
+output reg [3:0] Y;
+
+wire [3:0] D = A + B;
+
+assign X = S ? D : A + C;
+always @* begin
+ case(T)
+ 2'b01: Y <= A;
+ 2'b10: Y <= B;
+ default: Y <= D;
+ endcase
+end
+
+endmodule
+
+EOT
+
+proc
+equiv_opt -assert opt_share
diff --git a/tests/opt/opt_share_bug2336.ys b/tests/opt/opt_share_bug2336.ys
new file mode 100644
index 000000000..cd472ef46
--- /dev/null
+++ b/tests/opt/opt_share_bug2336.ys
@@ -0,0 +1,14 @@
+read_verilog <<EOT
+
+module top(input [3:0] A, B, C, input S, output [2:0] O);
+
+wire [3:0] tb = A + B;
+wire [3:0] tc = A + C;
+
+assign O = S ? tb[3:1] : tc[3:1];
+
+endmodule
+
+EOT
+
+equiv_opt -assert opt_share
diff --git a/tests/opt/opt_share_bug2538.ys b/tests/opt/opt_share_bug2538.ys
new file mode 100644
index 000000000..7261c6695
--- /dev/null
+++ b/tests/opt/opt_share_bug2538.ys
@@ -0,0 +1,20 @@
+read_verilog <<EOT
+
+module top(...);
+
+input [3:0] A;
+input S;
+output [1:0] Y;
+
+wire [3:0] A1 = A + 1;
+wire [3:0] A2 = A + 2;
+assign Y = S ? A1[3:2] : A2[3:2];
+
+endmodule
+
+EOT
+
+proc
+alumacc
+equiv_opt -assert opt_share
+
diff --git a/tests/opt/run-test.sh b/tests/opt/run-test.sh
index 44ce7e674..2007cd6e4 100755
--- a/tests/opt/run-test.sh
+++ b/tests/opt/run-test.sh
@@ -1,6 +1,4 @@
#!/bin/bash
-set -e
-for x in *.ys; do
- echo "Running $x.."
- ../../yosys -ql ${x%.ys}.log $x
-done
+set -eu
+source ../gen-tests-makefile.sh
+run_tests --yosys-scripts