Add peepopt_muldiv, fixes #930
authorClifford Wolf <clifford@clifford.at>
Tue, 30 Apr 2019 09:25:15 +0000 (11:25 +0200)
committerClifford Wolf <clifford@clifford.at>
Tue, 30 Apr 2019 09:25:15 +0000 (11:25 +0200)
Signed-off-by: Clifford Wolf <clifford@clifford.at>
passes/opt/wreduce.cc
passes/pmgen/Makefile.inc
passes/pmgen/peepopt.cc
passes/pmgen/peepopt_muldiv.pmg [new file with mode: 0644]
passes/pmgen/pmgen.py
tests/simple/peepopt.v [new file with mode: 0644]

index 68e077cf9eb5e1249f9802494aa06e2fe4987c85..bbb1f4c4881399dac7f89ed157a8cabbde37f215 100644 (file)
@@ -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);
index a8cac7ea47d97827bff75e6a46c89762b1bb00cc..7911132db44d6c5f94d7b105a9b1740b2623c61f 100644 (file)
@@ -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 $<,$^)
index 0584878c367187536ca7fb22968a3e8b1a69f27e..78eb68c7a84804d9ece3e0547099768c3809ae00 100644 (file)
@@ -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 (file)
index 0000000..06c2758
--- /dev/null
@@ -0,0 +1,36 @@
+pattern muldiv
+
+state <SigSpec> 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 <SigSpec> port(div, \A) === t
+       index <SigSpec> 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
index 95a0a5f5d641d3704dd80d90feeda98bbbb5ee52..81052afce0509b62c38f22469f8482c8acd17fe1 100644 (file)
@@ -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 (file)
index 0000000..b27b9fe
--- /dev/null
@@ -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