Skip to content

Commit fa87d81

Browse files
mdempskypull[bot]
authored andcommitted
cmd/compile/internal/noder: elide statically known "if" statements
In go.dev/cl/517775, I moved the frontend's deadcode elimination pass into unified IR. But I also made a small enhancement: a branch like "if x || true" is now detected as always taken, so the else branch can be eliminated. However, the inliner also has an optimization for delaying the introduction of the result temporary variables when there's a single return statement (added in go.dev/cl/266199). Consequently, the inliner turns "if x || true { return true }; return true" into: if x || true { ~R0 := true goto .i0 } .i0: // code that uses ~R0 In turn, this confuses phi insertion, because it doesn't recognize that the "if" statement is always taken, and so ~R0 will always be initialized. With this CL, after inlining we instead produce: _ = x || true ~R0 := true goto .i0 .i0: Fixes #62211. Change-Id: Ic8a12c9eb85833ee4e5d114f60e6c47817fce538 Reviewed-on: https://go-review.googlesource.com/c/go/+/522096 Reviewed-by: Than McIntosh <[email protected]> Run-TryBot: Matthew Dempsky <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Auto-Submit: Matthew Dempsky <[email protected]> Reviewed-by: Cuong Manh Le <[email protected]>
1 parent ca9b351 commit fa87d81

File tree

3 files changed

+67
-14
lines changed

3 files changed

+67
-14
lines changed

src/cmd/compile/internal/noder/reader.go

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1677,7 +1677,11 @@ func (r *reader) closeAnotherScope() {
16771677
// @@@ Statements
16781678

16791679
func (r *reader) stmt() ir.Node {
1680-
switch stmts := r.stmts(); len(stmts) {
1680+
return block(r.stmts())
1681+
}
1682+
1683+
func block(stmts []ir.Node) ir.Node {
1684+
switch len(stmts) {
16811685
case 0:
16821686
return nil
16831687
case 1:
@@ -1687,7 +1691,7 @@ func (r *reader) stmt() ir.Node {
16871691
}
16881692
}
16891693

1690-
func (r *reader) stmts() []ir.Node {
1694+
func (r *reader) stmts() ir.Nodes {
16911695
assert(ir.CurFunc == r.curfn)
16921696
var res ir.Nodes
16931697

@@ -1912,12 +1916,29 @@ func (r *reader) ifStmt() ir.Node {
19121916
pos := r.pos()
19131917
init := r.stmts()
19141918
cond := r.expr()
1915-
then := r.blockStmt()
1916-
els := r.stmts()
1919+
staticCond := r.Int()
1920+
var then, els []ir.Node
1921+
if staticCond >= 0 {
1922+
then = r.blockStmt()
1923+
} else {
1924+
r.lastCloseScopePos = r.pos()
1925+
}
1926+
if staticCond <= 0 {
1927+
els = r.stmts()
1928+
}
19171929
r.closeAnotherScope()
19181930

1919-
if ir.IsConst(cond, constant.Bool) && len(init)+len(then)+len(els) == 0 {
1920-
return nil // drop empty if statement
1931+
if staticCond != 0 {
1932+
// We may have removed a dead return statement, which can trip up
1933+
// later passes (#62211). To avoid confusion, we instead flatten
1934+
// the if statement into a block.
1935+
1936+
if cond.Op() != ir.OLITERAL {
1937+
init.Append(typecheck.Stmt(ir.NewAssignStmt(pos, ir.BlankNode, cond))) // for side effects
1938+
}
1939+
init.Append(then...)
1940+
init.Append(els...)
1941+
return block(init)
19211942
}
19221943

19231944
n := ir.NewIfStmt(pos, cond, then, els)

src/cmd/compile/internal/noder/writer.go

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1520,20 +1520,22 @@ func (pw *pkgWriter) rangeTypes(expr syntax.Expr) (key, value types2.Type) {
15201520
}
15211521

15221522
func (w *writer) ifStmt(stmt *syntax.IfStmt) {
1523-
switch cond := w.p.staticBool(&stmt.Cond); {
1524-
case cond > 0: // always true
1525-
stmt.Else = nil
1526-
case cond < 0: // always false
1527-
stmt.Then.List = nil
1528-
}
1523+
cond := w.p.staticBool(&stmt.Cond)
15291524

15301525
w.Sync(pkgbits.SyncIfStmt)
15311526
w.openScope(stmt.Pos())
15321527
w.pos(stmt)
15331528
w.stmt(stmt.Init)
15341529
w.expr(stmt.Cond)
1535-
w.blockStmt(stmt.Then)
1536-
w.stmt(stmt.Else)
1530+
w.Int(cond)
1531+
if cond >= 0 {
1532+
w.blockStmt(stmt.Then)
1533+
} else {
1534+
w.pos(stmt.Then.Rbrace)
1535+
}
1536+
if cond <= 0 {
1537+
w.stmt(stmt.Else)
1538+
}
15371539
w.closeAnotherScope()
15381540
}
15391541

test/inline.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,3 +393,33 @@ loop:
393393
select2(x, y) // ERROR "inlining call to select2"
394394
}
395395
}
396+
397+
// Issue #62211: inlining a function with unreachable "return"
398+
// statements could trip up phi insertion.
399+
func issue62211(x bool) { // ERROR "can inline issue62211"
400+
if issue62211F(x) { // ERROR "inlining call to issue62211F"
401+
}
402+
if issue62211G(x) { // ERROR "inlining call to issue62211G"
403+
}
404+
405+
// Initial fix CL caused a "non-monotonic scope positions" failure
406+
// on code like this.
407+
if z := 0; false {
408+
panic(z)
409+
}
410+
}
411+
412+
func issue62211F(x bool) bool { // ERROR "can inline issue62211F"
413+
if x || true {
414+
return true
415+
}
416+
return true
417+
}
418+
419+
func issue62211G(x bool) bool { // ERROR "can inline issue62211G"
420+
if x || true {
421+
return true
422+
} else {
423+
return true
424+
}
425+
}

0 commit comments

Comments
 (0)