mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile: remove some more gotos in gc
Split typecheckrange into two, separating the bigger chunk of code that takes care of the range expression. It had to sometimes exit early, which was done via a goto in the larger func. This lets us simplify many declarations and the flow of the code. While at it, also replace the toomany int with a bool. In the case of walkselect, split it into two funcs too since using a defer for all the trailing work would be a bit much. It also lets us simplify the declarations and the flow of the code, since now walkselectcases has a narrower scope and straightforward signature. Also replace the gotos in typecheckaste with a lineno defer. Passes toolstash -cmp on std cmd. Change-Id: Iacfaa0a34c987c44f180a792c473558785cf6823 Reviewed-on: https://go-review.googlesource.com/72374 Run-TryBot: Daniel Martí <mvdan@mvdan.cc> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
parent
1722a2d79d
commit
7f88d3c121
3 changed files with 75 additions and 88 deletions
|
|
@ -13,14 +13,6 @@ import (
|
||||||
|
|
||||||
// range
|
// range
|
||||||
func typecheckrange(n *Node) {
|
func typecheckrange(n *Node) {
|
||||||
var toomany bool
|
|
||||||
var why string
|
|
||||||
var t1 *types.Type
|
|
||||||
var t2 *types.Type
|
|
||||||
var v1 *Node
|
|
||||||
var v2 *Node
|
|
||||||
var ls []*Node
|
|
||||||
|
|
||||||
// Typechecking order is important here:
|
// Typechecking order is important here:
|
||||||
// 0. first typecheck range expression (slice/map/chan),
|
// 0. first typecheck range expression (slice/map/chan),
|
||||||
// it is evaluated only once and so logically it is not part of the loop.
|
// it is evaluated only once and so logically it is not part of the loop.
|
||||||
|
|
@ -30,15 +22,31 @@ func typecheckrange(n *Node) {
|
||||||
// 2. decldepth++ to denote loop body.
|
// 2. decldepth++ to denote loop body.
|
||||||
// 3. typecheck body.
|
// 3. typecheck body.
|
||||||
// 4. decldepth--.
|
// 4. decldepth--.
|
||||||
|
typecheckrangeExpr(n)
|
||||||
|
|
||||||
|
// second half of dance, the first half being typecheckrangeExpr
|
||||||
|
n.SetTypecheck(1)
|
||||||
|
ls := n.List.Slice()
|
||||||
|
for i1, n1 := range ls {
|
||||||
|
if n1.Typecheck() == 0 {
|
||||||
|
ls[i1] = typecheck(ls[i1], Erv|Easgn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
decldepth++
|
||||||
|
typecheckslice(n.Nbody.Slice(), Etop)
|
||||||
|
decldepth--
|
||||||
|
}
|
||||||
|
|
||||||
|
func typecheckrangeExpr(n *Node) {
|
||||||
n.Right = typecheck(n.Right, Erv)
|
n.Right = typecheck(n.Right, Erv)
|
||||||
|
|
||||||
t := n.Right.Type
|
t := n.Right.Type
|
||||||
if t == nil {
|
if t == nil {
|
||||||
goto out
|
return
|
||||||
}
|
}
|
||||||
// delicate little dance. see typecheckas2
|
// delicate little dance. see typecheckas2
|
||||||
ls = n.List.Slice()
|
ls := n.List.Slice()
|
||||||
for i1, n1 := range ls {
|
for i1, n1 := range ls {
|
||||||
if n1.Name == nil || n1.Name.Defn != n {
|
if n1.Name == nil || n1.Name.Defn != n {
|
||||||
ls[i1] = typecheck(ls[i1], Erv|Easgn)
|
ls[i1] = typecheck(ls[i1], Erv|Easgn)
|
||||||
|
|
@ -50,11 +58,12 @@ func typecheckrange(n *Node) {
|
||||||
}
|
}
|
||||||
n.Type = t
|
n.Type = t
|
||||||
|
|
||||||
toomany = false
|
var t1, t2 *types.Type
|
||||||
|
toomany := false
|
||||||
switch t.Etype {
|
switch t.Etype {
|
||||||
default:
|
default:
|
||||||
yyerrorl(n.Pos, "cannot range over %L", n.Right)
|
yyerrorl(n.Pos, "cannot range over %L", n.Right)
|
||||||
goto out
|
return
|
||||||
|
|
||||||
case TARRAY, TSLICE:
|
case TARRAY, TSLICE:
|
||||||
t1 = types.Types[TINT]
|
t1 = types.Types[TINT]
|
||||||
|
|
@ -67,7 +76,7 @@ func typecheckrange(n *Node) {
|
||||||
case TCHAN:
|
case TCHAN:
|
||||||
if !t.ChanDir().CanRecv() {
|
if !t.ChanDir().CanRecv() {
|
||||||
yyerrorl(n.Pos, "invalid operation: range %v (receive from send-only type %v)", n.Right, n.Right.Type)
|
yyerrorl(n.Pos, "invalid operation: range %v (receive from send-only type %v)", n.Right, n.Right.Type)
|
||||||
goto out
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
t1 = t.Elem()
|
t1 = t.Elem()
|
||||||
|
|
@ -85,11 +94,10 @@ func typecheckrange(n *Node) {
|
||||||
yyerrorl(n.Pos, "too many variables in range")
|
yyerrorl(n.Pos, "too many variables in range")
|
||||||
}
|
}
|
||||||
|
|
||||||
v1 = nil
|
var v1, v2 *Node
|
||||||
if n.List.Len() != 0 {
|
if n.List.Len() != 0 {
|
||||||
v1 = n.List.First()
|
v1 = n.List.First()
|
||||||
}
|
}
|
||||||
v2 = nil
|
|
||||||
if n.List.Len() > 1 {
|
if n.List.Len() > 1 {
|
||||||
v2 = n.List.Second()
|
v2 = n.List.Second()
|
||||||
}
|
}
|
||||||
|
|
@ -105,6 +113,7 @@ func typecheckrange(n *Node) {
|
||||||
v2 = nil
|
v2 = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var why string
|
||||||
if v1 != nil {
|
if v1 != nil {
|
||||||
if v1.Name != nil && v1.Name.Defn == n {
|
if v1.Name != nil && v1.Name.Defn == n {
|
||||||
v1.Type = t1
|
v1.Type = t1
|
||||||
|
|
@ -122,20 +131,6 @@ func typecheckrange(n *Node) {
|
||||||
}
|
}
|
||||||
checkassign(n, v2)
|
checkassign(n, v2)
|
||||||
}
|
}
|
||||||
|
|
||||||
// second half of dance
|
|
||||||
out:
|
|
||||||
n.SetTypecheck(1)
|
|
||||||
ls = n.List.Slice()
|
|
||||||
for i1, n1 := range ls {
|
|
||||||
if n1.Typecheck() == 0 {
|
|
||||||
ls[i1] = typecheck(ls[i1], Erv|Easgn)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
decldepth++
|
|
||||||
typecheckslice(n.Nbody.Slice(), Etop)
|
|
||||||
decldepth--
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func cheapComputableIndex(width int64) bool {
|
func cheapComputableIndex(width int64) bool {
|
||||||
|
|
|
||||||
|
|
@ -78,35 +78,41 @@ func typecheckselect(sel *Node) {
|
||||||
typecheckslice(ncase.Nbody.Slice(), Etop)
|
typecheckslice(ncase.Nbody.Slice(), Etop)
|
||||||
}
|
}
|
||||||
|
|
||||||
sel.Xoffset = int64(sel.List.Len())
|
|
||||||
lineno = lno
|
lineno = lno
|
||||||
}
|
}
|
||||||
|
|
||||||
func walkselect(sel *Node) {
|
func walkselect(sel *Node) {
|
||||||
if sel.List.Len() == 0 && sel.Xoffset != 0 {
|
lno := setlineno(sel)
|
||||||
Fatalf("double walkselect") // already rewrote
|
if sel.Nbody.Len() != 0 {
|
||||||
|
Fatalf("double walkselect")
|
||||||
}
|
}
|
||||||
|
|
||||||
lno := setlineno(sel)
|
init := sel.Ninit.Slice()
|
||||||
i := sel.List.Len()
|
sel.Ninit.Set(nil)
|
||||||
|
|
||||||
|
init = append(init, walkselectcases(&sel.List)...)
|
||||||
|
sel.List.Set(nil)
|
||||||
|
|
||||||
|
sel.Nbody.Set(init)
|
||||||
|
walkstmtlist(sel.Nbody.Slice())
|
||||||
|
|
||||||
|
lineno = lno
|
||||||
|
}
|
||||||
|
|
||||||
|
func walkselectcases(cases *Nodes) []*Node {
|
||||||
|
n := cases.Len()
|
||||||
|
sellineno := lineno
|
||||||
|
|
||||||
// optimization: zero-case select
|
// optimization: zero-case select
|
||||||
var init []*Node
|
if n == 0 {
|
||||||
var r *Node
|
return []*Node{mkcall("block", nil, nil)}
|
||||||
var n *Node
|
|
||||||
var var_ *Node
|
|
||||||
var selv *Node
|
|
||||||
var chosen *Node
|
|
||||||
if i == 0 {
|
|
||||||
sel.Nbody.Set1(mkcall("block", nil, nil))
|
|
||||||
goto out
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// optimization: one-case select: single op.
|
// optimization: one-case select: single op.
|
||||||
// TODO(rsc): Reenable optimization once order.go can handle it.
|
// TODO(rsc): Reenable optimization once order.go can handle it.
|
||||||
// golang.org/issue/7672.
|
// golang.org/issue/7672.
|
||||||
if i == 1 {
|
if n == 1 {
|
||||||
cas := sel.List.First()
|
cas := cases.First()
|
||||||
setlineno(cas)
|
setlineno(cas)
|
||||||
l := cas.Ninit.Slice()
|
l := cas.Ninit.Slice()
|
||||||
if cas.Left != nil { // not default:
|
if cas.Left != nil { // not default:
|
||||||
|
|
@ -161,15 +167,14 @@ func walkselect(sel *Node) {
|
||||||
|
|
||||||
l = append(l, cas.Nbody.Slice()...)
|
l = append(l, cas.Nbody.Slice()...)
|
||||||
l = append(l, nod(OBREAK, nil, nil))
|
l = append(l, nod(OBREAK, nil, nil))
|
||||||
sel.Nbody.Set(l)
|
return l
|
||||||
goto out
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert case value arguments to addresses.
|
// convert case value arguments to addresses.
|
||||||
// this rewrite is used by both the general code and the next optimization.
|
// this rewrite is used by both the general code and the next optimization.
|
||||||
for _, cas := range sel.List.Slice() {
|
for _, cas := range cases.Slice() {
|
||||||
setlineno(cas)
|
setlineno(cas)
|
||||||
n = cas.Left
|
n := cas.Left
|
||||||
if n == nil {
|
if n == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -197,15 +202,15 @@ func walkselect(sel *Node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// optimization: two-case select but one is default: single non-blocking op.
|
// optimization: two-case select but one is default: single non-blocking op.
|
||||||
if i == 2 && (sel.List.First().Left == nil || sel.List.Second().Left == nil) {
|
if n == 2 && (cases.First().Left == nil || cases.Second().Left == nil) {
|
||||||
var cas *Node
|
var cas *Node
|
||||||
var dflt *Node
|
var dflt *Node
|
||||||
if sel.List.First().Left == nil {
|
if cases.First().Left == nil {
|
||||||
cas = sel.List.Second()
|
cas = cases.Second()
|
||||||
dflt = sel.List.First()
|
dflt = cases.First()
|
||||||
} else {
|
} else {
|
||||||
dflt = sel.List.Second()
|
dflt = cases.Second()
|
||||||
cas = sel.List.First()
|
cas = cases.First()
|
||||||
}
|
}
|
||||||
|
|
||||||
n := cas.Left
|
n := cas.Left
|
||||||
|
|
@ -239,26 +244,24 @@ func walkselect(sel *Node) {
|
||||||
r.Left = typecheck(r.Left, Erv)
|
r.Left = typecheck(r.Left, Erv)
|
||||||
r.Nbody.Set(cas.Nbody.Slice())
|
r.Nbody.Set(cas.Nbody.Slice())
|
||||||
r.Rlist.Set(append(dflt.Ninit.Slice(), dflt.Nbody.Slice()...))
|
r.Rlist.Set(append(dflt.Ninit.Slice(), dflt.Nbody.Slice()...))
|
||||||
sel.Nbody.Set2(r, nod(OBREAK, nil, nil))
|
return []*Node{r, nod(OBREAK, nil, nil)}
|
||||||
goto out
|
|
||||||
}
|
}
|
||||||
|
|
||||||
init = sel.Ninit.Slice()
|
var init []*Node
|
||||||
sel.Ninit.Set(nil)
|
|
||||||
|
|
||||||
// generate sel-struct
|
// generate sel-struct
|
||||||
setlineno(sel)
|
lineno = sellineno
|
||||||
selv = temp(selecttype(sel.Xoffset))
|
selv := temp(selecttype(int64(n)))
|
||||||
r = nod(OAS, selv, nil)
|
r := nod(OAS, selv, nil)
|
||||||
r = typecheck(r, Etop)
|
r = typecheck(r, Etop)
|
||||||
init = append(init, r)
|
init = append(init, r)
|
||||||
var_ = conv(conv(nod(OADDR, selv, nil), types.Types[TUNSAFEPTR]), types.NewPtr(types.Types[TUINT8]))
|
var_ := conv(conv(nod(OADDR, selv, nil), types.Types[TUNSAFEPTR]), types.NewPtr(types.Types[TUINT8]))
|
||||||
r = mkcall("newselect", nil, nil, var_, nodintconst(selv.Type.Width), nodintconst(sel.Xoffset))
|
r = mkcall("newselect", nil, nil, var_, nodintconst(selv.Type.Width), nodintconst(int64(n)))
|
||||||
r = typecheck(r, Etop)
|
r = typecheck(r, Etop)
|
||||||
init = append(init, r)
|
init = append(init, r)
|
||||||
|
|
||||||
// register cases
|
// register cases
|
||||||
for _, cas := range sel.List.Slice() {
|
for _, cas := range cases.Slice() {
|
||||||
setlineno(cas)
|
setlineno(cas)
|
||||||
|
|
||||||
init = append(init, cas.Ninit.Slice()...)
|
init = append(init, cas.Ninit.Slice()...)
|
||||||
|
|
@ -290,8 +293,8 @@ func walkselect(sel *Node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// run the select
|
// run the select
|
||||||
setlineno(sel)
|
lineno = sellineno
|
||||||
chosen = temp(types.Types[TINT])
|
chosen := temp(types.Types[TINT])
|
||||||
r = nod(OAS, chosen, mkcall("selectgo", types.Types[TINT], nil, var_))
|
r = nod(OAS, chosen, mkcall("selectgo", types.Types[TINT], nil, var_))
|
||||||
r = typecheck(r, Etop)
|
r = typecheck(r, Etop)
|
||||||
init = append(init, r)
|
init = append(init, r)
|
||||||
|
|
@ -300,7 +303,7 @@ func walkselect(sel *Node) {
|
||||||
init = append(init, nod(OVARKILL, selv, nil))
|
init = append(init, nod(OVARKILL, selv, nil))
|
||||||
|
|
||||||
// dispatch cases
|
// dispatch cases
|
||||||
for i, cas := range sel.List.Slice() {
|
for i, cas := range cases.Slice() {
|
||||||
setlineno(cas)
|
setlineno(cas)
|
||||||
|
|
||||||
cond := nod(OEQ, chosen, nodintconst(int64(i)))
|
cond := nod(OEQ, chosen, nodintconst(int64(i)))
|
||||||
|
|
@ -312,12 +315,7 @@ func walkselect(sel *Node) {
|
||||||
init = append(init, r)
|
init = append(init, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
sel.Nbody.Set(init)
|
return init
|
||||||
|
|
||||||
out:
|
|
||||||
sel.List.Set(nil)
|
|
||||||
walkstmtlist(sel.Nbody.Slice())
|
|
||||||
lineno = lno
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keep in sync with src/runtime/select.go.
|
// Keep in sync with src/runtime/select.go.
|
||||||
|
|
|
||||||
|
|
@ -2547,18 +2547,18 @@ func hasddd(t *types.Type) bool {
|
||||||
// typecheck assignment: type list = expression list
|
// typecheck assignment: type list = expression list
|
||||||
func typecheckaste(op Op, call *Node, isddd bool, tstruct *types.Type, nl Nodes, desc func() string) {
|
func typecheckaste(op Op, call *Node, isddd bool, tstruct *types.Type, nl Nodes, desc func() string) {
|
||||||
var t *types.Type
|
var t *types.Type
|
||||||
var n *Node
|
|
||||||
var n1 int
|
var n1 int
|
||||||
var n2 int
|
var n2 int
|
||||||
var i int
|
var i int
|
||||||
|
|
||||||
lno := lineno
|
lno := lineno
|
||||||
|
defer func() { lineno = lno }()
|
||||||
|
|
||||||
if tstruct.Broke() {
|
if tstruct.Broke() {
|
||||||
goto out
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
n = nil
|
var n *Node
|
||||||
if nl.Len() == 1 {
|
if nl.Len() == 1 {
|
||||||
n = nl.First()
|
n = nl.First()
|
||||||
if n.Type != nil && n.Type.IsFuncArgStruct() {
|
if n.Type != nil && n.Type.IsFuncArgStruct() {
|
||||||
|
|
@ -2587,7 +2587,7 @@ func typecheckaste(op Op, call *Node, isddd bool, tstruct *types.Type, nl Nodes,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
goto out
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if i >= len(rfs) {
|
if i >= len(rfs) {
|
||||||
|
|
@ -2606,7 +2606,7 @@ func typecheckaste(op Op, call *Node, isddd bool, tstruct *types.Type, nl Nodes,
|
||||||
if len(rfs) > len(lfs) {
|
if len(rfs) > len(lfs) {
|
||||||
goto toomany
|
goto toomany
|
||||||
}
|
}
|
||||||
goto out
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2650,7 +2650,7 @@ func typecheckaste(op Op, call *Node, isddd bool, tstruct *types.Type, nl Nodes,
|
||||||
if n.Type != nil {
|
if n.Type != nil {
|
||||||
nl.SetIndex(i, assignconvfn(n, t, desc))
|
nl.SetIndex(i, assignconvfn(n, t, desc))
|
||||||
}
|
}
|
||||||
goto out
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for ; i < nl.Len(); i++ {
|
for ; i < nl.Len(); i++ {
|
||||||
|
|
@ -2660,8 +2660,7 @@ func typecheckaste(op Op, call *Node, isddd bool, tstruct *types.Type, nl Nodes,
|
||||||
nl.SetIndex(i, assignconvfn(n, t.Elem(), desc))
|
nl.SetIndex(i, assignconvfn(n, t.Elem(), desc))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return
|
||||||
goto out
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if i >= nl.Len() {
|
if i >= nl.Len() {
|
||||||
|
|
@ -2685,9 +2684,6 @@ func typecheckaste(op Op, call *Node, isddd bool, tstruct *types.Type, nl Nodes,
|
||||||
yyerror("invalid use of ... in %v", op)
|
yyerror("invalid use of ... in %v", op)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
|
||||||
lineno = lno
|
|
||||||
return
|
return
|
||||||
|
|
||||||
notenough:
|
notenough:
|
||||||
|
|
@ -2709,8 +2705,7 @@ notenough:
|
||||||
n.SetDiag(true)
|
n.SetDiag(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return
|
||||||
goto out
|
|
||||||
|
|
||||||
toomany:
|
toomany:
|
||||||
details := errorDetails(nl, tstruct, isddd)
|
details := errorDetails(nl, tstruct, isddd)
|
||||||
|
|
@ -2719,7 +2714,6 @@ toomany:
|
||||||
} else {
|
} else {
|
||||||
yyerror("too many arguments to %v%s", op, details)
|
yyerror("too many arguments to %v%s", op, details)
|
||||||
}
|
}
|
||||||
goto out
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func errorDetails(nl Nodes, tstruct *types.Type, isddd bool) string {
|
func errorDetails(nl Nodes, tstruct *types.Type, isddd bool) string {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue