Commit 7f88d3c1 authored by Daniel Martí's avatar Daniel Martí

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: default avatarMatthew Dempsky <mdempsky@google.com>
parent 1722a2d7
...@@ -13,14 +13,6 @@ import ( ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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 { ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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: ...@@ -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: ...@@ -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 {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment