mirror of
https://github.com/golang/go
synced 2024-11-11 19:51:37 -07:00
[dev.regabi] cmd/compile: cleanup for concrete types - range, select, swt
An automated rewrite will add concrete type assertions after a test of n.Op(), when n can be safely type-asserted (meaning, n is not reassigned a different type, n is not reassigned and then used outside the scope of the type assertion, and so on). This sequence of CLs handles the code that the automated rewrite does not: adding specific types to function arguments, adjusting code not to call n.Left() etc when n may have multiple representations, and so on. This CL focuses on range.go, select.go, and swt.go: the big control structures. Passes buildall w/ toolstash -cmp. Change-Id: I033fe056a7b815edb6e8a06f45c12ffd990f4d45 Reviewed-on: https://go-review.googlesource.com/c/go/+/277929 Trust: Russ Cox <rsc@golang.org> Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
parent
42fec2ded4
commit
dd67b13d07
@ -13,7 +13,7 @@ import (
|
||||
)
|
||||
|
||||
// range
|
||||
func typecheckrange(n ir.Node) {
|
||||
func typecheckrange(n *ir.RangeStmt) {
|
||||
// Typechecking order is important here:
|
||||
// 0. first typecheck range expression (slice/map/chan),
|
||||
// it is evaluated only once and so logically it is not part of the loop.
|
||||
@ -39,7 +39,7 @@ func typecheckrange(n ir.Node) {
|
||||
decldepth--
|
||||
}
|
||||
|
||||
func typecheckrangeExpr(n ir.Node) {
|
||||
func typecheckrangeExpr(n *ir.RangeStmt) {
|
||||
n.SetRight(typecheck(n.Right(), ctxExpr))
|
||||
|
||||
t := n.Right().Type()
|
||||
@ -157,7 +157,7 @@ func cheapComputableIndex(width int64) bool {
|
||||
// simpler forms. The result must be assigned back to n.
|
||||
// Node n may also be modified in place, and may also be
|
||||
// the returned node.
|
||||
func walkrange(nrange ir.Node) ir.Node {
|
||||
func walkrange(nrange *ir.RangeStmt) ir.Node {
|
||||
if isMapClear(nrange) {
|
||||
m := nrange.Right()
|
||||
lno := setlineno(m)
|
||||
@ -204,7 +204,7 @@ func walkrange(nrange ir.Node) ir.Node {
|
||||
base.Fatalf("walkrange: v2 != nil while v1 == nil")
|
||||
}
|
||||
|
||||
var ifGuard ir.Node
|
||||
var ifGuard *ir.IfStmt
|
||||
|
||||
var body []ir.Node
|
||||
var init []ir.Node
|
||||
@ -267,7 +267,7 @@ func walkrange(nrange ir.Node) ir.Node {
|
||||
// TODO(austin): OFORUNTIL inhibits bounds-check
|
||||
// elimination on the index variable (see #20711).
|
||||
// Enhance the prove pass to understand this.
|
||||
ifGuard = ir.Nod(ir.OIF, nil, nil)
|
||||
ifGuard = ir.NewIfStmt(base.Pos, nil, nil, nil)
|
||||
ifGuard.SetLeft(ir.Nod(ir.OLT, hv1, hn))
|
||||
nfor.SetOp(ir.OFORUNTIL)
|
||||
|
||||
@ -426,7 +426,7 @@ func walkrange(nrange ir.Node) ir.Node {
|
||||
|
||||
if ifGuard != nil {
|
||||
ifGuard.PtrInit().Append(init...)
|
||||
ifGuard = typecheck(ifGuard, ctxStmt)
|
||||
ifGuard = typecheck(ifGuard, ctxStmt).(*ir.IfStmt)
|
||||
} else {
|
||||
nfor.PtrInit().Append(init...)
|
||||
}
|
||||
@ -459,7 +459,7 @@ func walkrange(nrange ir.Node) ir.Node {
|
||||
// }
|
||||
//
|
||||
// where == for keys of map m is reflexive.
|
||||
func isMapClear(n ir.Node) bool {
|
||||
func isMapClear(n *ir.RangeStmt) bool {
|
||||
if base.Flag.N != 0 || instrumenting {
|
||||
return false
|
||||
}
|
||||
@ -488,7 +488,7 @@ func isMapClear(n ir.Node) bool {
|
||||
}
|
||||
|
||||
m := n.Right()
|
||||
if !samesafeexpr(stmt.List().First(), m) || !samesafeexpr(stmt.List().Second(), k) {
|
||||
if delete := stmt.(*ir.CallExpr); !samesafeexpr(delete.List().First(), m) || !samesafeexpr(delete.List().Second(), k) {
|
||||
return false
|
||||
}
|
||||
|
||||
@ -508,11 +508,7 @@ func mapClear(m ir.Node) ir.Node {
|
||||
fn := syslook("mapclear")
|
||||
fn = substArgTypes(fn, t.Key(), t.Elem())
|
||||
n := mkcall1(fn, nil, nil, typename(t), m)
|
||||
|
||||
n = typecheck(n, ctxStmt)
|
||||
n = walkstmt(n)
|
||||
|
||||
return n
|
||||
return walkstmt(typecheck(n, ctxStmt))
|
||||
}
|
||||
|
||||
// Lower n into runtime·memclr if possible, for
|
||||
@ -526,7 +522,7 @@ func mapClear(m ir.Node) ir.Node {
|
||||
// in which the evaluation of a is side-effect-free.
|
||||
//
|
||||
// Parameters are as in walkrange: "for v1, v2 = range a".
|
||||
func arrayClear(loop, v1, v2, a ir.Node) ir.Node {
|
||||
func arrayClear(loop *ir.RangeStmt, v1, v2, a ir.Node) ir.Node {
|
||||
if base.Flag.N != 0 || instrumenting {
|
||||
return nil
|
||||
}
|
||||
@ -539,12 +535,17 @@ func arrayClear(loop, v1, v2, a ir.Node) ir.Node {
|
||||
return nil
|
||||
}
|
||||
|
||||
stmt := loop.Body().First() // only stmt in body
|
||||
if stmt.Op() != ir.OAS || stmt.Left().Op() != ir.OINDEX {
|
||||
stmt1 := loop.Body().First() // only stmt in body
|
||||
if stmt1.Op() != ir.OAS {
|
||||
return nil
|
||||
}
|
||||
stmt := stmt1.(*ir.AssignStmt)
|
||||
if stmt.Left().Op() != ir.OINDEX {
|
||||
return nil
|
||||
}
|
||||
lhs := stmt.Left().(*ir.IndexExpr)
|
||||
|
||||
if !samesafeexpr(stmt.Left().Left(), a) || !samesafeexpr(stmt.Left().Right(), v1) {
|
||||
if !samesafeexpr(lhs.Left(), a) || !samesafeexpr(lhs.Right(), v1) {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -11,15 +11,12 @@ import (
|
||||
)
|
||||
|
||||
// select
|
||||
func typecheckselect(sel ir.Node) {
|
||||
func typecheckselect(sel *ir.SelectStmt) {
|
||||
var def ir.Node
|
||||
lno := setlineno(sel)
|
||||
typecheckslice(sel.Init().Slice(), ctxStmt)
|
||||
for _, ncase := range sel.List().Slice() {
|
||||
if ncase.Op() != ir.OCASE {
|
||||
setlineno(ncase)
|
||||
base.Fatalf("typecheckselect %v", ncase.Op())
|
||||
}
|
||||
ncase := ncase.(*ir.CaseStmt)
|
||||
|
||||
if ncase.List().Len() == 0 {
|
||||
// default
|
||||
@ -51,8 +48,10 @@ func typecheckselect(sel ir.Node) {
|
||||
// convert x = <-c into OSELRECV(x, <-c).
|
||||
// remove implicit conversions; the eventual assignment
|
||||
// will reintroduce them.
|
||||
if (n.Right().Op() == ir.OCONVNOP || n.Right().Op() == ir.OCONVIFACE) && n.Right().Implicit() {
|
||||
n.SetRight(n.Right().Left())
|
||||
if r := n.Right(); r.Op() == ir.OCONVNOP || r.Op() == ir.OCONVIFACE {
|
||||
if r.Implicit() {
|
||||
n.SetRight(r.Left())
|
||||
}
|
||||
}
|
||||
if n.Right().Op() != ir.ORECV {
|
||||
base.ErrorfAt(n.Pos(), "select assignment must have receive on right hand side")
|
||||
@ -70,9 +69,10 @@ func typecheckselect(sel ir.Node) {
|
||||
|
||||
case ir.ORECV:
|
||||
// convert <-c into OSELRECV(_, <-c)
|
||||
n = ir.NodAt(n.Pos(), ir.OAS, ir.BlankNode, n)
|
||||
n.SetOp(ir.OSELRECV)
|
||||
n.SetTypecheck(1)
|
||||
as := ir.NewAssignStmt(n.Pos(), ir.BlankNode, n)
|
||||
as.SetOp(ir.OSELRECV)
|
||||
as.SetTypecheck(1)
|
||||
n = as
|
||||
ncase.SetLeft(n)
|
||||
|
||||
case ir.OSEND:
|
||||
@ -86,7 +86,7 @@ func typecheckselect(sel ir.Node) {
|
||||
base.Pos = lno
|
||||
}
|
||||
|
||||
func walkselect(sel ir.Node) {
|
||||
func walkselect(sel *ir.SelectStmt) {
|
||||
lno := setlineno(sel)
|
||||
if sel.Body().Len() != 0 {
|
||||
base.Fatalf("double walkselect")
|
||||
@ -95,8 +95,8 @@ func walkselect(sel ir.Node) {
|
||||
init := sel.Init().Slice()
|
||||
sel.PtrInit().Set(nil)
|
||||
|
||||
init = append(init, walkselectcases(sel.PtrList())...)
|
||||
sel.PtrList().Set(nil)
|
||||
init = append(init, walkselectcases(sel.List())...)
|
||||
sel.SetList(ir.Nodes{})
|
||||
|
||||
sel.PtrBody().Set(init)
|
||||
walkstmtlist(sel.Body().Slice())
|
||||
@ -104,7 +104,7 @@ func walkselect(sel ir.Node) {
|
||||
base.Pos = lno
|
||||
}
|
||||
|
||||
func walkselectcases(cases *ir.Nodes) []ir.Node {
|
||||
func walkselectcases(cases ir.Nodes) []ir.Node {
|
||||
ncas := cases.Len()
|
||||
sellineno := base.Pos
|
||||
|
||||
@ -115,7 +115,7 @@ func walkselectcases(cases *ir.Nodes) []ir.Node {
|
||||
|
||||
// optimization: one-case select: single op.
|
||||
if ncas == 1 {
|
||||
cas := cases.First()
|
||||
cas := cases.First().(*ir.CaseStmt)
|
||||
setlineno(cas)
|
||||
l := cas.Init().Slice()
|
||||
if cas.Left() != nil { // not default:
|
||||
@ -130,18 +130,20 @@ func walkselectcases(cases *ir.Nodes) []ir.Node {
|
||||
// already ok
|
||||
|
||||
case ir.OSELRECV:
|
||||
if ir.IsBlank(n.Left()) {
|
||||
n = n.Right()
|
||||
r := n.(*ir.AssignStmt)
|
||||
if ir.IsBlank(r.Left()) {
|
||||
n = r.Right()
|
||||
break
|
||||
}
|
||||
n.SetOp(ir.OAS)
|
||||
r.SetOp(ir.OAS)
|
||||
|
||||
case ir.OSELRECV2:
|
||||
if ir.IsBlank(n.List().First()) && ir.IsBlank(n.List().Second()) {
|
||||
n = n.Rlist().First()
|
||||
r := n.(*ir.AssignListStmt)
|
||||
if ir.IsBlank(r.List().First()) && ir.IsBlank(r.List().Second()) {
|
||||
n = r.Rlist().First()
|
||||
break
|
||||
}
|
||||
n.SetOp(ir.OAS2RECV)
|
||||
r.SetOp(ir.OAS2RECV)
|
||||
}
|
||||
|
||||
l = append(l, n)
|
||||
@ -154,8 +156,9 @@ func walkselectcases(cases *ir.Nodes) []ir.Node {
|
||||
|
||||
// convert case value arguments to addresses.
|
||||
// this rewrite is used by both the general code and the next optimization.
|
||||
var dflt ir.Node
|
||||
var dflt *ir.CaseStmt
|
||||
for _, cas := range cases.Slice() {
|
||||
cas := cas.(*ir.CaseStmt)
|
||||
setlineno(cas)
|
||||
n := cas.Left()
|
||||
if n == nil {
|
||||
@ -164,11 +167,14 @@ func walkselectcases(cases *ir.Nodes) []ir.Node {
|
||||
}
|
||||
|
||||
// Lower x, _ = <-c to x = <-c.
|
||||
if n.Op() == ir.OSELRECV2 && ir.IsBlank(n.List().Second()) {
|
||||
n = ir.NodAt(n.Pos(), ir.OAS, n.List().First(), n.Rlist().First())
|
||||
n.SetOp(ir.OSELRECV)
|
||||
n.SetTypecheck(1)
|
||||
cas.SetLeft(n)
|
||||
if sel := n; sel.Op() == ir.OSELRECV2 {
|
||||
if ir.IsBlank(sel.List().Second()) {
|
||||
as := ir.NewAssignStmt(sel.Pos(), sel.List().First(), sel.Rlist().First())
|
||||
as.SetOp(ir.OSELRECV)
|
||||
as.SetTypecheck(1)
|
||||
n = as
|
||||
cas.SetLeft(n)
|
||||
}
|
||||
}
|
||||
|
||||
switch n.Op() {
|
||||
@ -192,9 +198,9 @@ func walkselectcases(cases *ir.Nodes) []ir.Node {
|
||||
|
||||
// optimization: two-case select but one is default: single non-blocking op.
|
||||
if ncas == 2 && dflt != nil {
|
||||
cas := cases.First()
|
||||
cas := cases.First().(*ir.CaseStmt)
|
||||
if cas == dflt {
|
||||
cas = cases.Second()
|
||||
cas = cases.Second().(*ir.CaseStmt)
|
||||
}
|
||||
|
||||
n := cas.Left()
|
||||
@ -213,7 +219,8 @@ func walkselectcases(cases *ir.Nodes) []ir.Node {
|
||||
|
||||
case ir.OSELRECV:
|
||||
// if selectnbrecv(&v, c) { body } else { default body }
|
||||
ch := n.Right().Left()
|
||||
recv := n.Right().(*ir.UnaryExpr)
|
||||
ch := recv.Left()
|
||||
elem := n.Left()
|
||||
if ir.IsBlank(elem) {
|
||||
elem = nodnil()
|
||||
@ -222,7 +229,8 @@ func walkselectcases(cases *ir.Nodes) []ir.Node {
|
||||
|
||||
case ir.OSELRECV2:
|
||||
// if selectnbrecv2(&v, &received, c) { body } else { default body }
|
||||
ch := n.Rlist().First().Left()
|
||||
recv := n.Rlist().First().(*ir.UnaryExpr)
|
||||
ch := recv.Left()
|
||||
elem := n.List().First()
|
||||
if ir.IsBlank(elem) {
|
||||
elem = nodnil()
|
||||
@ -240,7 +248,7 @@ func walkselectcases(cases *ir.Nodes) []ir.Node {
|
||||
if dflt != nil {
|
||||
ncas--
|
||||
}
|
||||
casorder := make([]ir.Node, ncas)
|
||||
casorder := make([]*ir.CaseStmt, ncas)
|
||||
nsends, nrecvs := 0, 0
|
||||
|
||||
var init []ir.Node
|
||||
@ -263,6 +271,7 @@ func walkselectcases(cases *ir.Nodes) []ir.Node {
|
||||
|
||||
// register cases
|
||||
for _, cas := range cases.Slice() {
|
||||
cas := cas.(*ir.CaseStmt)
|
||||
setlineno(cas)
|
||||
|
||||
init = append(init, cas.Init().Slice()...)
|
||||
@ -286,12 +295,14 @@ func walkselectcases(cases *ir.Nodes) []ir.Node {
|
||||
case ir.OSELRECV:
|
||||
nrecvs++
|
||||
i = ncas - nrecvs
|
||||
c = n.Right().Left()
|
||||
recv := n.Right().(*ir.UnaryExpr)
|
||||
c = recv.Left()
|
||||
elem = n.Left()
|
||||
case ir.OSELRECV2:
|
||||
nrecvs++
|
||||
i = ncas - nrecvs
|
||||
c = n.Rlist().First().Left()
|
||||
recv := n.Rlist().First().(*ir.UnaryExpr)
|
||||
c = recv.Left()
|
||||
elem = n.List().First()
|
||||
}
|
||||
|
||||
@ -338,7 +349,7 @@ func walkselectcases(cases *ir.Nodes) []ir.Node {
|
||||
}
|
||||
|
||||
// dispatch cases
|
||||
dispatch := func(cond, cas ir.Node) {
|
||||
dispatch := func(cond ir.Node, cas *ir.CaseStmt) {
|
||||
cond = typecheck(cond, ctxExpr)
|
||||
cond = defaultlit(cond, nil)
|
||||
|
||||
|
@ -15,7 +15,7 @@ import (
|
||||
)
|
||||
|
||||
// typecheckswitch typechecks a switch statement.
|
||||
func typecheckswitch(n ir.Node) {
|
||||
func typecheckswitch(n *ir.SwitchStmt) {
|
||||
typecheckslice(n.Init().Slice(), ctxStmt)
|
||||
if n.Left() != nil && n.Left().Op() == ir.OTYPESW {
|
||||
typecheckTypeSwitch(n)
|
||||
@ -24,24 +24,26 @@ func typecheckswitch(n ir.Node) {
|
||||
}
|
||||
}
|
||||
|
||||
func typecheckTypeSwitch(n ir.Node) {
|
||||
n.Left().SetRight(typecheck(n.Left().Right(), ctxExpr))
|
||||
t := n.Left().Right().Type()
|
||||
func typecheckTypeSwitch(n *ir.SwitchStmt) {
|
||||
guard := n.Left().(*ir.TypeSwitchGuard)
|
||||
guard.SetRight(typecheck(guard.Right(), ctxExpr))
|
||||
t := guard.Right().Type()
|
||||
if t != nil && !t.IsInterface() {
|
||||
base.ErrorfAt(n.Pos(), "cannot type switch on non-interface value %L", n.Left().Right())
|
||||
base.ErrorfAt(n.Pos(), "cannot type switch on non-interface value %L", guard.Right())
|
||||
t = nil
|
||||
}
|
||||
|
||||
// We don't actually declare the type switch's guarded
|
||||
// declaration itself. So if there are no cases, we won't
|
||||
// notice that it went unused.
|
||||
if v := n.Left().Left(); v != nil && !ir.IsBlank(v) && n.List().Len() == 0 {
|
||||
if v := guard.Left(); v != nil && !ir.IsBlank(v) && n.List().Len() == 0 {
|
||||
base.ErrorfAt(v.Pos(), "%v declared but not used", v.Sym())
|
||||
}
|
||||
|
||||
var defCase, nilCase ir.Node
|
||||
var ts typeSet
|
||||
for _, ncase := range n.List().Slice() {
|
||||
ncase := ncase.(*ir.CaseStmt)
|
||||
ls := ncase.List().Slice()
|
||||
if len(ls) == 0 { // default:
|
||||
if defCase != nil {
|
||||
@ -60,31 +62,33 @@ func typecheckTypeSwitch(n ir.Node) {
|
||||
|
||||
var missing, have *types.Field
|
||||
var ptr int
|
||||
switch {
|
||||
case ir.IsNil(n1): // case nil:
|
||||
if ir.IsNil(n1) { // case nil:
|
||||
if nilCase != nil {
|
||||
base.ErrorfAt(ncase.Pos(), "multiple nil cases in type switch (first at %v)", ir.Line(nilCase))
|
||||
} else {
|
||||
nilCase = ncase
|
||||
}
|
||||
case n1.Op() != ir.OTYPE:
|
||||
continue
|
||||
}
|
||||
if n1.Op() != ir.OTYPE {
|
||||
base.ErrorfAt(ncase.Pos(), "%L is not a type", n1)
|
||||
case !n1.Type().IsInterface() && !implements(n1.Type(), t, &missing, &have, &ptr) && !missing.Broke():
|
||||
continue
|
||||
}
|
||||
if !n1.Type().IsInterface() && !implements(n1.Type(), t, &missing, &have, &ptr) && !missing.Broke() {
|
||||
if have != nil && !have.Broke() {
|
||||
base.ErrorfAt(ncase.Pos(), "impossible type switch case: %L cannot have dynamic type %v"+
|
||||
" (wrong type for %v method)\n\thave %v%S\n\twant %v%S", n.Left().Right(), n1.Type(), missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
|
||||
" (wrong type for %v method)\n\thave %v%S\n\twant %v%S", guard.Right(), n1.Type(), missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
|
||||
} else if ptr != 0 {
|
||||
base.ErrorfAt(ncase.Pos(), "impossible type switch case: %L cannot have dynamic type %v"+
|
||||
" (%v method has pointer receiver)", n.Left().Right(), n1.Type(), missing.Sym)
|
||||
" (%v method has pointer receiver)", guard.Right(), n1.Type(), missing.Sym)
|
||||
} else {
|
||||
base.ErrorfAt(ncase.Pos(), "impossible type switch case: %L cannot have dynamic type %v"+
|
||||
" (missing %v method)", n.Left().Right(), n1.Type(), missing.Sym)
|
||||
" (missing %v method)", guard.Right(), n1.Type(), missing.Sym)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if n1.Op() == ir.OTYPE {
|
||||
ts.add(ncase.Pos(), n1.Type())
|
||||
}
|
||||
ts.add(ncase.Pos(), n1.Type())
|
||||
}
|
||||
|
||||
if ncase.Rlist().Len() != 0 {
|
||||
@ -144,7 +148,7 @@ func (s *typeSet) add(pos src.XPos, typ *types.Type) {
|
||||
s.m[ls] = append(prevs, typeSetEntry{pos, typ})
|
||||
}
|
||||
|
||||
func typecheckExprSwitch(n ir.Node) {
|
||||
func typecheckExprSwitch(n *ir.SwitchStmt) {
|
||||
t := types.Types[types.TBOOL]
|
||||
if n.Left() != nil {
|
||||
n.SetLeft(typecheck(n.Left(), ctxExpr))
|
||||
@ -175,6 +179,7 @@ func typecheckExprSwitch(n ir.Node) {
|
||||
var defCase ir.Node
|
||||
var cs constSet
|
||||
for _, ncase := range n.List().Slice() {
|
||||
ncase := ncase.(*ir.CaseStmt)
|
||||
ls := ncase.List().Slice()
|
||||
if len(ls) == 0 { // default:
|
||||
if defCase != nil {
|
||||
@ -225,7 +230,7 @@ func typecheckExprSwitch(n ir.Node) {
|
||||
}
|
||||
|
||||
// walkswitch walks a switch statement.
|
||||
func walkswitch(sw ir.Node) {
|
||||
func walkswitch(sw *ir.SwitchStmt) {
|
||||
// Guard against double walk, see #25776.
|
||||
if sw.List().Len() == 0 && sw.Body().Len() > 0 {
|
||||
return // Was fatal, but eliminating every possible source of double-walking is hard
|
||||
@ -240,7 +245,7 @@ func walkswitch(sw ir.Node) {
|
||||
|
||||
// walkExprSwitch generates an AST implementing sw. sw is an
|
||||
// expression switch.
|
||||
func walkExprSwitch(sw ir.Node) {
|
||||
func walkExprSwitch(sw *ir.SwitchStmt) {
|
||||
lno := setlineno(sw)
|
||||
|
||||
cond := sw.Left()
|
||||
@ -278,6 +283,7 @@ func walkExprSwitch(sw ir.Node) {
|
||||
var defaultGoto ir.Node
|
||||
var body ir.Nodes
|
||||
for _, ncase := range sw.List().Slice() {
|
||||
ncase := ncase.(*ir.CaseStmt)
|
||||
label := autolabel(".s")
|
||||
jmp := npos(ncase.Pos(), nodSym(ir.OGOTO, nil, label))
|
||||
|
||||
@ -393,7 +399,7 @@ func (s *exprSwitch) flush() {
|
||||
func(i int) ir.Node {
|
||||
return ir.Nod(ir.OLE, ir.Nod(ir.OLEN, s.exprname, nil), nodintconst(runLen(runs[i-1])))
|
||||
},
|
||||
func(i int, nif ir.Node) {
|
||||
func(i int, nif *ir.IfStmt) {
|
||||
run := runs[i]
|
||||
nif.SetLeft(ir.Nod(ir.OEQ, ir.Nod(ir.OLEN, s.exprname, nil), nodintconst(runLen(run))))
|
||||
s.search(run, nif.PtrBody())
|
||||
@ -428,7 +434,7 @@ func (s *exprSwitch) search(cc []exprClause, out *ir.Nodes) {
|
||||
func(i int) ir.Node {
|
||||
return ir.Nod(ir.OLE, s.exprname, cc[i-1].hi)
|
||||
},
|
||||
func(i int, nif ir.Node) {
|
||||
func(i int, nif *ir.IfStmt) {
|
||||
c := &cc[i]
|
||||
nif.SetLeft(c.test(s.exprname))
|
||||
nif.PtrBody().Set1(c.jmp)
|
||||
@ -456,7 +462,7 @@ func (c *exprClause) test(exprname ir.Node) ir.Node {
|
||||
return ir.NodAt(c.pos, ir.OEQ, exprname, c.lo)
|
||||
}
|
||||
|
||||
func allCaseExprsAreSideEffectFree(sw ir.Node) bool {
|
||||
func allCaseExprsAreSideEffectFree(sw *ir.SwitchStmt) bool {
|
||||
// In theory, we could be more aggressive, allowing any
|
||||
// side-effect-free expressions in cases, but it's a bit
|
||||
// tricky because some of that information is unavailable due
|
||||
@ -465,9 +471,7 @@ func allCaseExprsAreSideEffectFree(sw ir.Node) bool {
|
||||
// enough.
|
||||
|
||||
for _, ncase := range sw.List().Slice() {
|
||||
if ncase.Op() != ir.OCASE {
|
||||
base.Fatalf("switch string(byteslice) bad op: %v", ncase.Op())
|
||||
}
|
||||
ncase := ncase.(*ir.CaseStmt)
|
||||
for _, v := range ncase.List().Slice() {
|
||||
if v.Op() != ir.OLITERAL {
|
||||
return false
|
||||
@ -497,9 +501,9 @@ func hasFall(stmts []ir.Node) (bool, src.XPos) {
|
||||
|
||||
// walkTypeSwitch generates an AST that implements sw, where sw is a
|
||||
// type switch.
|
||||
func walkTypeSwitch(sw ir.Node) {
|
||||
func walkTypeSwitch(sw *ir.SwitchStmt) {
|
||||
var s typeSwitch
|
||||
s.facename = sw.Left().Right()
|
||||
s.facename = sw.Left().(*ir.TypeSwitchGuard).Right()
|
||||
sw.SetLeft(nil)
|
||||
|
||||
s.facename = walkexpr(s.facename, sw.PtrInit())
|
||||
@ -541,6 +545,7 @@ func walkTypeSwitch(sw ir.Node) {
|
||||
var defaultGoto, nilGoto ir.Node
|
||||
var body ir.Nodes
|
||||
for _, ncase := range sw.List().Slice() {
|
||||
ncase := ncase.(*ir.CaseStmt)
|
||||
var caseVar ir.Node
|
||||
if ncase.Rlist().Len() != 0 {
|
||||
caseVar = ncase.Rlist().First()
|
||||
@ -704,7 +709,7 @@ func (s *typeSwitch) flush() {
|
||||
func(i int) ir.Node {
|
||||
return ir.Nod(ir.OLE, s.hashname, nodintconst(int64(cc[i-1].hash)))
|
||||
},
|
||||
func(i int, nif ir.Node) {
|
||||
func(i int, nif *ir.IfStmt) {
|
||||
// TODO(mdempsky): Omit hash equality check if
|
||||
// there's only one type.
|
||||
c := cc[i]
|
||||
@ -723,7 +728,7 @@ func (s *typeSwitch) flush() {
|
||||
//
|
||||
// leaf(i, nif) should setup nif (an OIF node) to test case i. In
|
||||
// particular, it should set nif.Left and nif.Nbody.
|
||||
func binarySearch(n int, out *ir.Nodes, less func(i int) ir.Node, leaf func(i int, nif ir.Node)) {
|
||||
func binarySearch(n int, out *ir.Nodes, less func(i int) ir.Node, leaf func(i int, nif *ir.IfStmt)) {
|
||||
const binarySearchMin = 4 // minimum number of cases for binary search
|
||||
|
||||
var do func(lo, hi int, out *ir.Nodes)
|
||||
@ -731,7 +736,7 @@ func binarySearch(n int, out *ir.Nodes, less func(i int) ir.Node, leaf func(i in
|
||||
n := hi - lo
|
||||
if n < binarySearchMin {
|
||||
for i := lo; i < hi; i++ {
|
||||
nif := ir.Nod(ir.OIF, nil, nil)
|
||||
nif := ir.NewIfStmt(base.Pos, nil, nil, nil)
|
||||
leaf(i, nif)
|
||||
base.Pos = base.Pos.WithNotStmt()
|
||||
nif.SetLeft(typecheck(nif.Left(), ctxExpr))
|
||||
|
@ -349,14 +349,17 @@ func walkstmt(n ir.Node) ir.Node {
|
||||
return n
|
||||
|
||||
case ir.OSELECT:
|
||||
n := n.(*ir.SelectStmt)
|
||||
walkselect(n)
|
||||
return n
|
||||
|
||||
case ir.OSWITCH:
|
||||
n := n.(*ir.SwitchStmt)
|
||||
walkswitch(n)
|
||||
return n
|
||||
|
||||
case ir.ORANGE:
|
||||
n := n.(*ir.RangeStmt)
|
||||
return walkrange(n)
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user