diff options
| author | Matthew Dempsky <mdempsky@google.com> | 2023-08-22 17:44:19 -0700 |
|---|---|---|
| committer | Gopher Robot <gobot@golang.org> | 2023-08-23 18:01:55 +0000 |
| commit | f92741b1d82316db15516b82e3812e262202de40 (patch) | |
| tree | b9564e860999618004c6d3479015fe558a7ae692 /src/cmd/compile/internal/noder/reader.go | |
| parent | aa0ba4dcaff56b1e44ad0165516db36b71f99e50 (diff) | |
| download | go-f92741b1d82316db15516b82e3812e262202de40.tar.xz | |
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 <thanm@google.com>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Auto-Submit: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Diffstat (limited to 'src/cmd/compile/internal/noder/reader.go')
| -rw-r--r-- | src/cmd/compile/internal/noder/reader.go | 33 |
1 files changed, 27 insertions, 6 deletions
diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go index 2a526dbe69..0efe2ea2d5 100644 --- a/src/cmd/compile/internal/noder/reader.go +++ b/src/cmd/compile/internal/noder/reader.go @@ -1677,7 +1677,11 @@ func (r *reader) closeAnotherScope() { // @@@ Statements func (r *reader) stmt() ir.Node { - switch stmts := r.stmts(); len(stmts) { + return block(r.stmts()) +} + +func block(stmts []ir.Node) ir.Node { + switch len(stmts) { case 0: return nil case 1: @@ -1687,7 +1691,7 @@ func (r *reader) stmt() ir.Node { } } -func (r *reader) stmts() []ir.Node { +func (r *reader) stmts() ir.Nodes { assert(ir.CurFunc == r.curfn) var res ir.Nodes @@ -1912,12 +1916,29 @@ func (r *reader) ifStmt() ir.Node { pos := r.pos() init := r.stmts() cond := r.expr() - then := r.blockStmt() - els := r.stmts() + staticCond := r.Int() + var then, els []ir.Node + if staticCond >= 0 { + then = r.blockStmt() + } else { + r.lastCloseScopePos = r.pos() + } + if staticCond <= 0 { + els = r.stmts() + } r.closeAnotherScope() - if ir.IsConst(cond, constant.Bool) && len(init)+len(then)+len(els) == 0 { - return nil // drop empty if statement + if staticCond != 0 { + // We may have removed a dead return statement, which can trip up + // later passes (#62211). To avoid confusion, we instead flatten + // the if statement into a block. + + if cond.Op() != ir.OLITERAL { + init.Append(typecheck.Stmt(ir.NewAssignStmt(pos, ir.BlankNode, cond))) // for side effects + } + init.Append(then...) + init.Append(els...) + return block(init) } n := ir.NewIfStmt(pos, cond, then, els) |
