aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/noder/reader.go
diff options
context:
space:
mode:
authorMatthew Dempsky <mdempsky@google.com>2023-08-22 17:44:19 -0700
committerGopher Robot <gobot@golang.org>2023-08-23 18:01:55 +0000
commitf92741b1d82316db15516b82e3812e262202de40 (patch)
treeb9564e860999618004c6d3479015fe558a7ae692 /src/cmd/compile/internal/noder/reader.go
parentaa0ba4dcaff56b1e44ad0165516db36b71f99e50 (diff)
downloadgo-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.go33
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)