opt_shift

This commit is contained in:
Akash Levy 2026-04-02 00:43:06 -07:00
parent 72db8885aa
commit 5082625d71
6 changed files with 959 additions and 0 deletions

View File

@ -28,6 +28,17 @@ PEEPOPT_PATTERN = passes/silimate/peepopt_expand.pmg
passes/silimate/peepopt_expand.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN)
$(P) mkdir -p $(dir $@) && $(PYTHON_EXECUTABLE) $< -o $@ -p peepopt $(filter-out $<,$^)
OBJS += passes/silimate/opt_shift.o
GENFILES += passes/silimate/peepopt_shift.h
passes/silimate/opt_shift.o: passes/silimate/peepopt_shift.h
$(eval $(call add_extra_objs,passes/silimate/peepopt_shift.h))
PEEPOPT_PATTERN = passes/silimate/peepopt_combine_shifts.pmg
PEEPOPT_PATTERN += passes/silimate/peepopt_expand_shifts.pmg
passes/silimate/peepopt_shift.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN)
$(P) mkdir -p $(dir $@) && $(PYTHON_EXECUTABLE) $< -o $@ -p peepopt $(filter-out $<,$^)
OBJS += passes/silimate/muxmode.o
GENFILES += passes/silimate/peepopt_muxmode.h
passes/silimate/muxmode.o: passes/silimate/peepopt_muxmode.h

View File

@ -0,0 +1,109 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
* Akash Levy <akash@silimate.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
bool did_something;
#include "passes/silimate/peepopt_shift.h"
struct OptShiftPass : public Pass {
OptShiftPass() : Pass("opt_shift", "shift optimizations: combine and expand") { }
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" opt_shift [options] [selection]\n");
log("\n");
log("This pass performs shift optimizations.\n");
log("\n");
log(" -combine\n");
log(" Combine nested shift operations (works with all\n");
log(" combinations of $shl/$sshl and $shr/$sshr):\n");
log(" (a <</<< b) <</<< c ===> a <</<< (b + c)\n");
log(" (a >>>/>> b) >>>/>> c ===> a >>>/>> (b + c)\n");
log(" (a <</<< b) >>>/>> c ===> a <</<< (b - c)\n");
log(" (a >>>/>> b) <</<< c ===> a >>>/>> (b - c)\n");
log(" Result uses the inner shift's type.\n");
log("\n");
log(" -expand\n");
log(" Expand shifts across binary operations:\n");
log(" (a OP b) << c ===> (a << c) OP (b << c)\n");
log(" (a OP b) >> c ===> (a >> c) OP (b >> c)\n");
log(" where OP in {$and, $or, $xor, $add, $sub}\n");
log("\n");
log(" -max_iters n\n");
log(" max number of pass iterations to run.\n");
log("\n");
log("If neither -combine nor -expand is given, both are run.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing OPT_SHIFT pass (shift optimizations).\n");
bool run_combine = false;
bool run_expand = false;
int max_iters = 10000;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
if (args[argidx] == "-combine") {
run_combine = true;
continue;
}
if (args[argidx] == "-expand") {
run_expand = true;
continue;
}
if (args[argidx] == "-max_iters" && argidx + 1 < args.size()) {
max_iters = std::stoi(args[++argidx]);
continue;
}
break;
}
extra_args(args, argidx, design);
if (!run_combine && !run_expand) {
run_combine = true;
run_expand = true;
}
for (auto module : design->selected_modules())
{
did_something = true;
for (int i = 0; did_something && i < max_iters; i++)
{
did_something = false;
peepopt_pm pm(module);
pm.setup(module->selected_cells());
if (run_combine)
pm.run_combine_shifts();
if (run_expand)
pm.run_expand_shifts();
}
}
}
} OptShiftPass;
PRIVATE_NAMESPACE_END

View File

@ -0,0 +1,91 @@
pattern combine_shifts
//
// Authored by Akash Levy of Silimate, Inc. under ISC license.
//
// Combine nested shift operations
//
// Same direction:
// (a << b) << c ===> a << (b + c)
// (a >> b) >> c ===> a >> (b + c)
// (a <<< b) <<< c ===> a <<< (b + c)
// (a >>> b) >>> c ===> a >>> (b + c)
// (a << b) <<< c ===> a << (b + c)
// (a <<< b) << c ===> a <<< (b + c)
// (a >> b) >>> c ===> a >> (b + c)
// (a >>> b) >> c ===> a >>> (b + c)
//
// Mixed direction:
// (a <</<< b) >>>/>> c ===> a <</<< (b - c)
// (a >>>/>> b) <</<< c ===> a >>>/>> (b - c)
//
state <SigSpec> inner_a inner_b inner_y outer_b outer_y
match inner_shift
select inner_shift->type.in($shl, $shr, $sshl, $sshr)
set inner_a port(inner_shift, \A)
set inner_b port(inner_shift, \B)
set inner_y port(inner_shift, \Y)
endmatch
code
if (nusers(inner_y) != 2)
reject;
endcode
match outer_shift
select outer_shift->type.in($shl, $shr, $sshl, $sshr)
index <SigSpec> port(outer_shift, \A) === inner_y
set outer_b port(outer_shift, \B)
set outer_y port(outer_shift, \Y)
endmatch
code inner_a inner_b inner_y outer_b outer_y
bool inner_is_left = inner_shift->type.in($shl, $sshl);
bool outer_is_left = outer_shift->type.in($shl, $sshl);
bool same_direction = (inner_is_left == outer_is_left);
// Unset all ports
inner_shift->unsetPort(\A);
inner_shift->unsetPort(\B);
inner_shift->unsetPort(\Y);
outer_shift->unsetPort(\A);
outer_shift->unsetPort(\B);
outer_shift->unsetPort(\Y);
Cell *cell = outer_shift;
// Create combined shift amount
int combined_width = max(GetSize(inner_b), GetSize(outer_b)) + 1;
Wire *combined_amt = module->addWire(NEW_ID2, combined_width);
if (same_direction) {
// Same direction: b + c
module->addAdd(NEW_ID2, inner_b, outer_b, combined_amt,
false, cell->get_src_attribute());
} else {
// Mixed direction: b - c
module->addSub(NEW_ID2, inner_b, outer_b, combined_amt,
false, cell->get_src_attribute());
}
// Reuse outer shift with inner shift's type, original data, and combined amount
outer_shift->type = inner_shift->type;
outer_shift->setPort(\A, inner_a);
outer_shift->setPort(\B, combined_amt);
outer_shift->setPort(\Y, outer_y);
outer_shift->setParam(\A_SIGNED, inner_shift->getParam(\A_SIGNED));
outer_shift->fixup_parameters();
// Rename for formal
module->rename(outer_shift, NEW_ID2);
// Remove inner shift
autoremove(inner_shift);
log("combine_shifts pattern in %s: inner=%s (%s), outer=%s (%s)\n",
log_id(module), log_id(inner_shift), log_id(inner_shift->type),
log_id(outer_shift), log_id(outer_shift->type));
did_something = true;
accept;
endcode

View File

@ -0,0 +1,93 @@
pattern expand_shifts
//
// Authored by Akash Levy of Silimate, Inc. under ISC license.
//
// Expand shifts across binary operations
//
// y = (a OP b) << c ===> y = (a << c) OP (b << c)
// y = (a OP b) >> c ===> y = (a >> c) OP (b >> c)
// y = (a OP b) <<< c ===> y = (a <<< c) OP (b <<< c)
// y = (a OP b) >>> c ===> y = (a >>> c) OP (b >>> c)
//
// where OP in {$and, $or, $xor, $add, $sub}
//
state <SigSpec> op_a op_b op_y shift_amt shift_y
match op_gate
// Select inner binary operation gate
select op_gate->type.in($and, $or, $xor, $add, $sub)
set op_a port(op_gate, \A)
set op_b port(op_gate, \B)
set op_y port(op_gate, \Y)
endmatch
code
// Fanout of each OP gate Y bit should be 1 (no bit-split)
if (nusers(op_y) != 2)
reject;
endcode
match shift_gate
// Select shift gate consuming the OP gate's output
select shift_gate->type.in($shl, $shr, $sshl, $sshr)
// Connection: shift gate's A input is the OP gate's output
index <SigSpec> port(shift_gate, \A) === op_y
set shift_amt port(shift_gate, \B)
set shift_y port(shift_gate, \Y)
endmatch
code op_a op_b op_y shift_amt shift_y
// Unset all ports
shift_gate->unsetPort(\A);
shift_gate->unsetPort(\B);
shift_gate->unsetPort(\Y);
op_gate->unsetPort(\A);
op_gate->unsetPort(\B);
op_gate->unsetPort(\Y);
Cell *cell = shift_gate;
// Create new intermediate wires
Wire *new_op_a = module->addWire(NEW_ID2, GetSize(shift_y));
Wire *new_op_b = module->addWire(NEW_ID2, GetSize(shift_y));
// Create new shift gates: (a SHIFT c) and (b SHIFT c)
Cell *new_shift_a = module->addCell(NEW_ID2, shift_gate->type);
new_shift_a->setPort(\A, op_a);
new_shift_a->setPort(\B, shift_amt);
new_shift_a->setPort(\Y, new_op_a);
new_shift_a->setParam(\A_SIGNED, shift_gate->getParam(\A_SIGNED));
new_shift_a->setParam(\B_SIGNED, shift_gate->getParam(\B_SIGNED));
new_shift_a->fixup_parameters();
new_shift_a->set_src_attribute(cell->get_src_attribute());
Cell *new_shift_b = module->addCell(NEW_ID2, shift_gate->type);
new_shift_b->setPort(\A, op_b);
new_shift_b->setPort(\B, shift_amt);
new_shift_b->setPort(\Y, new_op_b);
new_shift_b->setParam(\A_SIGNED, shift_gate->getParam(\A_SIGNED));
new_shift_b->setParam(\B_SIGNED, shift_gate->getParam(\B_SIGNED));
new_shift_b->fixup_parameters();
new_shift_b->set_src_attribute(cell->get_src_attribute());
// Update OP gate to take shifted inputs and produce final output
op_gate->setPort(\A, new_op_a);
op_gate->setPort(\B, new_op_b);
op_gate->setPort(\Y, shift_y);
op_gate->fixup_parameters();
// Rename OP gate for formal
cell = op_gate;
module->rename(op_gate, NEW_ID2);
// Remove original shift gate
autoremove(shift_gate);
// Log, fixup, accept
log("expand_shifts pattern in %s: op=%s (%s), shift=%s (%s)\n", log_id(module), log_id(op_gate), log_id(op_gate->type), log_id(shift_gate), log_id(shift_gate->type));
did_something = true;
accept;
endcode

View File

@ -0,0 +1,377 @@
log -header "Same direction SHL: (a << b) << c"
log -push
design -reset
read_verilog <<EOF
module top (
input wire [7:0] a,
input wire [2:0] b,
input wire [2:0] c,
output wire [7:0] x
);
assign x = (a << b) << c;
endmodule
EOF
check -assert
equiv_opt -assert opt_shift -combine
design -load postopt
select -assert-count 1 t:$shl
select -assert-count 1 t:$add
design -reset
log -pop
log -header "Same direction SHR: (a >> b) >> c"
log -push
design -reset
read_verilog <<EOF
module top (
input wire [7:0] a,
input wire [2:0] b,
input wire [2:0] c,
output wire [7:0] x
);
assign x = (a >> b) >> c;
endmodule
EOF
check -assert
equiv_opt -assert opt_shift -combine
design -load postopt
select -assert-count 1 t:$shr
select -assert-count 1 t:$add
design -reset
log -pop
log -header "Same direction SSHR: (a >>> b) >>> c (signed arithmetic)"
log -push
design -reset
read_verilog <<EOF
module top (
input wire signed [7:0] a,
input wire [2:0] b,
input wire [2:0] c,
output wire signed [7:0] x
);
assign x = (a >>> b) >>> c;
endmodule
EOF
check -assert
equiv_opt -assert opt_shift -combine
design -load postopt
select -assert-count 1 t:$sshr
select -assert-count 1 t:$add
design -reset
log -pop
log -header "Negative case: fanout from intermediate wire prevents combining"
log -push
design -reset
read_verilog <<EOF
module top (
input wire [7:0] a,
input wire [2:0] b,
input wire [2:0] c,
output wire [7:0] m,
output wire [7:0] x
);
assign m = a << b;
assign x = m << c;
endmodule
EOF
check -assert
equiv_opt -assert opt_shift -combine
design -load postopt
select -assert-count 2 t:$shl
select -assert-count 0 t:$add
design -reset
log -pop
log -header "Triple chain: ((a << b) << c) << d"
log -push
design -reset
read_verilog <<EOF
module top (
input wire [7:0] a,
input wire [2:0] b,
input wire [2:0] c,
input wire [2:0] d,
output wire [7:0] x
);
assign x = ((a << b) << c) << d;
endmodule
EOF
check -assert
equiv_opt -assert opt_shift -combine
design -load postopt
select -assert-count 1 t:$shl
select -assert-count 2 t:$add
design -reset
log -pop
log -header "Mixed direction: (a << b) >> c"
log -push
design -reset
read_verilog <<EOF
module top (
input wire [7:0] a,
input wire [2:0] b,
input wire [2:0] c,
output wire [7:0] x
);
assign x = (a << b) >> c;
endmodule
EOF
check -assert
opt_shift -combine
select -assert-count 1 t:$shl
select -assert-count 0 t:$shr
select -assert-count 1 t:$sub
design -reset
log -pop
log -header "Mixed direction: (a >> b) << c"
log -push
design -reset
read_verilog <<EOF
module top (
input wire [7:0] a,
input wire [2:0] b,
input wire [2:0] c,
output wire [7:0] x
);
assign x = (a >> b) << c;
endmodule
EOF
check -assert
opt_shift -combine
select -assert-count 0 t:$shl
select -assert-count 1 t:$shr
select -assert-count 1 t:$sub
design -reset
log -pop
log -header "Cross-type same direction: $shr then $sshr"
log -push
design -reset
read_rtlil <<EOF
autoidx 1
module \top
wire width 8 input 1 \a
wire width 3 input 2 \b
wire width 3 input 3 \c
wire width 8 output 4 \x
wire width 8 \t
cell $shr \shr_cell
parameter \A_SIGNED 0
parameter \B_SIGNED 0
parameter \A_WIDTH 8
parameter \B_WIDTH 3
parameter \Y_WIDTH 8
connect \A \a
connect \B \b
connect \Y \t
end
cell $sshr \sshr_cell
parameter \A_SIGNED 1
parameter \B_SIGNED 0
parameter \A_WIDTH 8
parameter \B_WIDTH 3
parameter \Y_WIDTH 8
connect \A \t
connect \B \c
connect \Y \x
end
end
EOF
check -assert
opt_shift -combine
select -assert-count 1 t:$shr
select -assert-count 0 t:$sshr
select -assert-count 1 t:$add
design -reset
log -pop
log -header "Cross-type same direction: $sshr then $shr"
log -push
design -reset
read_rtlil <<EOF
autoidx 1
module \top
wire width 8 input 1 \a
wire width 3 input 2 \b
wire width 3 input 3 \c
wire width 8 output 4 \x
wire width 8 \t
cell $sshr \sshr_cell
parameter \A_SIGNED 1
parameter \B_SIGNED 0
parameter \A_WIDTH 8
parameter \B_WIDTH 3
parameter \Y_WIDTH 8
connect \A \a
connect \B \b
connect \Y \t
end
cell $shr \shr_cell
parameter \A_SIGNED 0
parameter \B_SIGNED 0
parameter \A_WIDTH 8
parameter \B_WIDTH 3
parameter \Y_WIDTH 8
connect \A \t
connect \B \c
connect \Y \x
end
end
EOF
check -assert
opt_shift -combine
select -assert-count 0 t:$shr
select -assert-count 1 t:$sshr
select -assert-count 1 t:$add
design -reset
log -pop
log -header "Cross-type mixed direction: $sshr then $shl"
log -push
design -reset
read_rtlil <<EOF
autoidx 1
module \top
wire width 8 input 1 \a
wire width 3 input 2 \b
wire width 3 input 3 \c
wire width 8 output 4 \x
wire width 8 \t
cell $sshr \sshr_cell
parameter \A_SIGNED 1
parameter \B_SIGNED 0
parameter \A_WIDTH 8
parameter \B_WIDTH 3
parameter \Y_WIDTH 8
connect \A \a
connect \B \b
connect \Y \t
end
cell $shl \shl_cell
parameter \A_SIGNED 0
parameter \B_SIGNED 0
parameter \A_WIDTH 8
parameter \B_WIDTH 3
parameter \Y_WIDTH 8
connect \A \t
connect \B \c
connect \Y \x
end
end
EOF
check -assert
opt_shift -combine
select -assert-count 0 t:$shl
select -assert-count 1 t:$sshr
select -assert-count 1 t:$sub
design -reset
log -pop
log -header "Cross-type mixed direction: $shl then $sshr"
log -push
design -reset
read_rtlil <<EOF
autoidx 1
module \top
wire width 8 input 1 \a
wire width 3 input 2 \b
wire width 3 input 3 \c
wire width 8 output 4 \x
wire width 8 \t
cell $shl \shl_cell
parameter \A_SIGNED 0
parameter \B_SIGNED 0
parameter \A_WIDTH 8
parameter \B_WIDTH 3
parameter \Y_WIDTH 8
connect \A \a
connect \B \b
connect \Y \t
end
cell $sshr \sshr_cell
parameter \A_SIGNED 1
parameter \B_SIGNED 0
parameter \A_WIDTH 8
parameter \B_WIDTH 3
parameter \Y_WIDTH 8
connect \A \t
connect \B \c
connect \Y \x
end
end
EOF
check -assert
opt_shift -combine
select -assert-count 1 t:$shl
select -assert-count 0 t:$sshr
select -assert-count 1 t:$sub
design -reset
log -pop
log -header "1-bit operands: (a << b) << c"
log -push
design -reset
read_verilog <<EOF
module top (
input wire a,
input wire [2:0] b,
input wire [2:0] c,
output wire [7:0] x
);
assign x = (a << b) << c;
endmodule
EOF
check -assert
equiv_opt -assert opt_shift -combine
design -load postopt
select -assert-count 1 t:$shl
select -assert-count 1 t:$add
design -reset
log -pop
log -header "Constant shift amounts: (a << 3) << 2"
log -push
design -reset
read_verilog <<EOF
module top (
input wire [7:0] a,
output wire [7:0] x
);
assign x = (a << 3) << 2;
endmodule
EOF
check -assert
equiv_opt -assert opt_shift -combine
design -load postopt
select -assert-count 1 t:$shl
select -assert-count 1 t:$add
design -reset
log -pop

View File

@ -0,0 +1,278 @@
log -header "SHL across AND: (a & b) << c"
log -push
design -reset
read_verilog <<EOF
module top (
input wire [7:0] a,
input wire [7:0] b,
input wire [2:0] c,
output wire [7:0] x
);
assign x = (a & b) << c;
endmodule
EOF
check -assert
equiv_opt -assert opt_shift -expand
design -load postopt
select -assert-count 1 t:$and
select -assert-count 2 t:$shl
design -reset
log -pop
log -header "SHL across OR: (a | b) << c"
log -push
design -reset
read_verilog <<EOF
module top (
input wire [7:0] a,
input wire [7:0] b,
input wire [2:0] c,
output wire [7:0] x
);
assign x = (a | b) << c;
endmodule
EOF
check -assert
equiv_opt -assert opt_shift -expand
design -load postopt
select -assert-count 1 t:$or
select -assert-count 2 t:$shl
design -reset
log -pop
log -header "SHL across XOR: (a ^ b) << c"
log -push
design -reset
read_verilog <<EOF
module top (
input wire [7:0] a,
input wire [7:0] b,
input wire [2:0] c,
output wire [7:0] x
);
assign x = (a ^ b) << c;
endmodule
EOF
check -assert
equiv_opt -assert opt_shift -expand
design -load postopt
select -assert-count 1 t:$xor
select -assert-count 2 t:$shl
design -reset
log -pop
log -header "SHL across ADD: (a + b) << c"
log -push
design -reset
read_verilog <<EOF
module top (
input wire [7:0] a,
input wire [7:0] b,
input wire [2:0] c,
output wire [7:0] x
);
assign x = (a + b) << c;
endmodule
EOF
check -assert
equiv_opt -assert opt_shift -expand
design -load postopt
select -assert-count 1 t:$add
select -assert-count 2 t:$shl
design -reset
log -pop
log -header "SHL across SUB: (a - b) << c"
log -push
design -reset
read_verilog <<EOF
module top (
input wire [7:0] a,
input wire [7:0] b,
input wire [2:0] c,
output wire [7:0] x
);
assign x = (a - b) << c;
endmodule
EOF
check -assert
equiv_opt -assert opt_shift -expand
design -load postopt
select -assert-count 1 t:$sub
select -assert-count 2 t:$shl
design -reset
log -pop
log -header "SHR across AND: (a & b) >> c"
log -push
design -reset
read_verilog <<EOF
module top (
input wire [7:0] a,
input wire [7:0] b,
input wire [2:0] c,
output wire [7:0] x
);
assign x = (a & b) >> c;
endmodule
EOF
check -assert
equiv_opt -assert opt_shift -expand
design -load postopt
select -assert-count 1 t:$and
select -assert-count 2 t:$shr
design -reset
log -pop
log -header "SHR across XOR: (a ^ b) >> c"
log -push
design -reset
read_verilog <<EOF
module top (
input wire [7:0] a,
input wire [7:0] b,
input wire [2:0] c,
output wire [7:0] x
);
assign x = (a ^ b) >> c;
endmodule
EOF
check -assert
equiv_opt -assert opt_shift -expand
design -load postopt
select -assert-count 1 t:$xor
select -assert-count 2 t:$shr
design -reset
log -pop
log -header "SSHR (arithmetic right shift) across AND: signed (a & b) >>> c"
log -push
design -reset
read_verilog <<EOF
module top (
input wire signed [7:0] a,
input wire signed [7:0] b,
input wire [2:0] c,
output wire signed [7:0] x
);
assign x = (a & b) >>> c;
endmodule
EOF
check -assert
equiv_opt -assert opt_shift -expand
design -load postopt
select -assert-count 1 t:$and
select -assert-count 2 t:$sshr
design -reset
log -pop
log -header "Negative case: fanout from intermediate wire prevents expansion"
log -push
design -reset
read_verilog <<EOF
module top (
input wire [7:0] a,
input wire [7:0] b,
input wire [2:0] c,
output wire [7:0] m,
output wire [7:0] x
);
assign m = a & b;
assign x = m << c;
endmodule
EOF
check -assert
equiv_opt -assert opt_shift -expand
design -load postopt
select -assert-count 1 t:$and
select -assert-count 1 t:$shl
design -reset
log -pop
log -header "1-bit operands: (a & b) << c"
log -push
design -reset
read_verilog <<EOF
module top (
input wire a,
input wire b,
input wire [2:0] c,
output wire [7:0] x
);
assign x = (a & b) << c;
endmodule
EOF
check -assert
equiv_opt -assert opt_shift -expand
design -load postopt
select -assert-count 1 t:$and
select -assert-count 2 t:$shl
design -reset
log -pop
log -header "Nested: ((a | b) << c) ^ d"
log -push
design -reset
read_verilog <<EOF
module top (
input wire [7:0] a,
input wire [7:0] b,
input wire [2:0] c,
input wire [7:0] d,
output wire [7:0] x
);
assign x = ((a | b) << c) ^ d;
endmodule
EOF
check -assert
equiv_opt -assert opt_shift -expand
design -load postopt
select -assert-count 1 t:$xor
select -assert-count 1 t:$or
select -assert-count 2 t:$shl
design -reset
log -pop
log -header "Chained shifts: ((a + b) << c) << d"
log -push
design -reset
read_verilog <<EOF
module top (
input wire [7:0] a,
input wire [7:0] b,
input wire [2:0] c,
input wire [2:0] d,
output wire [7:0] x
);
assign x = ((a + b) << c) << d;
endmodule
EOF
check -assert
equiv_opt -assert opt_shift -expand
design -load postopt
select -assert-count 1 t:$add
select -assert-count 4 t:$shl
design -reset
log -pop