Commit 1e4ebfdd authored by Keith Randall's avatar Keith Randall

[dev.ssa] cmd/compile/internal/ssa: fix iface and slice comparisons

A simpler way to do iface/slice comparisons.  Fixes some
cases of failed lowerings.

Change-Id: Ia252bc8648293a2d460f63c41f1591785543a1e9
Reviewed-on: https://go-review.googlesource.com/14493Reviewed-by: default avatarJosh Bleecher Snyder <josharian@gmail.com>
parent 9d22c101
...@@ -950,8 +950,8 @@ var opToSSA = map[opAndType]ssa.Op{ ...@@ -950,8 +950,8 @@ var opToSSA = map[opAndType]ssa.Op{
opAndType{OEQ, TUINT32}: ssa.OpEq32, opAndType{OEQ, TUINT32}: ssa.OpEq32,
opAndType{OEQ, TINT64}: ssa.OpEq64, opAndType{OEQ, TINT64}: ssa.OpEq64,
opAndType{OEQ, TUINT64}: ssa.OpEq64, opAndType{OEQ, TUINT64}: ssa.OpEq64,
opAndType{OEQ, TINTER}: ssa.OpEqFat, // e == nil only opAndType{OEQ, TINTER}: ssa.OpEqInter,
opAndType{OEQ, TARRAY}: ssa.OpEqFat, // slice only; a == nil only opAndType{OEQ, TARRAY}: ssa.OpEqSlice,
opAndType{OEQ, TFUNC}: ssa.OpEqPtr, opAndType{OEQ, TFUNC}: ssa.OpEqPtr,
opAndType{OEQ, TMAP}: ssa.OpEqPtr, opAndType{OEQ, TMAP}: ssa.OpEqPtr,
opAndType{OEQ, TCHAN}: ssa.OpEqPtr, opAndType{OEQ, TCHAN}: ssa.OpEqPtr,
...@@ -970,8 +970,8 @@ var opToSSA = map[opAndType]ssa.Op{ ...@@ -970,8 +970,8 @@ var opToSSA = map[opAndType]ssa.Op{
opAndType{ONE, TUINT32}: ssa.OpNeq32, opAndType{ONE, TUINT32}: ssa.OpNeq32,
opAndType{ONE, TINT64}: ssa.OpNeq64, opAndType{ONE, TINT64}: ssa.OpNeq64,
opAndType{ONE, TUINT64}: ssa.OpNeq64, opAndType{ONE, TUINT64}: ssa.OpNeq64,
opAndType{ONE, TINTER}: ssa.OpNeqFat, // e != nil only opAndType{ONE, TINTER}: ssa.OpNeqInter,
opAndType{ONE, TARRAY}: ssa.OpNeqFat, // slice only; a != nil only opAndType{ONE, TARRAY}: ssa.OpNeqSlice,
opAndType{ONE, TFUNC}: ssa.OpNeqPtr, opAndType{ONE, TFUNC}: ssa.OpNeqPtr,
opAndType{ONE, TMAP}: ssa.OpNeqPtr, opAndType{ONE, TMAP}: ssa.OpNeqPtr,
opAndType{ONE, TCHAN}: ssa.OpNeqPtr, opAndType{ONE, TCHAN}: ssa.OpNeqPtr,
...@@ -1522,7 +1522,6 @@ func (s *state) expr(n *Node) *ssa.Value { ...@@ -1522,7 +1522,6 @@ func (s *state) expr(n *Node) *ssa.Value {
default: default:
s.Fatalf("ordered complex compare %s", opnames[n.Op]) s.Fatalf("ordered complex compare %s", opnames[n.Op])
} }
} }
return s.newValue2(s.ssaOp(n.Op, n.Left.Type), Types[TBOOL], a, b) return s.newValue2(s.ssaOp(n.Op, n.Left.Type), Types[TBOOL], a, b)
case OMUL: case OMUL:
......
...@@ -66,13 +66,12 @@ ...@@ -66,13 +66,12 @@
(EqPtr (ConstNil) p) -> (Not (IsNonNil p)) (EqPtr (ConstNil) p) -> (Not (IsNonNil p))
// slice and interface comparisons // slice and interface comparisons
// the frontend ensures that we can only compare against nil // The frontend ensures that we can only compare against nil,
// start by putting nil on the right to simplify the other rules // so we need only compare the first word (interface type or slice ptr).
(EqFat x y) && x.Op == OpConstNil && y.Op != OpConstNil -> (EqFat y x) (EqInter x y) -> (EqPtr (ITab x) (ITab y))
(NeqFat x y) && x.Op == OpConstNil && y.Op != OpConstNil -> (NeqFat y x) (NeqInter x y) -> (NeqPtr (ITab x) (ITab y))
// it suffices to check the first word (backing array for slices, dynamic type for interfaces) (EqSlice x y) -> (EqPtr (SlicePtr x) (SlicePtr y))
(EqFat (Load ptr mem) (ConstNil)) -> (EqPtr (Load <config.fe.TypeUintptr()> ptr mem) (ConstPtr [0])) (NeqSlice x y) -> (NeqPtr (SlicePtr x) (SlicePtr y))
(NeqFat (Load ptr mem) (ConstNil)) -> (NeqPtr (Load <config.fe.TypeUintptr()> ptr mem) (ConstPtr [0]))
// indexing operations // indexing operations
// Note: bounds check has already been done // Note: bounds check has already been done
......
...@@ -160,7 +160,8 @@ var genericOps = []opData{ ...@@ -160,7 +160,8 @@ var genericOps = []opData{
{name: "Eq32"}, {name: "Eq32"},
{name: "Eq64"}, {name: "Eq64"},
{name: "EqPtr"}, {name: "EqPtr"},
{name: "EqFat"}, // slice/interface; arg0 or arg1 is nil; other cases handled by frontend {name: "EqInter"}, // arg0 or arg1 is nil; other cases handled by frontend
{name: "EqSlice"}, // arg0 or arg1 is nil; other cases handled by frontend
{name: "Eq32F"}, {name: "Eq32F"},
{name: "Eq64F"}, {name: "Eq64F"},
...@@ -169,7 +170,8 @@ var genericOps = []opData{ ...@@ -169,7 +170,8 @@ var genericOps = []opData{
{name: "Neq32"}, {name: "Neq32"},
{name: "Neq64"}, {name: "Neq64"},
{name: "NeqPtr"}, {name: "NeqPtr"},
{name: "NeqFat"}, // slice/interface; arg0 or arg1 is nil; other cases handled by frontend {name: "NeqInter"}, // arg0 or arg1 is nil; other cases handled by frontend
{name: "NeqSlice"}, // arg0 or arg1 is nil; other cases handled by frontend
{name: "Neq32F"}, {name: "Neq32F"},
{name: "Neq64F"}, {name: "Neq64F"},
...@@ -334,10 +336,10 @@ var genericOps = []opData{ ...@@ -334,10 +336,10 @@ var genericOps = []opData{
{name: "StructSelect"}, // arg0=struct, auxint=field offset. Returns field at that offset (size=size of result type) {name: "StructSelect"}, // arg0=struct, auxint=field offset. Returns field at that offset (size=size of result type)
// Slices // Slices
{name: "SliceMake"}, // arg0=ptr, arg1=len, arg2=cap {name: "SliceMake"}, // arg0=ptr, arg1=len, arg2=cap
{name: "SlicePtr"}, // ptr(arg0) {name: "SlicePtr", typ: "Uintptr"}, // ptr(arg0)
{name: "SliceLen"}, // len(arg0) {name: "SliceLen"}, // len(arg0)
{name: "SliceCap"}, // cap(arg0) {name: "SliceCap"}, // cap(arg0)
// Complex (part/whole) // Complex (part/whole)
{name: "ComplexMake"}, // arg0=real, arg1=imag {name: "ComplexMake"}, // arg0=real, arg1=imag
...@@ -350,9 +352,9 @@ var genericOps = []opData{ ...@@ -350,9 +352,9 @@ var genericOps = []opData{
{name: "StringLen"}, // len(arg0) {name: "StringLen"}, // len(arg0)
// Interfaces // Interfaces
{name: "IMake"}, // arg0=itab, arg1=data {name: "IMake"}, // arg0=itab, arg1=data
{name: "ITab"}, // arg0=interface, returns itable field {name: "ITab", typ: "Uintptr"}, // arg0=interface, returns itable field
{name: "IData"}, // arg0=interface, returns data field {name: "IData"}, // arg0=interface, returns data field
// Spill&restore ops for the register allocator. These are // Spill&restore ops for the register allocator. These are
// semantically identical to OpCopy; they do not take/return // semantically identical to OpCopy; they do not take/return
......
...@@ -387,7 +387,8 @@ const ( ...@@ -387,7 +387,8 @@ const (
OpEq32 OpEq32
OpEq64 OpEq64
OpEqPtr OpEqPtr
OpEqFat OpEqInter
OpEqSlice
OpEq32F OpEq32F
OpEq64F OpEq64F
OpNeq8 OpNeq8
...@@ -395,7 +396,8 @@ const ( ...@@ -395,7 +396,8 @@ const (
OpNeq32 OpNeq32
OpNeq64 OpNeq64
OpNeqPtr OpNeqPtr
OpNeqFat OpNeqInter
OpNeqSlice
OpNeq32F OpNeq32F
OpNeq64F OpNeq64F
OpLess8 OpLess8
...@@ -3576,7 +3578,11 @@ var opcodeTable = [...]opInfo{ ...@@ -3576,7 +3578,11 @@ var opcodeTable = [...]opInfo{
generic: true, generic: true,
}, },
{ {
name: "EqFat", name: "EqInter",
generic: true,
},
{
name: "EqSlice",
generic: true, generic: true,
}, },
{ {
...@@ -3608,7 +3614,11 @@ var opcodeTable = [...]opInfo{ ...@@ -3608,7 +3614,11 @@ var opcodeTable = [...]opInfo{
generic: true, generic: true,
}, },
{ {
name: "NeqFat", name: "NeqInter",
generic: true,
},
{
name: "NeqSlice",
generic: true, generic: true,
}, },
{ {
......
...@@ -427,56 +427,29 @@ func rewriteValuegeneric(v *Value, config *Config) bool { ...@@ -427,56 +427,29 @@ func rewriteValuegeneric(v *Value, config *Config) bool {
goto enda66da0d3e7e51624ee46527727c48a9a goto enda66da0d3e7e51624ee46527727c48a9a
enda66da0d3e7e51624ee46527727c48a9a: enda66da0d3e7e51624ee46527727c48a9a:
; ;
case OpEqFat: case OpEqInter:
// match: (EqFat x y) // match: (EqInter x y)
// cond: x.Op == OpConstNil && y.Op != OpConstNil // cond:
// result: (EqFat y x) // result: (EqPtr (ITab x) (ITab y))
{ {
x := v.Args[0] x := v.Args[0]
y := v.Args[1] y := v.Args[1]
if !(x.Op == OpConstNil && y.Op != OpConstNil) {
goto endcea7f7399afcff860c54d82230a9a934
}
v.Op = OpEqFat
v.AuxInt = 0
v.Aux = nil
v.resetArgs()
v.AddArg(y)
v.AddArg(x)
return true
}
goto endcea7f7399afcff860c54d82230a9a934
endcea7f7399afcff860c54d82230a9a934:
;
// match: (EqFat (Load ptr mem) (ConstNil))
// cond:
// result: (EqPtr (Load <config.fe.TypeUintptr()> ptr mem) (ConstPtr [0]))
{
if v.Args[0].Op != OpLoad {
goto end6f10fb57a906a2c23667c770acb6abf9
}
ptr := v.Args[0].Args[0]
mem := v.Args[0].Args[1]
if v.Args[1].Op != OpConstNil {
goto end6f10fb57a906a2c23667c770acb6abf9
}
v.Op = OpEqPtr v.Op = OpEqPtr
v.AuxInt = 0 v.AuxInt = 0
v.Aux = nil v.Aux = nil
v.resetArgs() v.resetArgs()
v0 := b.NewValue0(v.Line, OpLoad, TypeInvalid) v0 := b.NewValue0(v.Line, OpITab, TypeInvalid)
v0.AddArg(x)
v0.Type = config.fe.TypeUintptr() v0.Type = config.fe.TypeUintptr()
v0.AddArg(ptr)
v0.AddArg(mem)
v.AddArg(v0) v.AddArg(v0)
v1 := b.NewValue0(v.Line, OpConstPtr, TypeInvalid) v1 := b.NewValue0(v.Line, OpITab, TypeInvalid)
v1.AuxInt = 0 v1.AddArg(y)
v1.Type = config.fe.TypeUintptr() v1.Type = config.fe.TypeUintptr()
v.AddArg(v1) v.AddArg(v1)
return true return true
} }
goto end6f10fb57a906a2c23667c770acb6abf9 goto endfcedc545b9bbbe3790786c8981b12d32
end6f10fb57a906a2c23667c770acb6abf9: endfcedc545b9bbbe3790786c8981b12d32:
; ;
case OpEqPtr: case OpEqPtr:
// match: (EqPtr p (ConstNil)) // match: (EqPtr p (ConstNil))
...@@ -521,6 +494,30 @@ func rewriteValuegeneric(v *Value, config *Config) bool { ...@@ -521,6 +494,30 @@ func rewriteValuegeneric(v *Value, config *Config) bool {
goto end7cdc0d5c38fbffe6287c8928803b038e goto end7cdc0d5c38fbffe6287c8928803b038e
end7cdc0d5c38fbffe6287c8928803b038e: end7cdc0d5c38fbffe6287c8928803b038e:
; ;
case OpEqSlice:
// match: (EqSlice x y)
// cond:
// result: (EqPtr (SlicePtr x) (SlicePtr y))
{
x := v.Args[0]
y := v.Args[1]
v.Op = OpEqPtr
v.AuxInt = 0
v.Aux = nil
v.resetArgs()
v0 := b.NewValue0(v.Line, OpSlicePtr, TypeInvalid)
v0.AddArg(x)
v0.Type = config.fe.TypeUintptr()
v.AddArg(v0)
v1 := b.NewValue0(v.Line, OpSlicePtr, TypeInvalid)
v1.AddArg(y)
v1.Type = config.fe.TypeUintptr()
v.AddArg(v1)
return true
}
goto end2937092dca53f896cd527e59e92cab1d
end2937092dca53f896cd527e59e92cab1d:
;
case OpIData: case OpIData:
// match: (IData (IMake _ data)) // match: (IData (IMake _ data))
// cond: // cond:
...@@ -953,56 +950,29 @@ func rewriteValuegeneric(v *Value, config *Config) bool { ...@@ -953,56 +950,29 @@ func rewriteValuegeneric(v *Value, config *Config) bool {
goto end09a0deaf3c42627d0d2d3efa96e30745 goto end09a0deaf3c42627d0d2d3efa96e30745
end09a0deaf3c42627d0d2d3efa96e30745: end09a0deaf3c42627d0d2d3efa96e30745:
; ;
case OpNeqFat: case OpNeqInter:
// match: (NeqFat x y) // match: (NeqInter x y)
// cond: x.Op == OpConstNil && y.Op != OpConstNil // cond:
// result: (NeqFat y x) // result: (NeqPtr (ITab x) (ITab y))
{ {
x := v.Args[0] x := v.Args[0]
y := v.Args[1] y := v.Args[1]
if !(x.Op == OpConstNil && y.Op != OpConstNil) {
goto end94c68f7dc30c66ed42e507e01c4e5dc7
}
v.Op = OpNeqFat
v.AuxInt = 0
v.Aux = nil
v.resetArgs()
v.AddArg(y)
v.AddArg(x)
return true
}
goto end94c68f7dc30c66ed42e507e01c4e5dc7
end94c68f7dc30c66ed42e507e01c4e5dc7:
;
// match: (NeqFat (Load ptr mem) (ConstNil))
// cond:
// result: (NeqPtr (Load <config.fe.TypeUintptr()> ptr mem) (ConstPtr [0]))
{
if v.Args[0].Op != OpLoad {
goto end3ffd7685735a83eaee8dc2577ae89d79
}
ptr := v.Args[0].Args[0]
mem := v.Args[0].Args[1]
if v.Args[1].Op != OpConstNil {
goto end3ffd7685735a83eaee8dc2577ae89d79
}
v.Op = OpNeqPtr v.Op = OpNeqPtr
v.AuxInt = 0 v.AuxInt = 0
v.Aux = nil v.Aux = nil
v.resetArgs() v.resetArgs()
v0 := b.NewValue0(v.Line, OpLoad, TypeInvalid) v0 := b.NewValue0(v.Line, OpITab, TypeInvalid)
v0.AddArg(x)
v0.Type = config.fe.TypeUintptr() v0.Type = config.fe.TypeUintptr()
v0.AddArg(ptr)
v0.AddArg(mem)
v.AddArg(v0) v.AddArg(v0)
v1 := b.NewValue0(v.Line, OpConstPtr, TypeInvalid) v1 := b.NewValue0(v.Line, OpITab, TypeInvalid)
v1.AuxInt = 0 v1.AddArg(y)
v1.Type = config.fe.TypeUintptr() v1.Type = config.fe.TypeUintptr()
v.AddArg(v1) v.AddArg(v1)
return true return true
} }
goto end3ffd7685735a83eaee8dc2577ae89d79 goto end17b2333bf57e9fe81a671be02f9c4c14
end3ffd7685735a83eaee8dc2577ae89d79: end17b2333bf57e9fe81a671be02f9c4c14:
; ;
case OpNeqPtr: case OpNeqPtr:
// match: (NeqPtr p (ConstNil)) // match: (NeqPtr p (ConstNil))
...@@ -1041,6 +1011,30 @@ func rewriteValuegeneric(v *Value, config *Config) bool { ...@@ -1041,6 +1011,30 @@ func rewriteValuegeneric(v *Value, config *Config) bool {
goto enddd95e9c3606d9fd48034f1a703561e45 goto enddd95e9c3606d9fd48034f1a703561e45
enddd95e9c3606d9fd48034f1a703561e45: enddd95e9c3606d9fd48034f1a703561e45:
; ;
case OpNeqSlice:
// match: (NeqSlice x y)
// cond:
// result: (NeqPtr (SlicePtr x) (SlicePtr y))
{
x := v.Args[0]
y := v.Args[1]
v.Op = OpNeqPtr
v.AuxInt = 0
v.Aux = nil
v.resetArgs()
v0 := b.NewValue0(v.Line, OpSlicePtr, TypeInvalid)
v0.AddArg(x)
v0.Type = config.fe.TypeUintptr()
v.AddArg(v0)
v1 := b.NewValue0(v.Line, OpSlicePtr, TypeInvalid)
v1.AddArg(y)
v1.Type = config.fe.TypeUintptr()
v.AddArg(v1)
return true
}
goto endc6bc83c506e491236ca66ea1081231a2
endc6bc83c506e491236ca66ea1081231a2:
;
case OpOr16: case OpOr16:
// match: (Or16 x x) // match: (Or16 x x)
// cond: // cond:
......
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