import (
"cmd/compile/internal/ssa"
+ "fmt"
)
func (t *Type) Size() int64 {
return Eqtype(t, x)
}
+// Compare compares types for purposes of the SSA back
+// end, returning an ssa.Cmp (one of CMPlt, CMPeq, CMPgt).
+// The answers are correct for an optimizer
+// or code generator, but not for Go source.
+// For example, "type gcDrainFlags int" results in
+// two Go-different types that Compare equal.
+// The order chosen is also arbitrary, only division into
+// equivalence classes (Types that compare CMPeq) matters.
+func (t *Type) Compare(u ssa.Type) ssa.Cmp {
+ x, ok := u.(*Type)
+ // ssa.CompilerType is smaller than gc.Type
+ // bare pointer equality is easy.
+ if !ok {
+ return ssa.CMPgt
+ }
+ if x == t {
+ return ssa.CMPeq
+ }
+ return t.cmp(x)
+}
+
+func cmpForNe(x bool) ssa.Cmp {
+ if x {
+ return ssa.CMPlt
+ }
+ return ssa.CMPgt
+}
+
+func (r *Sym) cmpsym(s *Sym) ssa.Cmp {
+ if r == s {
+ return ssa.CMPeq
+ }
+ if r == nil {
+ return ssa.CMPlt
+ }
+ if s == nil {
+ return ssa.CMPgt
+ }
+ // Fast sort, not pretty sort
+ if len(r.Name) != len(s.Name) {
+ return cmpForNe(len(r.Name) < len(s.Name))
+ }
+ if r.Pkg != s.Pkg {
+ if len(r.Pkg.Prefix) != len(s.Pkg.Prefix) {
+ return cmpForNe(len(r.Pkg.Prefix) < len(s.Pkg.Prefix))
+ }
+ if r.Pkg.Prefix != s.Pkg.Prefix {
+ return cmpForNe(r.Pkg.Prefix < s.Pkg.Prefix)
+ }
+ }
+ if r.Name != s.Name {
+ return cmpForNe(r.Name < s.Name)
+ }
+ return ssa.CMPeq
+}
+
+// cmp compares two *Types t and x, returning ssa.CMPlt,
+// ssa.CMPeq, ssa.CMPgt as t<x, t==x, t>x, for an arbitrary
+// and optimizer-centric notion of comparison.
+func (t *Type) cmp(x *Type) ssa.Cmp {
+ // This follows the structure of Eqtype in subr.go
+ // with two exceptions.
+ // 1. Symbols are compared more carefully because a <,=,> result is desired.
+ // 2. Maps are treated specially to avoid endless recursion -- maps
+ // contain an internal data type not expressible in Go source code.
+ if t == x {
+ return ssa.CMPeq
+ }
+ if t == nil {
+ return ssa.CMPlt
+ }
+ if x == nil {
+ return ssa.CMPgt
+ }
+
+ if t.Etype != x.Etype {
+ return cmpForNe(t.Etype < x.Etype)
+ }
+
+ if t.Sym != nil || x.Sym != nil {
+ // Special case: we keep byte and uint8 separate
+ // for error messages. Treat them as equal.
+ switch t.Etype {
+ case TUINT8:
+ if (t == Types[TUINT8] || t == bytetype) && (x == Types[TUINT8] || x == bytetype) {
+ return ssa.CMPeq
+ }
+
+ case TINT32:
+ if (t == Types[runetype.Etype] || t == runetype) && (x == Types[runetype.Etype] || x == runetype) {
+ return ssa.CMPeq
+ }
+ }
+ }
+
+ csym := t.Sym.cmpsym(x.Sym)
+ if csym != ssa.CMPeq {
+ return csym
+ }
+
+ if x.Sym != nil {
+ // Syms non-nil, if vargens match then equal.
+ if t.Vargen == x.Vargen {
+ return ssa.CMPeq
+ }
+ if t.Vargen < x.Vargen {
+ return ssa.CMPlt
+ }
+ return ssa.CMPgt
+ }
+ // both syms nil, look at structure below.
+
+ switch t.Etype {
+ case TBOOL, TFLOAT32, TFLOAT64, TCOMPLEX64, TCOMPLEX128, TUNSAFEPTR, TUINTPTR,
+ TINT8, TINT16, TINT32, TINT64, TINT, TUINT8, TUINT16, TUINT32, TUINT64, TUINT:
+ return ssa.CMPeq
+ }
+
+ switch t.Etype {
+ case TMAP, TFIELD:
+ // No special cases for these two, they are handled
+ // by the general code after the switch.
+
+ case TPTR32, TPTR64:
+ return t.Type.cmp(x.Type)
+
+ case TSTRUCT:
+ if t.Map == nil {
+ if x.Map != nil {
+ return ssa.CMPlt // nil < non-nil
+ }
+ // to the fallthrough
+ } else if x.Map == nil {
+ return ssa.CMPgt // nil > non-nil
+ } else if t.Map.Bucket == t {
+ // Both have non-nil Map
+ // Special case for Maps which include a recursive type where the recursion is not broken with a named type
+ if x.Map.Bucket != x {
+ return ssa.CMPlt // bucket maps are least
+ }
+ return t.Map.cmp(x.Map)
+ } // If t != t.Map.Bucket, fall through to general case
+
+ fallthrough
+ case TINTER:
+ t1 := t.Type
+ x1 := x.Type
+ for ; t1 != nil && x1 != nil; t1, x1 = t1.Down, x1.Down {
+ if t1.Embedded != x1.Embedded {
+ if t1.Embedded < x1.Embedded {
+ return ssa.CMPlt
+ }
+ return ssa.CMPgt
+ }
+ if t1.Note != x1.Note {
+ if t1.Note == nil {
+ return ssa.CMPlt
+ }
+ if x1.Note == nil {
+ return ssa.CMPgt
+ }
+ if *t1.Note != *x1.Note {
+ if *t1.Note < *x1.Note {
+ return ssa.CMPlt
+ }
+ return ssa.CMPgt
+ }
+ }
+ c := t1.Sym.cmpsym(x1.Sym)
+ if c != ssa.CMPeq {
+ return c
+ }
+ c = t1.Type.cmp(x1.Type)
+ if c != ssa.CMPeq {
+ return c
+ }
+ }
+ if t1 == x1 {
+ return ssa.CMPeq
+ }
+ if t1 == nil {
+ return ssa.CMPlt
+ }
+ return ssa.CMPgt
+
+ case TFUNC:
+ t1 := t.Type
+ t2 := x.Type
+ for ; t1 != nil && t2 != nil; t1, t2 = t1.Down, t2.Down {
+ // Loop over fields in structs, ignoring argument names.
+ ta := t1.Type
+ tb := t2.Type
+ for ; ta != nil && tb != nil; ta, tb = ta.Down, tb.Down {
+ if ta.Isddd != tb.Isddd {
+ if ta.Isddd {
+ return ssa.CMPgt
+ }
+ return ssa.CMPlt
+ }
+ c := ta.Type.cmp(tb.Type)
+ if c != ssa.CMPeq {
+ return c
+ }
+ }
+
+ if ta != tb {
+ if t1 == nil {
+ return ssa.CMPlt
+ }
+ return ssa.CMPgt
+ }
+ }
+ if t1 != t2 {
+ if t1 == nil {
+ return ssa.CMPlt
+ }
+ return ssa.CMPgt
+ }
+ return ssa.CMPeq
+
+ case TARRAY:
+ if t.Bound != x.Bound {
+ return cmpForNe(t.Bound < x.Bound)
+ }
+
+ case TCHAN:
+ if t.Chan != x.Chan {
+ return cmpForNe(t.Chan < x.Chan)
+ }
+
+ default:
+ e := fmt.Sprintf("Do not know how to compare %s with %s", t, x)
+ panic(e)
+ }
+
+ c := t.Down.cmp(x.Down)
+ if c != ssa.CMPeq {
+ return c
+ }
+ return t.Type.cmp(x.Type)
+}
+
func (t *Type) IsBoolean() bool {
return t.Etype == TBOOL
}
}
}
+ rewrites := 0
+
// Apply substitutions
for _, b := range f.Blocks {
for _, v := range b.Values {
for i, w := range v.Args {
if x := rewrite[w.ID]; x != nil {
v.SetArg(i, x)
+ rewrites++
}
}
}
}
}
}
+ if Debug > 0 && rewrites > 0 {
+ fmt.Printf("CSE: %d rewrites\n", rewrites)
+ }
}
// An eqclass approximates an equivalence class. During the
// backed by the same storage as the input slice.
// Equivalence classes of size 1 are ignored.
func partitionValues(a []*Value) []eqclass {
- typNames := map[Type]string{}
auxIDs := map[interface{}]int32{}
- sort.Sort(sortvalues{a, typNames, auxIDs})
+ sort.Sort(sortvalues{a, auxIDs})
var partition []eqclass
for len(a) > 0 {
v.Args[0].AuxInt != w.Args[0].AuxInt) ||
len(v.Args) >= 2 && (v.Args[1].Op != w.Args[1].Op ||
v.Args[1].AuxInt != w.Args[1].AuxInt) ||
- typNames[v.Type] != typNames[w.Type] {
+ v.Type.Compare(w.Type) != CMPeq {
if Debug > 3 {
- fmt.Printf("CSE.partitionValues separates %s from %s, AuxInt=%v, Aux=%v, typNames=%v",
- v.LongString(), w.LongString(), v.AuxInt != w.AuxInt, v.Aux != w.Aux, typNames[v.Type] != typNames[w.Type])
+ fmt.Printf("CSE.partitionValues separates %s from %s, AuxInt=%v, Aux=%v, Type.compare=%v",
+ v.LongString(), w.LongString(), v.AuxInt != w.AuxInt, v.Aux != w.Aux, v.Type.Compare(w.Type))
if !rootsDiffer {
if len(v.Args) >= 1 {
fmt.Printf(", a0Op=%v, a0AuxInt=%v", v.Args[0].Op != w.Args[0].Op, v.Args[0].AuxInt != w.Args[0].AuxInt)
// Sort values to make the initial partition.
type sortvalues struct {
- a []*Value // array of values
- typNames map[Type]string // type -> type ID map
- auxIDs map[interface{}]int32 // aux -> aux ID map
+ a []*Value // array of values
+ auxIDs map[interface{}]int32 // aux -> aux ID map
}
func (sv sortvalues) Len() int { return len(sv.a) }
}
}
- // Sort by type. Types are just interfaces, so we can't compare
- // them with < directly. Instead, map types to their names and
- // sort on that.
+ // Sort by type, using the ssa.Type Compare method
if v.Type != w.Type {
- x := sv.typNames[v.Type]
- if x == "" {
- x = v.Type.String()
- sv.typNames[v.Type] = x
- }
- y := sv.typNames[w.Type]
- if y == "" {
- y = w.Type.String()
- sv.typNames[w.Type] = y
- }
- if x != y {
- return x < y
+ c := v.Type.Compare(w.Type)
+ if c != CMPeq {
+ return c == CMPlt
}
}
- // Same deal for aux fields.
+ // Aux fields are interfaces with no comparison
+ // method. Use a map to number distinct ones,
+ // and use those numbers for comparison.
if v.Aux != w.Aux {
x := sv.auxIDs[v.Aux]
if x == 0 {