From 59d74a334889a17817bbf0c5d3bdef4c59df0c5b Mon Sep 17 00:00:00 2001
From: Clifford Wolf <clifford@clifford.at>
Date: Wed, 1 May 2019 09:01:47 +0200
Subject: [PATCH 1/5] Re-enable "final loop assignment" feature

Signed-off-by: Clifford Wolf <clifford@clifford.at>
---
 frontends/ast/simplify.cc | 2 --
 1 file changed, 2 deletions(-)

diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc
index 4d4b9dfe1..a342bf5d9 100644
--- a/frontends/ast/simplify.cc
+++ b/frontends/ast/simplify.cc
@@ -1172,14 +1172,12 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
 			varbuf->children[0] = buf;
 		}
 
-#if 0
 		if (type == AST_FOR) {
 			AstNode *buf = next_ast->clone();
 			delete buf->children[1];
 			buf->children[1] = varbuf->children[0]->clone();
 			current_block->children.insert(current_block->children.begin() + current_block_idx++, buf);
 		}
-#endif
 
 		current_scope[varbuf->str] = backup_scope_varbuf;
 		delete varbuf;

From a30b99e66e048530d74e9dfc5c103d5fac47c5bc Mon Sep 17 00:00:00 2001
From: Clifford Wolf <clifford@clifford.at>
Date: Wed, 1 May 2019 09:29:34 +0200
Subject: [PATCH 2/5] Silently resolve completely unused cell-vs-const
 driver-driver conflicts

Signed-off-by: Clifford Wolf <clifford@clifford.at>
---
 passes/opt/opt_clean.cc | 23 +++++++++++++++++++++--
 1 file changed, 21 insertions(+), 2 deletions(-)

diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc
index 5d95c4f1a..242680290 100644
--- a/passes/opt/opt_clean.cc
+++ b/passes/opt/opt_clean.cc
@@ -85,7 +85,14 @@ void rmunused_module_cells(Module *module, bool verbose)
 {
 	SigMap sigmap(module);
 	pool<Cell*> queue, unused;
+	pool<SigBit> used_raw_bits;
 	dict<SigBit, pool<Cell*>> wire2driver;
+	dict<SigBit, vector<string>> driver_driver_logs;
+
+	for (auto &it : module->connections_) {
+		for (auto raw_bit : it.second)
+			used_raw_bits.insert(raw_bit);
+	}
 
 	for (auto &it : module->cells_) {
 		Cell *cell = it.second;
@@ -96,11 +103,15 @@ void rmunused_module_cells(Module *module, bool verbose)
 						continue;
 					auto bit = sigmap(raw_bit);
 					if (bit.wire == nullptr)
-						log_warning("Driver-driver conflict for %s between cell %s.%s and constant %s in %s: Resolved using constant.\n",
-								log_signal(raw_bit), log_id(cell), log_id(it2.first), log_signal(bit), log_id(module));
+						driver_driver_logs[raw_bit].push_back(stringf("Driver-driver conflict "
+								"for %s between cell %s.%s and constant %s in %s: Resolved using constant.",
+								log_signal(raw_bit), log_id(cell), log_id(it2.first), log_signal(bit), log_id(module)));
 					if (bit.wire != nullptr)
 						wire2driver[bit].insert(cell);
 				}
+			if (!ct_all.cell_known(cell->type) || ct_all.cell_input(cell->type, it2.first))
+				for (auto raw_bit : it2.second)
+					used_raw_bits.insert(raw_bit);
 		}
 		if (keep_cache.query(cell))
 			queue.insert(cell);
@@ -114,9 +125,17 @@ void rmunused_module_cells(Module *module, bool verbose)
 			for (auto bit : sigmap(wire))
 			for (auto c : wire2driver[bit])
 				queue.insert(c), unused.erase(c);
+			for (auto raw_bit : SigSpec(wire))
+				used_raw_bits.insert(raw_bit);
 		}
 	}
 
+	for (auto it : driver_driver_logs) {
+		if (used_raw_bits.count(it.first))
+			for (auto msg : it.second)
+				log_warning("%s\n", msg.c_str());
+	}
+
 	while (!queue.empty())
 	{
 		pool<SigBit> bits;

From e5cb9435a064461b56d55dc6ba1241ba1f179119 Mon Sep 17 00:00:00 2001
From: Clifford Wolf <clifford@clifford.at>
Date: Wed, 1 May 2019 09:32:07 +0200
Subject: [PATCH 3/5] Add additional test cases for for-loops

Signed-off-by: Clifford Wolf <clifford@clifford.at>
---
 tests/simple/forloops.v | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)
 create mode 100644 tests/simple/forloops.v

diff --git a/tests/simple/forloops.v b/tests/simple/forloops.v
new file mode 100644
index 000000000..8665222d8
--- /dev/null
+++ b/tests/simple/forloops.v
@@ -0,0 +1,25 @@
+module forloops01 (input clk, a, b, output reg [3:0] p, q, x, y);
+	integer k;
+	always @(posedge clk) begin
+		for (k=0; k<2; k=k+1)
+			p[2*k +: 2] = {a, b} ^ {2{k}};
+		x <= k + {a, b};
+	end
+	always @* begin
+		for (k=0; k<4; k=k+1)
+			q[k] = {~a, ~b, a, b} >> k[1:0];
+		y = k - {a, b};
+	end
+endmodule
+
+module forloops02 (input clk, a, b, output reg [3:0] q, x, output [3:0] y);
+	integer k;
+	always @* begin
+		for (k=0; k<4; k=k+1)
+			q[k] = {~a, ~b, a, b} >> k[1:0];
+	end
+	always @* begin
+		x = k + {a, b};
+	end
+	assign y = k - {a, b};
+endmodule

From f12e1155f1d77443ee9d876d5ba3d407b9447540 Mon Sep 17 00:00:00 2001
From: Clifford Wolf <clifford@clifford.at>
Date: Fri, 3 May 2019 09:12:10 +0200
Subject: [PATCH 4/5] Improve unused-detection for opt_clean driver-driver
 conflict warning

Signed-off-by: Clifford Wolf <clifford@clifford.at>
---
 passes/opt/opt_clean.cc | 50 ++++++++++++++++++++++++-----------------
 1 file changed, 29 insertions(+), 21 deletions(-)

diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc
index 242680290..f287fdcff 100644
--- a/passes/opt/opt_clean.cc
+++ b/passes/opt/opt_clean.cc
@@ -97,21 +97,19 @@ void rmunused_module_cells(Module *module, bool verbose)
 	for (auto &it : module->cells_) {
 		Cell *cell = it.second;
 		for (auto &it2 : cell->connections()) {
-			if (!ct_all.cell_known(cell->type) || ct_all.cell_output(cell->type, it2.first))
-				for (auto raw_bit : it2.second) {
-					if (raw_bit.wire == nullptr)
-						continue;
-					auto bit = sigmap(raw_bit);
-					if (bit.wire == nullptr)
-						driver_driver_logs[raw_bit].push_back(stringf("Driver-driver conflict "
-								"for %s between cell %s.%s and constant %s in %s: Resolved using constant.",
-								log_signal(raw_bit), log_id(cell), log_id(it2.first), log_signal(bit), log_id(module)));
-					if (bit.wire != nullptr)
-						wire2driver[bit].insert(cell);
-				}
-			if (!ct_all.cell_known(cell->type) || ct_all.cell_input(cell->type, it2.first))
-				for (auto raw_bit : it2.second)
-					used_raw_bits.insert(raw_bit);
+			if (ct_all.cell_known(cell->type) && !ct_all.cell_output(cell->type, it2.first))
+				continue;
+			for (auto raw_bit : it2.second) {
+				if (raw_bit.wire == nullptr)
+					continue;
+				auto bit = sigmap(raw_bit);
+				if (bit.wire == nullptr)
+					driver_driver_logs[raw_bit].push_back(stringf("Driver-driver conflict "
+							"for %s between cell %s.%s and constant %s in %s: Resolved using constant.",
+							log_signal(raw_bit), log_id(cell), log_id(it2.first), log_signal(bit), log_id(module)));
+				if (bit.wire != nullptr)
+					wire2driver[bit].insert(cell);
+			}
 		}
 		if (keep_cache.query(cell))
 			queue.insert(cell);
@@ -130,12 +128,6 @@ void rmunused_module_cells(Module *module, bool verbose)
 		}
 	}
 
-	for (auto it : driver_driver_logs) {
-		if (used_raw_bits.count(it.first))
-			for (auto msg : it.second)
-				log_warning("%s\n", msg.c_str());
-	}
-
 	while (!queue.empty())
 	{
 		pool<SigBit> bits;
@@ -161,6 +153,22 @@ void rmunused_module_cells(Module *module, bool verbose)
 		module->remove(cell);
 		count_rm_cells++;
 	}
+
+	for (auto &it : module->cells_) {
+		Cell *cell = it.second;
+		for (auto &it2 : cell->connections()) {
+			if (ct_all.cell_known(cell->type) && !ct_all.cell_input(cell->type, it2.first))
+				continue;
+			for (auto raw_bit : it2.second)
+				used_raw_bits.insert(raw_bit);
+		}
+	}
+
+	for (auto it : driver_driver_logs) {
+		if (used_raw_bits.count(it.first))
+			for (auto msg : it.second)
+				log_warning("%s\n", msg.c_str());
+	}
 }
 
 int count_nontrivial_wire_attrs(RTLIL::Wire *w)

From 5c2c0b4bb2ade51396da3acbcce0d5916fb1c7d6 Mon Sep 17 00:00:00 2001
From: Clifford Wolf <clifford@clifford.at>
Date: Fri, 3 May 2019 09:22:26 +0200
Subject: [PATCH 5/5] Further improve unused-detection for opt_clean
 driver-driver conflict warning

Signed-off-by: Clifford Wolf <clifford@clifford.at>
---
 passes/opt/opt_clean.cc | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc
index f287fdcff..fcb662b59 100644
--- a/passes/opt/opt_clean.cc
+++ b/passes/opt/opt_clean.cc
@@ -89,9 +89,12 @@ void rmunused_module_cells(Module *module, bool verbose)
 	dict<SigBit, pool<Cell*>> wire2driver;
 	dict<SigBit, vector<string>> driver_driver_logs;
 
+	SigMap raw_sigmap;
 	for (auto &it : module->connections_) {
-		for (auto raw_bit : it.second)
-			used_raw_bits.insert(raw_bit);
+		for (int i = 0; i < GetSize(it.second); i++) {
+			if (it.second[i].wire != nullptr)
+				raw_sigmap.add(it.first[i], it.second[i]);
+		}
 	}
 
 	for (auto &it : module->cells_) {
@@ -104,7 +107,7 @@ void rmunused_module_cells(Module *module, bool verbose)
 					continue;
 				auto bit = sigmap(raw_bit);
 				if (bit.wire == nullptr)
-					driver_driver_logs[raw_bit].push_back(stringf("Driver-driver conflict "
+					driver_driver_logs[raw_sigmap(raw_bit)].push_back(stringf("Driver-driver conflict "
 							"for %s between cell %s.%s and constant %s in %s: Resolved using constant.",
 							log_signal(raw_bit), log_id(cell), log_id(it2.first), log_signal(bit), log_id(module)));
 				if (bit.wire != nullptr)
@@ -124,7 +127,7 @@ void rmunused_module_cells(Module *module, bool verbose)
 			for (auto c : wire2driver[bit])
 				queue.insert(c), unused.erase(c);
 			for (auto raw_bit : SigSpec(wire))
-				used_raw_bits.insert(raw_bit);
+				used_raw_bits.insert(raw_sigmap(raw_bit));
 		}
 	}
 
@@ -159,7 +162,7 @@ void rmunused_module_cells(Module *module, bool verbose)
 		for (auto &it2 : cell->connections()) {
 			if (ct_all.cell_known(cell->type) && !ct_all.cell_input(cell->type, it2.first))
 				continue;
-			for (auto raw_bit : it2.second)
+			for (auto raw_bit : raw_sigmap(it2.second))
 				used_raw_bits.insert(raw_bit);
 		}
 	}