[dev.ssa] cmd/compile/ssa: place for loop incr in a separate block

This is a prerequisite for implementing break and continue;
blocks ending in break or continue need to have
the increment block as a successor.

While we're here, implement for loops with no condition.

Change-Id: I85d8ba020628d805bfd0bd583dfd16e1be6f6fae
Reviewed-on: https://go-review.googlesource.com/11941
Reviewed-by: Keith Randall <khr@golang.org>
diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go
index 866db61..96ae49a 100644
--- a/src/cmd/compile/internal/gc/ssa.go
+++ b/src/cmd/compile/internal/gc/ssa.go
@@ -379,8 +379,10 @@
 		addEdge(b, s.exit)
 
 	case OFOR:
+		// OFOR: for Ninit; Left; Right { Nbody }
 		bCond := s.f.NewBlock(ssa.BlockPlain)
 		bBody := s.f.NewBlock(ssa.BlockPlain)
+		bIncr := s.f.NewBlock(ssa.BlockPlain)
 		bEnd := s.f.NewBlock(ssa.BlockPlain)
 
 		// first, jump to condition test
@@ -388,13 +390,14 @@
 		addEdge(b, bCond)
 
 		// generate code to test condition
-		// TODO(khr): Left == nil exception
-		if n.Left == nil {
-			s.Unimplementedf("cond n.Left == nil: %v", n)
-		}
 		s.startBlock(bCond)
-		s.stmtList(n.Left.Ninit)
-		cond := s.expr(n.Left)
+		var cond *ssa.Value
+		if n.Left != nil {
+			s.stmtList(n.Left.Ninit)
+			cond = s.expr(n.Left)
+		} else {
+			cond = s.entryNewValue0A(ssa.OpConst, Types[TBOOL], true)
+		}
 		b = s.endBlock()
 		b.Kind = ssa.BlockIf
 		b.Control = cond
@@ -405,13 +408,16 @@
 		// generate body
 		s.startBlock(bBody)
 		s.stmtList(n.Nbody)
+		if b := s.endBlock(); b != nil {
+			addEdge(b, bIncr)
+		}
+
+		// generate incr
+		s.startBlock(bIncr)
 		if n.Right != nil {
 			s.stmt(n.Right)
 		}
-		b = s.endBlock()
-		// If the body ends in a return statement,
-		// the condition check and loop are unreachable.
-		if b != nil {
+		if b := s.endBlock(); b != nil {
 			addEdge(b, bCond)
 		}
 		s.startBlock(bEnd)