Commit 58cdecb9 authored by Michael Munday's avatar Michael Munday

cmd/compile: generate constants for NeqPtr, EqPtr and IsNonNil ops

If both inputs are constant offsets from the same pointer then we
can evaluate NeqPtr and EqPtr at compile time. Triggers a few times
during all.bash. Removes a conditional branch in the following
code:

copy(x[1:], x[:])

This branch was recently added as an optimization in CL 94596. We
now skip the memmove if the pointers are equal. However, in the
above code we know at compile time that they are never equal.

Also, when the offset is variable, check if the offset is zero
rather than if the pointers are equal. For example:

copy(x[a:], x[:])

This would now skip the copy if a == 0, rather than if x + a == x.

Finally I've also added a rule to make IsNonNil true for pointers
to values on the stack. The nil check elimination pass will catch
these anyway, but eliminating them here might eliminate branches
earlier.

Change-Id: If72f436fef0a96ad0f4e296d3a1f8b6c3e712085
Reviewed-on: https://go-review.googlesource.com/106635
Run-TryBot: Michael Munday <mike.munday@ibm.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: 's avatarKeith Randall <khr@golang.org>
parent 89d576c9
...@@ -528,11 +528,6 @@ ...@@ -528,11 +528,6 @@
(Phi (Const32 [c]) (Const32 [c])) -> (Const32 [c]) (Phi (Const32 [c]) (Const32 [c])) -> (Const32 [c])
(Phi (Const64 [c]) (Const64 [c])) -> (Const64 [c]) (Phi (Const64 [c]) (Const64 [c])) -> (Const64 [c])
// user nil checks
(NeqPtr p (ConstNil)) -> (IsNonNil p)
(EqPtr p (ConstNil)) -> (Not (IsNonNil p))
(IsNonNil (ConstNil)) -> (ConstBool [0])
// 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,
// so we need only compare the first word (interface type or slice ptr). // so we need only compare the first word (interface type or slice ptr).
...@@ -1241,11 +1236,30 @@ ...@@ -1241,11 +1236,30 @@
&& warnRule(fe.Debug_checknil() && v.Pos.Line() > 1, v, "removed nil check") && warnRule(fe.Debug_checknil() && v.Pos.Line() > 1, v, "removed nil check")
-> (Invalid) -> (Invalid)
// Address comparison shows up in type assertions. // Evaluate constant address comparisons.
(EqPtr x x) -> (ConstBool [1]) (EqPtr x x) -> (ConstBool [1])
(EqPtr (Addr {a} x) (Addr {b} x)) -> (ConstBool [b2i(a == b)])
(NeqPtr x x) -> (ConstBool [0]) (NeqPtr x x) -> (ConstBool [0])
(NeqPtr (Addr {a} x) (Addr {b} x)) -> (ConstBool [b2i(a != b)]) (EqPtr (Addr {a} _) (Addr {b} _)) -> (ConstBool [b2i(a == b)])
(NeqPtr (Addr {a} _) (Addr {b} _)) -> (ConstBool [b2i(a != b)])
(EqPtr (OffPtr [o1] p1) p2) && isSamePtr(p1, p2) -> (ConstBool [b2i(o1 == 0)])
(NeqPtr (OffPtr [o1] p1) p2) && isSamePtr(p1, p2) -> (ConstBool [b2i(o1 != 0)])
(EqPtr (OffPtr [o1] p1) (OffPtr [o2] p2)) && isSamePtr(p1, p2) -> (ConstBool [b2i(o1 == o2)])
(NeqPtr (OffPtr [o1] p1) (OffPtr [o2] p2)) && isSamePtr(p1, p2) -> (ConstBool [b2i(o1 != o2)])
(EqPtr (Const(32|64) [c]) (Const(32|64) [d])) -> (ConstBool [b2i(c == d)])
(NeqPtr (Const(32|64) [c]) (Const(32|64) [d])) -> (ConstBool [b2i(c != d)])
// Simplify address comparisons.
(EqPtr (AddPtr p1 o1) p2) && isSamePtr(p1, p2) -> (Not (IsNonNil o1))
(NeqPtr (AddPtr p1 o1) p2) && isSamePtr(p1, p2) -> (IsNonNil o1)
(EqPtr (Const(32|64) [0]) p) -> (Not (IsNonNil p))
(NeqPtr (Const(32|64) [0]) p) -> (IsNonNil p)
(EqPtr (ConstNil) p) -> (Not (IsNonNil p))
(NeqPtr (ConstNil) p) -> (IsNonNil p)
// Evaluate constant user nil checks.
(IsNonNil (ConstNil)) -> (ConstBool [0])
(IsNonNil (Const(32|64) [c])) -> (ConstBool [b2i(c != 0)])
(IsNonNil (Addr _)) -> (ConstBool [1])
// Inline small runtime.memmove calls with constant length. // Inline small runtime.memmove calls with constant length.
(StaticCall {sym} s1:(Store _ (Const64 [sz]) s2:(Store _ src s3:(Store {t} _ dst mem)))) (StaticCall {sym} s1:(Store _ (Const64 [sz]) s2:(Store _ src s3:(Store {t} _ dst mem))))
......
...@@ -6,8 +6,7 @@ ...@@ -6,8 +6,7 @@
package codegen package codegen
// These tests check that memmoves calls on small data are replaced // Check small copies are replaced with moves.
// with MOVs
func movesmall4() { func movesmall4() {
x := [...]byte{1, 2, 3, 4} x := [...]byte{1, 2, 3, 4}
...@@ -31,3 +30,28 @@ func movesmall16() { ...@@ -31,3 +30,28 @@ func movesmall16() {
// amd64:-".*memmove" // amd64:-".*memmove"
copy(x[1:], x[:]) copy(x[1:], x[:])
} }
// Check that no branches are generated when the pointers are [not] equal.
var x [256]byte
func ptrEqual() {
// amd64:-"JEQ",-"JNE"
// ppc64le:-"BEQ",-"BNE"
// s390x:-"BEQ",-"BNE"
copy(x[:], x[:])
}
func ptrOneOffset() {
// amd64:-"JEQ",-"JNE"
// ppc64le:-"BEQ",-"BNE"
// s390x:-"BEQ",-"BNE"
copy(x[1:], x[:])
}
func ptrBothOffset() {
// amd64:-"JEQ",-"JNE"
// ppc64le:-"BEQ",-"BNE"
// s390x:-"BEQ",-"BNE"
copy(x[1:], x[2:])
}
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