]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.ssa] cmd/compile: implement non-numeric comparisons
authorJosh Bleecher Snyder <josharian@gmail.com>
Mon, 27 Jul 2015 20:17:45 +0000 (13:17 -0700)
committerJosh Bleecher Snyder <josharian@gmail.com>
Tue, 28 Jul 2015 18:44:57 +0000 (18:44 +0000)
The only slice/interface comparisons that reach
the backend are comparisons to nil.

Funcs, maps, and channels are references types,
so pointer equality is enough.

Change-Id: I60a71da46a36202e9bd62ed370ab7d7f2e2800e7
Reviewed-on: https://go-review.googlesource.com/12715
Reviewed-by: Keith Randall <khr@golang.org>
src/cmd/compile/internal/gc/ssa.go
src/cmd/compile/internal/ssa/gen/AMD64.rules
src/cmd/compile/internal/ssa/gen/generic.rules
src/cmd/compile/internal/ssa/gen/genericOps.go
src/cmd/compile/internal/ssa/opGen.go
src/cmd/compile/internal/ssa/rewriteAMD64.go
src/cmd/compile/internal/ssa/rewritegeneric.go

index 970799cf56cbf34471e314dff58645ceacb6d46a..0a45be0078b76493da4f5c6d52ca5fdc2f986414 100644 (file)
@@ -726,25 +726,39 @@ var opToSSA = map[opAndType]ssa.Op{
        opAndType{ORSH, TINT64}:  ssa.OpRsh64,
        opAndType{ORSH, TUINT64}: ssa.OpRsh64U,
 
-       opAndType{OEQ, TINT8}:   ssa.OpEq8,
-       opAndType{OEQ, TUINT8}:  ssa.OpEq8,
-       opAndType{OEQ, TINT16}:  ssa.OpEq16,
-       opAndType{OEQ, TUINT16}: ssa.OpEq16,
-       opAndType{OEQ, TINT32}:  ssa.OpEq32,
-       opAndType{OEQ, TUINT32}: ssa.OpEq32,
-       opAndType{OEQ, TINT64}:  ssa.OpEq64,
-       opAndType{OEQ, TUINT64}: ssa.OpEq64,
-       opAndType{OEQ, TPTR64}:  ssa.OpEq64,
-
-       opAndType{ONE, TINT8}:   ssa.OpNeq8,
-       opAndType{ONE, TUINT8}:  ssa.OpNeq8,
-       opAndType{ONE, TINT16}:  ssa.OpNeq16,
-       opAndType{ONE, TUINT16}: ssa.OpNeq16,
-       opAndType{ONE, TINT32}:  ssa.OpNeq32,
-       opAndType{ONE, TUINT32}: ssa.OpNeq32,
-       opAndType{ONE, TINT64}:  ssa.OpNeq64,
-       opAndType{ONE, TUINT64}: ssa.OpNeq64,
-       opAndType{ONE, TPTR64}:  ssa.OpNeq64,
+       opAndType{OEQ, TBOOL}:    ssa.OpEq8,
+       opAndType{OEQ, TINT8}:    ssa.OpEq8,
+       opAndType{OEQ, TUINT8}:   ssa.OpEq8,
+       opAndType{OEQ, TINT16}:   ssa.OpEq16,
+       opAndType{OEQ, TUINT16}:  ssa.OpEq16,
+       opAndType{OEQ, TINT32}:   ssa.OpEq32,
+       opAndType{OEQ, TUINT32}:  ssa.OpEq32,
+       opAndType{OEQ, TINT64}:   ssa.OpEq64,
+       opAndType{OEQ, TUINT64}:  ssa.OpEq64,
+       opAndType{OEQ, TPTR64}:   ssa.OpEq64,
+       opAndType{OEQ, TINTER}:   ssa.OpEqFat, // e == nil only
+       opAndType{OEQ, TARRAY}:   ssa.OpEqFat, // slice only; a == nil only
+       opAndType{OEQ, TFUNC}:    ssa.OpEqPtr,
+       opAndType{OEQ, TMAP}:     ssa.OpEqPtr,
+       opAndType{OEQ, TCHAN}:    ssa.OpEqPtr,
+       opAndType{OEQ, TUINTPTR}: ssa.OpEqPtr,
+
+       opAndType{ONE, TBOOL}:    ssa.OpNeq8,
+       opAndType{ONE, TINT8}:    ssa.OpNeq8,
+       opAndType{ONE, TUINT8}:   ssa.OpNeq8,
+       opAndType{ONE, TINT16}:   ssa.OpNeq16,
+       opAndType{ONE, TUINT16}:  ssa.OpNeq16,
+       opAndType{ONE, TINT32}:   ssa.OpNeq32,
+       opAndType{ONE, TUINT32}:  ssa.OpNeq32,
+       opAndType{ONE, TINT64}:   ssa.OpNeq64,
+       opAndType{ONE, TUINT64}:  ssa.OpNeq64,
+       opAndType{ONE, TPTR64}:   ssa.OpNeq64,
+       opAndType{ONE, TINTER}:   ssa.OpNeqFat, // e != nil only
+       opAndType{ONE, TARRAY}:   ssa.OpNeqFat, // slice only; a != nil only
+       opAndType{ONE, TFUNC}:    ssa.OpNeqPtr,
+       opAndType{ONE, TMAP}:     ssa.OpNeqPtr,
+       opAndType{ONE, TCHAN}:    ssa.OpNeqPtr,
+       opAndType{ONE, TUINTPTR}: ssa.OpNeqPtr,
 
        opAndType{OLT, TINT8}:   ssa.OpLess8,
        opAndType{OLT, TUINT8}:  ssa.OpLess8U,
index 5f4a5b5a693d845fb598a1226877ff0dc0d39cff..ea3974935f16ecd61b30e8cf6ede6b6f13c107d1 100644 (file)
 (Eq32 x y) -> (SETEQ (CMPL <TypeFlags> x y))
 (Eq16 x y) -> (SETEQ (CMPW <TypeFlags> x y))
 (Eq8 x y) -> (SETEQ (CMPB <TypeFlags> x y))
+(EqPtr x y) -> (SETEQ (CMPQ <TypeFlags> x y))
 
 (Neq64 x y) -> (SETNE (CMPQ <TypeFlags> x y))
 (Neq32 x y) -> (SETNE (CMPL <TypeFlags> x y))
 (Neq16 x y) -> (SETNE (CMPW <TypeFlags> x y))
 (Neq8 x y) -> (SETNE (CMPB <TypeFlags> x y))
+(NeqPtr x y) -> (SETNE (CMPQ <TypeFlags> x y))
 
 (Load <t> ptr mem) && (is64BitInt(t) || isPtr(t)) -> (MOVQload ptr mem)
 (Load <t> ptr mem) && is32BitInt(t) -> (MOVLload ptr mem)
index fc5ffb96100b4cbacaf98016e6060766576c562f..dd48706e63faeba660b12a5970a0ec9d201822e8 100644 (file)
 (SliceLen (Load ptr mem)) -> (Load (AddPtr <ptr.Type> ptr (Const <config.Uintptr> [config.PtrSize])) mem)
 (SliceCap (Load ptr mem)) -> (Load (AddPtr <ptr.Type> ptr (Const <config.Uintptr> [config.PtrSize*2])) mem)
 
+// slice and interface comparisons
+// the frontend ensures that we can only compare against nil
+// start by putting nil on the right to simplify the other rules
+(EqFat x y) && x.Op == OpConst && y.Op != OpConst -> (EqFat y x)
+(NeqFat x y) && x.Op == OpConst && y.Op != OpConst -> (NeqFat y x)
+// it suffices to check the first word (backing array for slices, dynamic type for interfaces)
+(EqFat (Load ptr mem) y) && y.Op == OpConst -> (EqPtr (Load <config.Uintptr> ptr mem) (Const <config.Uintptr> [0]))
+(NeqFat (Load ptr mem) y) && y.Op == OpConst -> (NeqPtr (Load <config.Uintptr> ptr mem) (Const <config.Uintptr> [0]))
+
 // indexing operations
 // Note: bounds check has already been done
 (ArrayIndex (Load ptr mem) idx) -> (Load (PtrIndex <v.Type.PtrTo()> ptr idx) mem)
index 0dc3ac42baf918649258251a316fca873e00e647..c67643d94e31a2727dfb4dfb101658f7d00cea42 100644 (file)
@@ -67,11 +67,15 @@ var genericOps = []opData{
        {name: "Eq16"},
        {name: "Eq32"},
        {name: "Eq64"},
+       {name: "EqPtr"},
+       {name: "EqFat"}, // slice/interface; arg0 or arg1 is nil; other cases handled by frontend
 
        {name: "Neq8"}, // arg0 != arg1
        {name: "Neq16"},
        {name: "Neq32"},
        {name: "Neq64"},
+       {name: "NeqPtr"},
+       {name: "NeqFat"}, // slice/interface; arg0 or arg1 is nil; other cases handled by frontend
 
        {name: "Less8"}, // arg0 < arg1
        {name: "Less8U"},
index d916ad0da2acabaa61ca7a2a3e5ac4f70ae1268e..d83f87305dab7670c62060973e619e9d887b742f 100644 (file)
@@ -183,10 +183,14 @@ const (
        OpEq16
        OpEq32
        OpEq64
+       OpEqPtr
+       OpEqFat
        OpNeq8
        OpNeq16
        OpNeq32
        OpNeq64
+       OpNeqPtr
+       OpNeqFat
        OpLess8
        OpLess8U
        OpLess16
@@ -1417,6 +1421,14 @@ var opcodeTable = [...]opInfo{
                name:    "Eq64",
                generic: true,
        },
+       {
+               name:    "EqPtr",
+               generic: true,
+       },
+       {
+               name:    "EqFat",
+               generic: true,
+       },
        {
                name:    "Neq8",
                generic: true,
@@ -1433,6 +1445,14 @@ var opcodeTable = [...]opInfo{
                name:    "Neq64",
                generic: true,
        },
+       {
+               name:    "NeqPtr",
+               generic: true,
+       },
+       {
+               name:    "NeqFat",
+               generic: true,
+       },
        {
                name:    "Less8",
                generic: true,
index 1c1638bf187da0d346ca78fdf8f84e7c34f1daf8..41bb6213f16124d657ecaf5933f953d16949f5e1 100644 (file)
@@ -852,6 +852,27 @@ func rewriteValueAMD64(v *Value, config *Config) bool {
                goto end84a692e769900e3adbfe00718d2169e0
        end84a692e769900e3adbfe00718d2169e0:
                ;
+       case OpEqPtr:
+               // match: (EqPtr x y)
+               // cond:
+               // result: (SETEQ (CMPQ <TypeFlags> x y))
+               {
+                       x := v.Args[0]
+                       y := v.Args[1]
+                       v.Op = OpAMD64SETEQ
+                       v.AuxInt = 0
+                       v.Aux = nil
+                       v.resetArgs()
+                       v0 := v.Block.NewValue0(v.Line, OpAMD64CMPQ, TypeInvalid)
+                       v0.Type = TypeFlags
+                       v0.AddArg(x)
+                       v0.AddArg(y)
+                       v.AddArg(v0)
+                       return true
+               }
+               goto end6de1d39c9d151e5e503d643bd835356e
+       end6de1d39c9d151e5e503d643bd835356e:
+               ;
        case OpGeq64:
                // match: (Geq64 x y)
                // cond:
@@ -2041,6 +2062,27 @@ func rewriteValueAMD64(v *Value, config *Config) bool {
                goto end4aaff28af59a65b3684f4f1897299932
        end4aaff28af59a65b3684f4f1897299932:
                ;
+       case OpNeqPtr:
+               // match: (NeqPtr x y)
+               // cond:
+               // result: (SETNE (CMPQ <TypeFlags> x y))
+               {
+                       x := v.Args[0]
+                       y := v.Args[1]
+                       v.Op = OpAMD64SETNE
+                       v.AuxInt = 0
+                       v.Aux = nil
+                       v.resetArgs()
+                       v0 := v.Block.NewValue0(v.Line, OpAMD64CMPQ, TypeInvalid)
+                       v0.Type = TypeFlags
+                       v0.AddArg(x)
+                       v0.AddArg(y)
+                       v.AddArg(v0)
+                       return true
+               }
+               goto end6e180ffd9583cd55361ed3e465158a4c
+       end6e180ffd9583cd55361ed3e465158a4c:
+               ;
        case OpNot:
                // match: (Not x)
                // cond:
index 54358129e0c173b7f75dc9f8de208fbe8ea0cb7b..976fbc94a0f96d453781e1ad0451a88457ec69b2 100644 (file)
@@ -129,6 +129,58 @@ func rewriteValuegeneric(v *Value, config *Config) bool {
                goto enda6f250a3c775ae5a239ece8074b46cea
        enda6f250a3c775ae5a239ece8074b46cea:
                ;
+       case OpEqFat:
+               // match: (EqFat x y)
+               // cond: x.Op == OpConst && y.Op != OpConst
+               // result: (EqFat y x)
+               {
+                       x := v.Args[0]
+                       y := v.Args[1]
+                       if !(x.Op == OpConst && y.Op != OpConst) {
+                               goto end4540bddcf0fc8e4b71fac6e9edbb8eec
+                       }
+                       v.Op = OpEqFat
+                       v.AuxInt = 0
+                       v.Aux = nil
+                       v.resetArgs()
+                       v.AddArg(y)
+                       v.AddArg(x)
+                       return true
+               }
+               goto end4540bddcf0fc8e4b71fac6e9edbb8eec
+       end4540bddcf0fc8e4b71fac6e9edbb8eec:
+               ;
+               // match: (EqFat (Load ptr mem) y)
+               // cond: y.Op == OpConst
+               // result: (EqPtr (Load <config.Uintptr> ptr mem) (Const <config.Uintptr> [0]))
+               {
+                       if v.Args[0].Op != OpLoad {
+                               goto end779b0e24e33d8eff668c368b90387caa
+                       }
+                       ptr := v.Args[0].Args[0]
+                       mem := v.Args[0].Args[1]
+                       y := v.Args[1]
+                       if !(y.Op == OpConst) {
+                               goto end779b0e24e33d8eff668c368b90387caa
+                       }
+                       v.Op = OpEqPtr
+                       v.AuxInt = 0
+                       v.Aux = nil
+                       v.resetArgs()
+                       v0 := v.Block.NewValue0(v.Line, OpLoad, TypeInvalid)
+                       v0.Type = config.Uintptr
+                       v0.AddArg(ptr)
+                       v0.AddArg(mem)
+                       v.AddArg(v0)
+                       v1 := v.Block.NewValue0(v.Line, OpConst, TypeInvalid)
+                       v1.Type = config.Uintptr
+                       v1.AuxInt = 0
+                       v.AddArg(v1)
+                       return true
+               }
+               goto end779b0e24e33d8eff668c368b90387caa
+       end779b0e24e33d8eff668c368b90387caa:
+               ;
        case OpIsInBounds:
                // match: (IsInBounds (Const [c]) (Const [d]))
                // cond:
@@ -255,6 +307,58 @@ func rewriteValuegeneric(v *Value, config *Config) bool {
                goto end10541de7ea2bce703c1e372ac9a271e7
        end10541de7ea2bce703c1e372ac9a271e7:
                ;
+       case OpNeqFat:
+               // match: (NeqFat x y)
+               // cond: x.Op == OpConst && y.Op != OpConst
+               // result: (NeqFat y x)
+               {
+                       x := v.Args[0]
+                       y := v.Args[1]
+                       if !(x.Op == OpConst && y.Op != OpConst) {
+                               goto end5d2a9d3aa52fb6866825f35ac65c7cfd
+                       }
+                       v.Op = OpNeqFat
+                       v.AuxInt = 0
+                       v.Aux = nil
+                       v.resetArgs()
+                       v.AddArg(y)
+                       v.AddArg(x)
+                       return true
+               }
+               goto end5d2a9d3aa52fb6866825f35ac65c7cfd
+       end5d2a9d3aa52fb6866825f35ac65c7cfd:
+               ;
+               // match: (NeqFat (Load ptr mem) y)
+               // cond: y.Op == OpConst
+               // result: (NeqPtr (Load <config.Uintptr> ptr mem) (Const <config.Uintptr> [0]))
+               {
+                       if v.Args[0].Op != OpLoad {
+                               goto endf2f18052c2d999a7ac883c441c3b7ade
+                       }
+                       ptr := v.Args[0].Args[0]
+                       mem := v.Args[0].Args[1]
+                       y := v.Args[1]
+                       if !(y.Op == OpConst) {
+                               goto endf2f18052c2d999a7ac883c441c3b7ade
+                       }
+                       v.Op = OpNeqPtr
+                       v.AuxInt = 0
+                       v.Aux = nil
+                       v.resetArgs()
+                       v0 := v.Block.NewValue0(v.Line, OpLoad, TypeInvalid)
+                       v0.Type = config.Uintptr
+                       v0.AddArg(ptr)
+                       v0.AddArg(mem)
+                       v.AddArg(v0)
+                       v1 := v.Block.NewValue0(v.Line, OpConst, TypeInvalid)
+                       v1.Type = config.Uintptr
+                       v1.AuxInt = 0
+                       v.AddArg(v1)
+                       return true
+               }
+               goto endf2f18052c2d999a7ac883c441c3b7ade
+       endf2f18052c2d999a7ac883c441c3b7ade:
+               ;
        case OpPtrIndex:
                // match: (PtrIndex <t> ptr idx)
                // cond: