[dev.regabi] cmd/compile: reshuffle type-checking code [generated]

This commit splits up typecheck.Package and moves the code
elsewhere. The type-checking code is moved into noder, so that it can
eventually be interleaved with the noding process. The
non-type-checking code is moved back into package gc, so that it can
be incorporated into appropriate compiler backend phases.

While here, deadcode removal is moved into its own package.

Passes toolstash -cmp.

[git-generate]
cd src/cmd/compile/internal/typecheck

: Split into two functions.
sed -i -e '/Phase 6/i}\n\nfunc postTypecheck() {' typecheck.go

rf '
	# Export needed identifiers.
	mv deadcode Deadcode
	mv loadsys InitRuntime
	mv declareUniverse DeclareUniverse
	mv dirtyAddrtaken DirtyAddrtaken
	mv computeAddrtaken ComputeAddrtaken
	mv incrementalAddrtaken IncrementalAddrtaken

	# Move into new package.
	mv Deadcode deadcodeslice deadcodeexpr deadcode.go
	mv deadcode.go cmd/compile/internal/deadcode

	# Move top-level type-checking code into noder.
	# Move DeclVars there too, now that nothing else uses it.
	mv DeclVars Package noder.go
	mv noder.go cmd/compile/internal/noder

	# Move non-type-checking code back into gc.
	mv postTypecheck main.go
	mv main.go cmd/compile/internal/gc
'

cd ../deadcode
rf '
	# Destutter names.
	mv Deadcode Func
	mv deadcodeslice stmts
	mv deadcodeexpr expr
'

cd ../noder
rf '
	# Move functions up, next to their related code.
	mv noder.go:/func Package/-1,$ \
		noder.go:/makeSrcPosBase translates/-1
	mv noder.go:/func DeclVars/-3,$ \
		noder.go:/constState tracks/-1
'

cd ../gc
rf '
	# Inline postTypecheck code back into gc.Main.
	mv main.go:/func postTypecheck/+0,/AllImportedBodies/+1 \
		main.go:/Build init task/-1
	rm postTypecheck
'

Change-Id: Ie5e992ece4a42204cce6aa98dd6eb52112d098c8
Reviewed-on: https://go-review.googlesource.com/c/go/+/280974
Trust: Matthew Dempsky <mdempsky@google.com>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
This commit is contained in:
Matthew Dempsky 2020-12-31 21:48:27 -08:00
parent b8fd3440cd
commit 0f1d2129c4
9 changed files with 327 additions and 315 deletions

View file

@ -0,0 +1,150 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package deadcode
import (
"go/constant"
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
)
func Func(fn *ir.Func) {
stmts(&fn.Body)
if len(fn.Body) == 0 {
return
}
for _, n := range fn.Body {
if len(n.Init()) > 0 {
return
}
switch n.Op() {
case ir.OIF:
n := n.(*ir.IfStmt)
if !ir.IsConst(n.Cond, constant.Bool) || len(n.Body) > 0 || len(n.Else) > 0 {
return
}
case ir.OFOR:
n := n.(*ir.ForStmt)
if !ir.IsConst(n.Cond, constant.Bool) || ir.BoolVal(n.Cond) {
return
}
default:
return
}
}
fn.Body.Set([]ir.Node{ir.NewBlockStmt(base.Pos, nil)})
}
func stmts(nn *ir.Nodes) {
var lastLabel = -1
for i, n := range *nn {
if n != nil && n.Op() == ir.OLABEL {
lastLabel = i
}
}
for i, n := range *nn {
// Cut is set to true when all nodes after i'th position
// should be removed.
// In other words, it marks whole slice "tail" as dead.
cut := false
if n == nil {
continue
}
if n.Op() == ir.OIF {
n := n.(*ir.IfStmt)
n.Cond = expr(n.Cond)
if ir.IsConst(n.Cond, constant.Bool) {
var body ir.Nodes
if ir.BoolVal(n.Cond) {
n.Else = ir.Nodes{}
body = n.Body
} else {
n.Body = ir.Nodes{}
body = n.Else
}
// If "then" or "else" branch ends with panic or return statement,
// it is safe to remove all statements after this node.
// isterminating is not used to avoid goto-related complications.
// We must be careful not to deadcode-remove labels, as they
// might be the target of a goto. See issue 28616.
if body := body; len(body) != 0 {
switch body[(len(body) - 1)].Op() {
case ir.ORETURN, ir.ORETJMP, ir.OPANIC:
if i > lastLabel {
cut = true
}
}
}
}
}
stmts(n.PtrInit())
switch n.Op() {
case ir.OBLOCK:
n := n.(*ir.BlockStmt)
stmts(&n.List)
case ir.OFOR:
n := n.(*ir.ForStmt)
stmts(&n.Body)
case ir.OIF:
n := n.(*ir.IfStmt)
stmts(&n.Body)
stmts(&n.Else)
case ir.ORANGE:
n := n.(*ir.RangeStmt)
stmts(&n.Body)
case ir.OSELECT:
n := n.(*ir.SelectStmt)
for _, cas := range n.Cases {
stmts(&cas.Body)
}
case ir.OSWITCH:
n := n.(*ir.SwitchStmt)
for _, cas := range n.Cases {
stmts(&cas.Body)
}
}
if cut {
nn.Set((*nn)[:i+1])
break
}
}
}
func expr(n ir.Node) ir.Node {
// Perform dead-code elimination on short-circuited boolean
// expressions involving constants with the intent of
// producing a constant 'if' condition.
switch n.Op() {
case ir.OANDAND:
n := n.(*ir.LogicalExpr)
n.X = expr(n.X)
n.Y = expr(n.Y)
if ir.IsConst(n.X, constant.Bool) {
if ir.BoolVal(n.X) {
return n.Y // true && x => x
} else {
return n.X // false && x => false
}
}
case ir.OOROR:
n := n.(*ir.LogicalExpr)
n.X = expr(n.X)
n.Y = expr(n.Y)
if ir.IsConst(n.X, constant.Bool) {
if ir.BoolVal(n.X) {
return n.X // true || x => true
} else {
return n.Y // false || x => x
}
}
}
return n
}