From 1b2c7948963543286516f78f0b0d52956f58d82c Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Fri, 13 Sep 2019 15:13:22 -0700 Subject: [PATCH] cmd/compile: tweak OIF construction for binarySearch When emitting base cases, previously we would emit: if c1 { s1 } if c2 { s2 } if c3 { s3 } With this CL, we instead emit: if c1 { s1 } else if c2 { s2 } else if c3 { s3 } Most of the time, this doesn't make a difference, because s1/s2/s3 are typically "goto" statements. But for type switches, we currently emit: if hash == 271 { if _, ok := iface.(T1); ok { goto t1case } } if hash == 314 { if _, ok := iface.(T2); ok { goto t2case } } That is, the if bodies can fallthrough, even though it's impossible for them to match any of the subsequent cases. Change-Id: I453d424d0b5e40060a703738bbb374523f1c403c Reviewed-on: https://go-review.googlesource.com/c/go/+/195339 Run-TryBot: Matthew Dempsky TryBot-Result: Gobot Gobot Reviewed-by: Keith Randall --- src/cmd/compile/internal/gc/swt.go | 34 ++++++++++++++---------------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/src/cmd/compile/internal/gc/swt.go b/src/cmd/compile/internal/gc/swt.go index 4a8e9bceed..004ff3c4c0 100644 --- a/src/cmd/compile/internal/gc/swt.go +++ b/src/cmd/compile/internal/gc/swt.go @@ -397,14 +397,10 @@ func (s *exprSwitch) flush() { } return le }, - func(i int, out *Nodes) { + func(i int, nif *Node) { c := &cc[i] - - nif := nodl(c.pos, OIF, c.test(s.exprname), nil) - nif.Left = typecheck(nif.Left, ctxExpr) - nif.Left = defaultlit(nif.Left, nil) + nif.Left = c.test(s.exprname) nif.Nbody.Set1(c.jmp) - out.Append(nif) }, ) } @@ -521,8 +517,8 @@ func walkTypeSwitch(sw *Node) { singleType := ncase.List.Len() == 1 && ncase.List.First().Op == OTYPE label := autolabel(".s") - jmp := npos(ncase.Pos, nodSym(OGOTO, nil, label)) + if ncase.List.Len() == 0 { // default: if defaultGoto != nil { Fatalf("duplicate default case not detected during typechecking") @@ -672,16 +668,12 @@ func (s *typeSwitch) flush() { func(i int) *Node { return nod(OLE, s.hashname, nodintconst(int64(cc[i-1].hash))) }, - func(i int, out *Nodes) { + func(i int, nif *Node) { // TODO(mdempsky): Omit hash equality check if // there's only one type. c := cc[i] - a := nod(OIF, nil, nil) - a.Left = nod(OEQ, s.hashname, nodintconst(int64(c.hash))) - a.Left = typecheck(a.Left, ctxExpr) - a.Left = defaultlit(a.Left, nil) - a.Nbody.AppendNodes(&c.body) - out.Append(a) + nif.Left = nod(OEQ, s.hashname, nodintconst(int64(c.hash))) + nif.Nbody.AppendNodes(&c.body) }, ) } @@ -691,10 +683,11 @@ func (s *typeSwitch) flush() { // switch statements. // // less(i) should return a boolean expression. If it evaluates true, -// then cases [0, i) will be tested; otherwise, cases [i, n). +// then cases before i will be tested; otherwise, cases i and later. // -// base(i, out) should append statements to out to test the i'th case. -func binarySearch(n int, out *Nodes, less func(i int) *Node, base func(i int, out *Nodes)) { +// base(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 *Nodes, less func(i int) *Node, base func(i int, nif *Node)) { const binarySearchMin = 4 // minimum number of cases for binary search var do func(lo, hi int, out *Nodes) @@ -702,7 +695,12 @@ func binarySearch(n int, out *Nodes, less func(i int) *Node, base func(i int, ou n := hi - lo if n < binarySearchMin { for i := lo; i < hi; i++ { - base(i, out) + nif := nod(OIF, nil, nil) + base(i, nif) + nif.Left = typecheck(nif.Left, ctxExpr) + nif.Left = defaultlit(nif.Left, nil) + out.Append(nif) + out = &nif.Rlist } return } -- 2.50.0