From b515fd2d25851c90c9a0b08414c5ea5edeb916a0 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 30 Apr 2019 11:25:15 +0200 Subject: [PATCH] Add peepopt_muldiv, fixes #930 Signed-off-by: Clifford Wolf --- passes/opt/wreduce.cc | 36 +++++++++++++++++++++++++++++++++ passes/pmgen/Makefile.inc | 3 ++- passes/pmgen/peepopt.cc | 1 + passes/pmgen/peepopt_muldiv.pmg | 36 +++++++++++++++++++++++++++++++++ passes/pmgen/pmgen.py | 2 ++ tests/simple/peepopt.v | 9 +++++++++ 6 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 passes/pmgen/peepopt_muldiv.pmg create mode 100644 tests/simple/peepopt.v diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc index 68e077cf9..bbb1f4c48 100644 --- a/passes/opt/wreduce.cc +++ b/passes/opt/wreduce.cc @@ -529,6 +529,42 @@ struct WreducePass : public Pass { module->connect(sig, Const(0, GetSize(sig))); } } + + if (c->type.in("$div", "$mod", "$pow")) + { + SigSpec A = c->getPort("\\A"); + int original_a_width = GetSize(A); + if (c->getParam("\\A_SIGNED").as_bool()) { + while (GetSize(A) > 1 && A[GetSize(A)-1] == State::S0 && A[GetSize(A)-2] == State::S0) + A.remove(GetSize(A)-1, 1); + } else { + while (GetSize(A) > 0 && A[GetSize(A)-1] == State::S0) + A.remove(GetSize(A)-1, 1); + } + if (original_a_width != GetSize(A)) { + log("Removed top %d bits (of %d) from port A of cell %s.%s (%s).\n", + original_a_width-GetSize(A), original_a_width, log_id(module), log_id(c), log_id(c->type)); + c->setPort("\\A", A); + c->setParam("\\A_WIDTH", GetSize(A)); + } + + SigSpec B = c->getPort("\\B"); + int original_b_width = GetSize(B); + if (c->getParam("\\B_SIGNED").as_bool()) { + while (GetSize(B) > 1 && B[GetSize(B)-1] == State::S0 && B[GetSize(B)-2] == State::S0) + B.remove(GetSize(B)-1, 1); + } else { + while (GetSize(B) > 0 && B[GetSize(B)-1] == State::S0) + B.remove(GetSize(B)-1, 1); + } + if (original_b_width != GetSize(B)) { + log("Removed top %d bits (of %d) from port B of cell %s.%s (%s).\n", + original_b_width-GetSize(B), original_b_width, log_id(module), log_id(c), log_id(c->type)); + c->setPort("\\B", B); + c->setParam("\\B_WIDTH", GetSize(B)); + } + } + if (!opt_memx && c->type.in("$memrd", "$memwr", "$meminit")) { IdString memid = c->getParam("\\MEMID").decode_string(); RTLIL::Memory *mem = module->memories.at(memid); diff --git a/passes/pmgen/Makefile.inc b/passes/pmgen/Makefile.inc index a8cac7ea4..7911132db 100644 --- a/passes/pmgen/Makefile.inc +++ b/passes/pmgen/Makefile.inc @@ -16,7 +16,8 @@ passes/pmgen/peepopt.o: passes/pmgen/peepopt_pm.h EXTRA_OBJS += passes/pmgen/peepopt_pm.h .SECONDARY: passes/pmgen/peepopt_pm.h -PEEPOPT_PATTERN = passes/pmgen/peepopt_shiftmul.pmg +PEEPOPT_PATTERN = passes/pmgen/peepopt_shiftmul.pmg +PEEPOPT_PATTERN += passes/pmgen/peepopt_muldiv.pmg passes/pmgen/peepopt_pm.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN) $(P) mkdir -p passes/pmgen && python3 $< -o $@ -p peepopt $(filter-out $<,$^) diff --git a/passes/pmgen/peepopt.cc b/passes/pmgen/peepopt.cc index 0584878c3..78eb68c7a 100644 --- a/passes/pmgen/peepopt.cc +++ b/passes/pmgen/peepopt.cc @@ -59,6 +59,7 @@ struct PeepoptPass : public Pass { did_something = false; peepopt_pm pm(module, module->selected_cells()); pm.run_shiftmul(); + pm.run_muldiv(); } } } diff --git a/passes/pmgen/peepopt_muldiv.pmg b/passes/pmgen/peepopt_muldiv.pmg new file mode 100644 index 000000000..06c275834 --- /dev/null +++ b/passes/pmgen/peepopt_muldiv.pmg @@ -0,0 +1,36 @@ +pattern muldiv + +state t x y + +match mul + select mul->type == $mul + select GetSize(port(mul, \A)) + GetSize(port(mul, \B)) <= GetSize(port(mul, \Y)) +endmatch + +code t x y + t = port(mul, \Y); + x = port(mul, \A); + y = port(mul, \B); + branch; + std::swap(x, y); +endcode + +match div + select div->type.in($div) + index port(div, \A) === t + index port(div, \B) === x +endmatch + +code + SigSpec div_y = port(div, \Y); + SigSpec val_y = y; + + if (GetSize(div_y) != GetSize(val_y)) + val_y.extend_u0(GetSize(div_y), param(div, \A_SIGNED).as_bool()); + + did_something = true; + log("muldiv pattern in %s: mul=%s, div=%s\n", log_id(module), log_id(mul), log_id(div)); + module->connect(div_y, val_y); + autoremove(div); + reject; +endcode diff --git a/passes/pmgen/pmgen.py b/passes/pmgen/pmgen.py index 95a0a5f5d..81052afce 100644 --- a/passes/pmgen/pmgen.py +++ b/passes/pmgen/pmgen.py @@ -335,6 +335,8 @@ with open(outfile, "w") as f: print(" blacklist_dirty = false;", file=f) for index in range(len(blocks)): block = blocks[index] + if block["pattern"] != current_pattern: + continue if block["type"] == "match": print(" if (st_{}.{} != nullptr && blacklist_cells.count(st_{}.{})) {{".format(current_pattern, block["cell"], current_pattern, block["cell"]), file=f) print(" rollback = {};".format(index+1), file=f) diff --git a/tests/simple/peepopt.v b/tests/simple/peepopt.v new file mode 100644 index 000000000..b27b9fe57 --- /dev/null +++ b/tests/simple/peepopt.v @@ -0,0 +1,9 @@ +module peepopt_shiftmul_0 #(parameter N=3, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output [W-1:0] o); +assign o = i[s*W+:W]; +endmodule + +module peepopt_muldiv_0(input [1:0] i, output [1:0] o); +wire [3:0] t; +assign t = i * 3; +assign o = t / 3; +endmodule -- 2.30.2