Commit b0467865 authored by Josh Bleecher Snyder's avatar Josh Bleecher Snyder

cmd/compile: eliminate switch case kinds

We used to have separate kinds for the default
case and the nil type case. Now that those are
gone, we can use a simple bool instead.

Change-Id: I65488e945df68178e893cddd2e091ebb6e32ef4d
Reviewed-on: https://go-review.googlesource.com/26763
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
Reviewed-by: default avatarMatthew Dempsky <mdempsky@google.com>
parent 4739dcf7
...@@ -16,16 +16,6 @@ const ( ...@@ -16,16 +16,6 @@ const (
switchKindType // switch a.(type) {...} switchKindType // switch a.(type) {...}
) )
const (
// expression switch
caseKindExprConst = iota // case 5:
caseKindExprVar // case x:
// type switch
caseKindTypeConst // case time.Time: (concrete type, has type hash)
caseKindTypeVar // case io.Reader: (interface type)
)
const binarySearchMin = 4 // minimum number of cases for binary search const binarySearchMin = 4 // minimum number of cases for binary search
// An exprSwitch walks an expression switch. // An exprSwitch walks an expression switch.
...@@ -46,7 +36,11 @@ type caseClause struct { ...@@ -46,7 +36,11 @@ type caseClause struct {
node *Node // points at case statement node *Node // points at case statement
ordinal int // position in switch ordinal int // position in switch
hash uint32 // hash of a type switch hash uint32 // hash of a type switch
typ uint8 // type of case // isconst indicates whether this case clause is a constant,
// for the purposes of the switch code generation.
// For expression switches, that's generally literals (case 5:, not case x:).
// For type switches, that's concrete types (case time.Time:), not interfaces (case io.Reader:).
isconst bool
} }
// caseClauses are all the case clauses in a switch statement. // caseClauses are all the case clauses in a switch statement.
...@@ -260,7 +254,7 @@ func (s *exprSwitch) walk(sw *Node) { ...@@ -260,7 +254,7 @@ func (s *exprSwitch) walk(sw *Node) {
// handle the cases in order // handle the cases in order
for len(cc) > 0 { for len(cc) > 0 {
// deal with expressions one at a time // deal with expressions one at a time
if !okforcmp[t.Etype] || cc[0].typ != caseKindExprConst { if !okforcmp[t.Etype] || !cc[0].isconst {
a := s.walkCases(cc[:1]) a := s.walkCases(cc[:1])
cas = append(cas, a) cas = append(cas, a)
cc = cc[1:] cc = cc[1:]
...@@ -269,7 +263,7 @@ func (s *exprSwitch) walk(sw *Node) { ...@@ -269,7 +263,7 @@ func (s *exprSwitch) walk(sw *Node) {
// do binary search on runs of constants // do binary search on runs of constants
var run int var run int
for run = 1; run < len(cc) && cc[run].typ == caseKindExprConst; run++ { for run = 1; run < len(cc) && cc[run].isconst; run++ {
} }
// sort and compile constants // sort and compile constants
...@@ -448,20 +442,13 @@ func genCaseClauses(sw *Node, kind int) caseClauses { ...@@ -448,20 +442,13 @@ func genCaseClauses(sw *Node, kind int) caseClauses {
c := caseClause{node: n, ordinal: len(cc.list)} c := caseClause{node: n, ordinal: len(cc.list)}
if kind == switchKindType { if kind == switchKindType {
// type switch // type switch
switch { c.isconst = !n.Left.Type.IsInterface()
case n.Left.Type.IsInterface():
c.typ = caseKindTypeVar
default:
c.typ = caseKindTypeConst
}
c.hash = typehash(n.Left.Type) c.hash = typehash(n.Left.Type)
} else { } else {
// expression switch // expression switch
switch consttype(n.Left) { switch consttype(n.Left) {
case CTFLT, CTINT, CTRUNE, CTSTR: case CTFLT, CTINT, CTRUNE, CTSTR:
c.typ = caseKindExprConst c.isconst = true
default:
c.typ = caseKindExprVar
} }
} }
cc.list = append(cc.list, c) cc.list = append(cc.list, c)
...@@ -619,18 +606,12 @@ func (s *typeSwitch) walk(sw *Node) { ...@@ -619,18 +606,12 @@ func (s *typeSwitch) walk(sw *Node) {
// insert type equality check into each case block // insert type equality check into each case block
for _, c := range cc { for _, c := range cc {
n := c.node c.node.Right = s.typeone(c.node)
switch c.typ {
case caseKindTypeVar, caseKindTypeConst:
n.Right = s.typeone(n)
default:
Fatalf("typeSwitch with bad kind: %d", c.typ)
}
} }
// generate list of if statements, binary search for constant sequences // generate list of if statements, binary search for constant sequences
for len(cc) > 0 { for len(cc) > 0 {
if cc[0].typ != caseKindTypeConst { if !cc[0].isconst {
n := cc[0].node n := cc[0].node
cas = append(cas, n.Right) cas = append(cas, n.Right)
cc = cc[1:] cc = cc[1:]
...@@ -639,7 +620,7 @@ func (s *typeSwitch) walk(sw *Node) { ...@@ -639,7 +620,7 @@ func (s *typeSwitch) walk(sw *Node) {
// identify run of constants // identify run of constants
var run int var run int
for run = 1; run < len(cc) && cc[run].typ == caseKindTypeConst; run++ { for run = 1; run < len(cc) && cc[run].isconst; run++ {
} }
// sort by hash // sort by hash
...@@ -716,7 +697,7 @@ func (s *typeSwitch) walkCases(cc []caseClause) *Node { ...@@ -716,7 +697,7 @@ func (s *typeSwitch) walkCases(cc []caseClause) *Node {
var cas []*Node var cas []*Node
for _, c := range cc { for _, c := range cc {
n := c.node n := c.node
if c.typ != caseKindTypeConst { if !c.isconst {
Fatalf("typeSwitch walkCases") Fatalf("typeSwitch walkCases")
} }
a := Nod(OIF, nil, nil) a := Nod(OIF, nil, nil)
...@@ -754,10 +735,10 @@ func (x caseClauseByExpr) Less(i, j int) bool { ...@@ -754,10 +735,10 @@ func (x caseClauseByExpr) Less(i, j int) bool {
func exprcmp(c1, c2 caseClause) int { func exprcmp(c1, c2 caseClause) int {
// sort non-constants last // sort non-constants last
if c1.typ != caseKindExprConst { if !c1.isconst {
return +1 return +1
} }
if c2.typ != caseKindExprConst { if !c2.isconst {
return -1 return -1
} }
......
...@@ -16,120 +16,120 @@ func TestExprcmp(t *testing.T) { ...@@ -16,120 +16,120 @@ func TestExprcmp(t *testing.T) {
}{ }{
// Non-constants. // Non-constants.
{ {
caseClause{node: Nod(OXXX, nil, nil), typ: caseKindExprVar}, caseClause{node: Nod(OXXX, nil, nil)},
caseClause{node: Nod(OXXX, nil, nil), typ: caseKindExprConst}, caseClause{node: Nod(OXXX, nil, nil), isconst: true},
+1, +1,
}, },
{ {
caseClause{node: Nod(OXXX, nil, nil), typ: caseKindExprConst}, caseClause{node: Nod(OXXX, nil, nil), isconst: true},
caseClause{node: Nod(OXXX, nil, nil), typ: caseKindExprVar}, caseClause{node: Nod(OXXX, nil, nil)},
-1, -1,
}, },
// Type switches // Type switches
{ {
caseClause{node: Nod(OXXX, Nodintconst(0), nil), typ: caseKindExprConst}, caseClause{node: Nod(OXXX, Nodintconst(0), nil), isconst: true},
caseClause{node: Nod(OXXX, Nodbool(true), nil), typ: caseKindExprConst}, caseClause{node: Nod(OXXX, Nodbool(true), nil), isconst: true},
-1, -1,
}, },
{ {
caseClause{node: Nod(OXXX, Nodbool(true), nil), typ: caseKindExprConst}, caseClause{node: Nod(OXXX, Nodbool(true), nil), isconst: true},
caseClause{node: Nod(OXXX, Nodintconst(1), nil), typ: caseKindExprConst}, caseClause{node: Nod(OXXX, Nodintconst(1), nil), isconst: true},
+1, +1,
}, },
{ {
caseClause{node: Nod(OXXX, &Node{Type: &Type{Etype: TBOOL, Vargen: 1}}, nil), typ: caseKindExprConst}, caseClause{node: Nod(OXXX, &Node{Type: &Type{Etype: TBOOL, Vargen: 1}}, nil), isconst: true},
caseClause{node: Nod(OXXX, &Node{Type: &Type{Etype: TINT, Vargen: 0}}, nil), typ: caseKindExprConst}, caseClause{node: Nod(OXXX, &Node{Type: &Type{Etype: TINT, Vargen: 0}}, nil), isconst: true},
+1, +1,
}, },
{ {
caseClause{node: Nod(OXXX, &Node{Type: &Type{Etype: TBOOL, Vargen: 1}}, nil), typ: caseKindExprConst}, caseClause{node: Nod(OXXX, &Node{Type: &Type{Etype: TBOOL, Vargen: 1}}, nil), isconst: true},
caseClause{node: Nod(OXXX, &Node{Type: &Type{Etype: TINT, Vargen: 1}}, nil), typ: caseKindExprConst}, caseClause{node: Nod(OXXX, &Node{Type: &Type{Etype: TINT, Vargen: 1}}, nil), isconst: true},
-1, -1,
}, },
{ {
caseClause{node: Nod(OXXX, &Node{Type: &Type{Etype: TBOOL, Vargen: 0}}, nil), typ: caseKindExprConst}, caseClause{node: Nod(OXXX, &Node{Type: &Type{Etype: TBOOL, Vargen: 0}}, nil), isconst: true},
caseClause{node: Nod(OXXX, &Node{Type: &Type{Etype: TINT, Vargen: 1}}, nil), typ: caseKindExprConst}, caseClause{node: Nod(OXXX, &Node{Type: &Type{Etype: TINT, Vargen: 1}}, nil), isconst: true},
-1, -1,
}, },
// Constant values. // Constant values.
// CTFLT // CTFLT
{ {
caseClause{node: Nod(OXXX, nodlit(Val{&Mpflt{Val: *big.NewFloat(0.1)}}), nil), typ: caseKindExprConst}, caseClause{node: Nod(OXXX, nodlit(Val{&Mpflt{Val: *big.NewFloat(0.1)}}), nil), isconst: true},
caseClause{node: Nod(OXXX, nodlit(Val{&Mpflt{Val: *big.NewFloat(0.2)}}), nil), typ: caseKindExprConst}, caseClause{node: Nod(OXXX, nodlit(Val{&Mpflt{Val: *big.NewFloat(0.2)}}), nil), isconst: true},
-1, -1,
}, },
{ {
caseClause{node: Nod(OXXX, nodlit(Val{&Mpflt{Val: *big.NewFloat(0.1)}}), nil), typ: caseKindExprConst}, caseClause{node: Nod(OXXX, nodlit(Val{&Mpflt{Val: *big.NewFloat(0.1)}}), nil), isconst: true},
caseClause{node: Nod(OXXX, nodlit(Val{&Mpflt{Val: *big.NewFloat(0.1)}}), nil), typ: caseKindExprConst}, caseClause{node: Nod(OXXX, nodlit(Val{&Mpflt{Val: *big.NewFloat(0.1)}}), nil), isconst: true},
0, 0,
}, },
{ {
caseClause{node: Nod(OXXX, nodlit(Val{&Mpflt{Val: *big.NewFloat(0.2)}}), nil), typ: caseKindExprConst}, caseClause{node: Nod(OXXX, nodlit(Val{&Mpflt{Val: *big.NewFloat(0.2)}}), nil), isconst: true},
caseClause{node: Nod(OXXX, nodlit(Val{&Mpflt{Val: *big.NewFloat(0.1)}}), nil), typ: caseKindExprConst}, caseClause{node: Nod(OXXX, nodlit(Val{&Mpflt{Val: *big.NewFloat(0.1)}}), nil), isconst: true},
+1, +1,
}, },
// CTINT // CTINT
{ {
caseClause{node: Nod(OXXX, Nodintconst(0), nil), typ: caseKindExprConst}, caseClause{node: Nod(OXXX, Nodintconst(0), nil), isconst: true},
caseClause{node: Nod(OXXX, Nodintconst(1), nil), typ: caseKindExprConst}, caseClause{node: Nod(OXXX, Nodintconst(1), nil), isconst: true},
-1, -1,
}, },
{ {
caseClause{node: Nod(OXXX, Nodintconst(1), nil), typ: caseKindExprConst}, caseClause{node: Nod(OXXX, Nodintconst(1), nil), isconst: true},
caseClause{node: Nod(OXXX, Nodintconst(1), nil), typ: caseKindExprConst}, caseClause{node: Nod(OXXX, Nodintconst(1), nil), isconst: true},
0, 0,
}, },
{ {
caseClause{node: Nod(OXXX, Nodintconst(1), nil), typ: caseKindExprConst}, caseClause{node: Nod(OXXX, Nodintconst(1), nil), isconst: true},
caseClause{node: Nod(OXXX, Nodintconst(0), nil), typ: caseKindExprConst}, caseClause{node: Nod(OXXX, Nodintconst(0), nil), isconst: true},
+1, +1,
}, },
// CTRUNE // CTRUNE
{ {
caseClause{node: Nod(OXXX, nodlit(Val{&Mpint{Val: *big.NewInt('a'), Rune: true}}), nil), typ: caseKindExprConst}, caseClause{node: Nod(OXXX, nodlit(Val{&Mpint{Val: *big.NewInt('a'), Rune: true}}), nil), isconst: true},
caseClause{node: Nod(OXXX, nodlit(Val{&Mpint{Val: *big.NewInt('b'), Rune: true}}), nil), typ: caseKindExprConst}, caseClause{node: Nod(OXXX, nodlit(Val{&Mpint{Val: *big.NewInt('b'), Rune: true}}), nil), isconst: true},
-1, -1,
}, },
{ {
caseClause{node: Nod(OXXX, nodlit(Val{&Mpint{Val: *big.NewInt('b'), Rune: true}}), nil), typ: caseKindExprConst}, caseClause{node: Nod(OXXX, nodlit(Val{&Mpint{Val: *big.NewInt('b'), Rune: true}}), nil), isconst: true},
caseClause{node: Nod(OXXX, nodlit(Val{&Mpint{Val: *big.NewInt('b'), Rune: true}}), nil), typ: caseKindExprConst}, caseClause{node: Nod(OXXX, nodlit(Val{&Mpint{Val: *big.NewInt('b'), Rune: true}}), nil), isconst: true},
0, 0,
}, },
{ {
caseClause{node: Nod(OXXX, nodlit(Val{&Mpint{Val: *big.NewInt('b'), Rune: true}}), nil), typ: caseKindExprConst}, caseClause{node: Nod(OXXX, nodlit(Val{&Mpint{Val: *big.NewInt('b'), Rune: true}}), nil), isconst: true},
caseClause{node: Nod(OXXX, nodlit(Val{&Mpint{Val: *big.NewInt('a'), Rune: true}}), nil), typ: caseKindExprConst}, caseClause{node: Nod(OXXX, nodlit(Val{&Mpint{Val: *big.NewInt('a'), Rune: true}}), nil), isconst: true},
+1, +1,
}, },
// CTSTR // CTSTR
{ {
caseClause{node: Nod(OXXX, nodlit(Val{"ab"}), nil), typ: caseKindExprConst}, caseClause{node: Nod(OXXX, nodlit(Val{"ab"}), nil), isconst: true},
caseClause{node: Nod(OXXX, nodlit(Val{"abc"}), nil), typ: caseKindExprConst}, caseClause{node: Nod(OXXX, nodlit(Val{"abc"}), nil), isconst: true},
-1, -1,
}, },
{ {
caseClause{node: Nod(OXXX, nodlit(Val{"abc"}), nil), typ: caseKindExprConst}, caseClause{node: Nod(OXXX, nodlit(Val{"abc"}), nil), isconst: true},
caseClause{node: Nod(OXXX, nodlit(Val{"xyz"}), nil), typ: caseKindExprConst}, caseClause{node: Nod(OXXX, nodlit(Val{"xyz"}), nil), isconst: true},
-1, -1,
}, },
{ {
caseClause{node: Nod(OXXX, nodlit(Val{"abc"}), nil), typ: caseKindExprConst}, caseClause{node: Nod(OXXX, nodlit(Val{"abc"}), nil), isconst: true},
caseClause{node: Nod(OXXX, nodlit(Val{"abc"}), nil), typ: caseKindExprConst}, caseClause{node: Nod(OXXX, nodlit(Val{"abc"}), nil), isconst: true},
0, 0,
}, },
{ {
caseClause{node: Nod(OXXX, nodlit(Val{"abc"}), nil), typ: caseKindExprConst}, caseClause{node: Nod(OXXX, nodlit(Val{"abc"}), nil), isconst: true},
caseClause{node: Nod(OXXX, nodlit(Val{"ab"}), nil), typ: caseKindExprConst}, caseClause{node: Nod(OXXX, nodlit(Val{"ab"}), nil), isconst: true},
+1, +1,
}, },
{ {
caseClause{node: Nod(OXXX, nodlit(Val{"xyz"}), nil), typ: caseKindExprConst}, caseClause{node: Nod(OXXX, nodlit(Val{"xyz"}), nil), isconst: true},
caseClause{node: Nod(OXXX, nodlit(Val{"abc"}), nil), typ: caseKindExprConst}, caseClause{node: Nod(OXXX, nodlit(Val{"abc"}), nil), isconst: true},
+1, +1,
}, },
// Everything else should compare equal. // Everything else should compare equal.
{ {
caseClause{node: Nod(OXXX, nodnil(), nil), typ: caseKindExprConst}, caseClause{node: Nod(OXXX, nodnil(), nil), isconst: true},
caseClause{node: Nod(OXXX, nodnil(), nil), typ: caseKindExprConst}, caseClause{node: Nod(OXXX, nodnil(), nil), isconst: true},
0, 0,
}, },
} }
...@@ -137,8 +137,8 @@ func TestExprcmp(t *testing.T) { ...@@ -137,8 +137,8 @@ func TestExprcmp(t *testing.T) {
got := exprcmp(d.a, d.b) got := exprcmp(d.a, d.b)
if d.want != got { if d.want != got {
t.Errorf("%d: exprcmp(a, b) = %d; want %d", i, got, d.want) t.Errorf("%d: exprcmp(a, b) = %d; want %d", i, got, d.want)
t.Logf("\ta = caseClause{node: %#v, typ: %#v}", d.a.node, d.a.typ) t.Logf("\ta = caseClause{node: %#v, isconst: %v}", d.a.node, d.a.isconst)
t.Logf("\tb = caseClause{node: %#v, typ: %#v}", d.b.node, d.b.typ) t.Logf("\tb = caseClause{node: %#v, isconst: %v}", d.b.node, d.b.isconst)
} }
} }
} }
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