Commit 44343c77 authored by Brian Kessler's avatar Brian Kessler Committed by Brad Fitzpatrick

cmd/compile: add signed divisibility by power of 2 rules

For powers of two (c=1<<k), the divisibility check x%c == 0 can be made
just by checking the trailing zeroes via a mask x&(c-1) == 0 even for signed
integers. This avoids division fix-ups when just divisibility check is needed.

To apply this rule, we match on the fixed-up version of the division. This is
neccessary because the mod and division rewrite rules are already applied
during the initial opt pass.

The speed up on amd64 due to elimination of unneccessary fix-up code is ~55%:

name                     old time/op  new time/op  delta
DivconstI64-4            2.08ns ± 0%  2.09ns ± 1%     ~     (p=0.730 n=5+5)
DivisiblePow2constI64-4  1.78ns ± 1%  0.81ns ± 1%  -54.66%  (p=0.008 n=5+5)
DivconstU64-4            2.08ns ± 0%  2.08ns ± 0%     ~     (p=0.683 n=5+5)
DivconstI32-4            1.53ns ± 0%  1.53ns ± 1%     ~     (p=0.968 n=4+5)
DivisiblePow2constI32-4  1.79ns ± 1%  0.81ns ± 1%  -54.97%  (p=0.008 n=5+5)
DivconstU32-4            1.78ns ± 1%  1.80ns ± 2%     ~     (p=0.206 n=5+5)
DivconstI16-4            1.54ns ± 2%  1.54ns ± 0%     ~     (p=0.238 n=5+4)
DivisiblePow2constI16-4  1.78ns ± 0%  0.81ns ± 1%  -54.72%  (p=0.000 n=4+5)
DivconstU16-4            1.00ns ± 5%  1.01ns ± 1%     ~     (p=0.119 n=5+5)
DivconstI8-4             1.54ns ± 0%  1.54ns ± 2%     ~     (p=0.571 n=4+5)
DivisiblePow2constI8-4   1.78ns ± 0%  0.82ns ± 8%  -53.71%  (p=0.008 n=5+5)
DivconstU8-4             0.93ns ± 1%  0.93ns ± 1%     ~     (p=0.643 n=5+5)

A follow-up CL will address the general case of x%c == 0 for signed integers.

Updates #15806

Change-Id: Iabadbbe369b6e0998c8ce85d038ebc236142e42a
Reviewed-on: https://go-review.googlesource.com/c/go/+/173557
Run-TryBot: Brian Kessler <brian.m.kessler@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarKeith Randall <khr@golang.org>
parent 2693b424
......@@ -7,6 +7,7 @@
package main
import (
"math"
"runtime"
"testing"
)
......@@ -924,6 +925,7 @@ func TestArithmetic(t *testing.T) {
testShiftRemoval(t)
testShiftedOps(t)
testDivFixUp(t)
testDivisibleSignedPow2(t)
}
// testDivFixUp ensures that signed division fix-ups are being generated.
......@@ -952,3 +954,292 @@ func testDivFixUp(t *testing.T) {
g64 = z % int64(i)
}
}
//go:noinline
func divisible_int8_2to1(x int8) bool {
return x%(1<<1) == 0
}
//go:noinline
func divisible_int8_2to2(x int8) bool {
return x%(1<<2) == 0
}
//go:noinline
func divisible_int8_2to3(x int8) bool {
return x%(1<<3) == 0
}
//go:noinline
func divisible_int8_2to4(x int8) bool {
return x%(1<<4) == 0
}
//go:noinline
func divisible_int8_2to5(x int8) bool {
return x%(1<<5) == 0
}
//go:noinline
func divisible_int8_2to6(x int8) bool {
return x%(1<<6) == 0
}
//go:noinline
func divisible_int16_2to1(x int16) bool {
return x%(1<<1) == 0
}
//go:noinline
func divisible_int16_2to2(x int16) bool {
return x%(1<<2) == 0
}
//go:noinline
func divisible_int16_2to3(x int16) bool {
return x%(1<<3) == 0
}
//go:noinline
func divisible_int16_2to4(x int16) bool {
return x%(1<<4) == 0
}
//go:noinline
func divisible_int16_2to5(x int16) bool {
return x%(1<<5) == 0
}
//go:noinline
func divisible_int16_2to6(x int16) bool {
return x%(1<<6) == 0
}
//go:noinline
func divisible_int16_2to7(x int16) bool {
return x%(1<<7) == 0
}
//go:noinline
func divisible_int16_2to8(x int16) bool {
return x%(1<<8) == 0
}
//go:noinline
func divisible_int16_2to9(x int16) bool {
return x%(1<<9) == 0
}
//go:noinline
func divisible_int16_2to10(x int16) bool {
return x%(1<<10) == 0
}
//go:noinline
func divisible_int16_2to11(x int16) bool {
return x%(1<<11) == 0
}
//go:noinline
func divisible_int16_2to12(x int16) bool {
return x%(1<<12) == 0
}
//go:noinline
func divisible_int16_2to13(x int16) bool {
return x%(1<<13) == 0
}
//go:noinline
func divisible_int16_2to14(x int16) bool {
return x%(1<<14) == 0
}
//go:noinline
func divisible_int32_2to4(x int32) bool {
return x%(1<<4) == 0
}
//go:noinline
func divisible_int32_2to15(x int32) bool {
return x%(1<<15) == 0
}
//go:noinline
func divisible_int32_2to26(x int32) bool {
return x%(1<<26) == 0
}
//go:noinline
func divisible_int64_2to4(x int64) bool {
return x%(1<<4) == 0
}
//go:noinline
func divisible_int64_2to15(x int64) bool {
return x%(1<<15) == 0
}
//go:noinline
func divisible_int64_2to26(x int64) bool {
return x%(1<<26) == 0
}
//go:noinline
func divisible_int64_2to34(x int64) bool {
return x%(1<<34) == 0
}
//go:noinline
func divisible_int64_2to48(x int64) bool {
return x%(1<<48) == 0
}
//go:noinline
func divisible_int64_2to57(x int64) bool {
return x%(1<<57) == 0
}
// testDivisibleSignedPow2 confirms that x%(1<<k)==0 is rewritten correctly
func testDivisibleSignedPow2(t *testing.T) {
var i int64
var pow2 = []int64{
1,
1 << 1,
1 << 2,
1 << 3,
1 << 4,
1 << 5,
1 << 6,
1 << 7,
1 << 8,
1 << 9,
1 << 10,
1 << 11,
1 << 12,
1 << 13,
1 << 14,
}
// exhaustive test for int8
for i = math.MinInt8; i <= math.MaxInt8; i++ {
if want, got := int8(i)%int8(pow2[1]) == 0, divisible_int8_2to1(int8(i)); got != want {
t.Errorf("divisible_int8_2to1(%d) = %v want %v", i, got, want)
}
if want, got := int8(i)%int8(pow2[2]) == 0, divisible_int8_2to2(int8(i)); got != want {
t.Errorf("divisible_int8_2to2(%d) = %v want %v", i, got, want)
}
if want, got := int8(i)%int8(pow2[3]) == 0, divisible_int8_2to3(int8(i)); got != want {
t.Errorf("divisible_int8_2to3(%d) = %v want %v", i, got, want)
}
if want, got := int8(i)%int8(pow2[4]) == 0, divisible_int8_2to4(int8(i)); got != want {
t.Errorf("divisible_int8_2to4(%d) = %v want %v", i, got, want)
}
if want, got := int8(i)%int8(pow2[5]) == 0, divisible_int8_2to5(int8(i)); got != want {
t.Errorf("divisible_int8_2to5(%d) = %v want %v", i, got, want)
}
if want, got := int8(i)%int8(pow2[6]) == 0, divisible_int8_2to6(int8(i)); got != want {
t.Errorf("divisible_int8_2to6(%d) = %v want %v", i, got, want)
}
}
// exhaustive test for int16
for i = math.MinInt16; i <= math.MaxInt16; i++ {
if want, got := int16(i)%int16(pow2[1]) == 0, divisible_int16_2to1(int16(i)); got != want {
t.Errorf("divisible_int16_2to1(%d) = %v want %v", i, got, want)
}
if want, got := int16(i)%int16(pow2[2]) == 0, divisible_int16_2to2(int16(i)); got != want {
t.Errorf("divisible_int16_2to2(%d) = %v want %v", i, got, want)
}
if want, got := int16(i)%int16(pow2[3]) == 0, divisible_int16_2to3(int16(i)); got != want {
t.Errorf("divisible_int16_2to3(%d) = %v want %v", i, got, want)
}
if want, got := int16(i)%int16(pow2[4]) == 0, divisible_int16_2to4(int16(i)); got != want {
t.Errorf("divisible_int16_2to4(%d) = %v want %v", i, got, want)
}
if want, got := int16(i)%int16(pow2[5]) == 0, divisible_int16_2to5(int16(i)); got != want {
t.Errorf("divisible_int16_2to5(%d) = %v want %v", i, got, want)
}
if want, got := int16(i)%int16(pow2[6]) == 0, divisible_int16_2to6(int16(i)); got != want {
t.Errorf("divisible_int16_2to6(%d) = %v want %v", i, got, want)
}
if want, got := int16(i)%int16(pow2[7]) == 0, divisible_int16_2to7(int16(i)); got != want {
t.Errorf("divisible_int16_2to7(%d) = %v want %v", i, got, want)
}
if want, got := int16(i)%int16(pow2[8]) == 0, divisible_int16_2to8(int16(i)); got != want {
t.Errorf("divisible_int16_2to8(%d) = %v want %v", i, got, want)
}
if want, got := int16(i)%int16(pow2[9]) == 0, divisible_int16_2to9(int16(i)); got != want {
t.Errorf("divisible_int16_2to9(%d) = %v want %v", i, got, want)
}
if want, got := int16(i)%int16(pow2[10]) == 0, divisible_int16_2to10(int16(i)); got != want {
t.Errorf("divisible_int16_2to10(%d) = %v want %v", i, got, want)
}
if want, got := int16(i)%int16(pow2[11]) == 0, divisible_int16_2to11(int16(i)); got != want {
t.Errorf("divisible_int16_2to11(%d) = %v want %v", i, got, want)
}
if want, got := int16(i)%int16(pow2[12]) == 0, divisible_int16_2to12(int16(i)); got != want {
t.Errorf("divisible_int16_2to12(%d) = %v want %v", i, got, want)
}
if want, got := int16(i)%int16(pow2[13]) == 0, divisible_int16_2to13(int16(i)); got != want {
t.Errorf("divisible_int16_2to13(%d) = %v want %v", i, got, want)
}
if want, got := int16(i)%int16(pow2[14]) == 0, divisible_int16_2to14(int16(i)); got != want {
t.Errorf("divisible_int16_2to14(%d) = %v want %v", i, got, want)
}
}
// spot check for int32 and int64
var (
two4 int64 = 1 << 4
two15 int64 = 1 << 15
two26 int64 = 1 << 26
two34 int64 = 1 << 34
two48 int64 = 1 << 48
two57 int64 = 1 << 57
)
var xs = []int64{two4, two4 + 3, -3 * two4, -3*two4 + 1,
two15, two15 + 3, -3 * two15, -3*two15 + 1,
two26, two26 + 37, -5 * two26, -5*two26 + 2,
two34, two34 + 356, -7 * two34, -7*two34 + 13,
two48, two48 + 3000, -12 * two48, -12*two48 + 1111,
two57, two57 + 397654, -15 * two57, -15*two57 + 11234,
}
for _, x := range xs {
if int64(int32(x)) == x {
if want, got := int32(x)%int32(two4) == 0, divisible_int32_2to4(int32(x)); got != want {
t.Errorf("divisible_int32_2to4(%d) = %v want %v", x, got, want)
}
if want, got := int32(x)%int32(two15) == 0, divisible_int32_2to15(int32(x)); got != want {
t.Errorf("divisible_int32_2to15(%d) = %v want %v", x, got, want)
}
if want, got := int32(x)%int32(two26) == 0, divisible_int32_2to26(int32(x)); got != want {
t.Errorf("divisible_int32_2to26(%d) = %v want %v", x, got, want)
}
}
// spot check for int64
if want, got := x%two4 == 0, divisible_int64_2to4(x); got != want {
t.Errorf("divisible_int64_2to4(%d) = %v want %v", x, got, want)
}
if want, got := x%two15 == 0, divisible_int64_2to15(x); got != want {
t.Errorf("divisible_int64_2to15(%d) = %v want %v", x, got, want)
}
if want, got := x%two26 == 0, divisible_int64_2to26(x); got != want {
t.Errorf("divisible_int64_2to26(%d) = %v want %v", x, got, want)
}
if want, got := x%two34 == 0, divisible_int64_2to34(x); got != want {
t.Errorf("divisible_int64_2to34(%d) = %v want %v", x, got, want)
}
if want, got := x%two48 == 0, divisible_int64_2to48(x); got != want {
t.Errorf("divisible_int64_2to48(%d) = %v want %v", x, got, want)
}
if want, got := x%two57 == 0, divisible_int64_2to57(x); got != want {
t.Errorf("divisible_int64_2to57(%d) = %v want %v", x, got, want)
}
}
}
......@@ -1163,6 +1163,41 @@
(Mod64u <t> x (Const64 [c])) && x.Op != OpConst64 && c > 0 && umagicOK(64,c)
-> (Sub64 x (Mul64 <t> (Div64u <t> x (Const64 <t> [c])) (Const64 <t> [c])))
// Divisibility check for signed integers for power of two constant are simple mask.
// However, we must match against the rewritten n%c == 0 -> n - c*(n/c) == 0 -> n == c *(n/c)
// where n/c contains fixup code to handle signed n.
(Eq8 n (Lsh8x64
(Rsh8x64
(Add8 <t> n (Rsh8Ux64 <t> (Rsh8x64 <t> n (Const64 <typ.UInt64> [ 7])) (Const64 <typ.UInt64> [kbar])))
(Const64 <typ.UInt64> [k]))
(Const64 <typ.UInt64> [k]))
) && k > 0 && k < 7 && kbar == 8 - k
-> (Eq8 (And8 <t> n (Const8 <t> [int64(1<<uint(k)-1)])) (Const8 <t> [0]))
(Eq16 n (Lsh16x64
(Rsh16x64
(Add16 <t> n (Rsh16Ux64 <t> (Rsh16x64 <t> n (Const64 <typ.UInt64> [15])) (Const64 <typ.UInt64> [kbar])))
(Const64 <typ.UInt64> [k]))
(Const64 <typ.UInt64> [k]))
) && k > 0 && k < 15 && kbar == 16 - k
-> (Eq16 (And16 <t> n (Const16 <t> [int64(1<<uint(k)-1)])) (Const16 <t> [0]))
(Eq32 n (Lsh32x64
(Rsh32x64
(Add32 <t> n (Rsh32Ux64 <t> (Rsh32x64 <t> n (Const64 <typ.UInt64> [31])) (Const64 <typ.UInt64> [kbar])))
(Const64 <typ.UInt64> [k]))
(Const64 <typ.UInt64> [k]))
) && k > 0 && k < 31 && kbar == 32 - k
-> (Eq32 (And32 <t> n (Const32 <t> [int64(1<<uint(k)-1)])) (Const32 <t> [0]))
(Eq64 n (Lsh64x64
(Rsh64x64
(Add64 <t> n (Rsh64Ux64 <t> (Rsh64x64 <t> n (Const64 <typ.UInt64> [63])) (Const64 <typ.UInt64> [kbar])))
(Const64 <typ.UInt64> [k]))
(Const64 <typ.UInt64> [k]))
) && k > 0 && k < 63 && kbar == 64 - k
-> (Eq64 (And64 <t> n (Const64 <t> [int64(1<<uint(k)-1)])) (Const64 <t> [0]))
(Eq(8|16|32|64) s:(Sub(8|16|32|64) x y) (Const(8|16|32|64) [0])) && s.Uses == 1 -> (Eq(8|16|32|64) x y)
(Neq(8|16|32|64) s:(Sub(8|16|32|64) x y) (Const(8|16|32|64) [0])) && s.Uses == 1 -> (Neq(8|16|32|64) x y)
......
......@@ -98,17 +98,17 @@ func rewriteValuegeneric(v *Value) bool {
case OpDiv8u:
return rewriteValuegeneric_OpDiv8u_0(v)
case OpEq16:
return rewriteValuegeneric_OpEq16_0(v)
return rewriteValuegeneric_OpEq16_0(v) || rewriteValuegeneric_OpEq16_10(v)
case OpEq32:
return rewriteValuegeneric_OpEq32_0(v)
return rewriteValuegeneric_OpEq32_0(v) || rewriteValuegeneric_OpEq32_10(v)
case OpEq32F:
return rewriteValuegeneric_OpEq32F_0(v)
case OpEq64:
return rewriteValuegeneric_OpEq64_0(v)
return rewriteValuegeneric_OpEq64_0(v) || rewriteValuegeneric_OpEq64_10(v)
case OpEq64F:
return rewriteValuegeneric_OpEq64F_0(v)
case OpEq8:
return rewriteValuegeneric_OpEq8_0(v)
return rewriteValuegeneric_OpEq8_0(v) || rewriteValuegeneric_OpEq8_10(v)
case OpEqB:
return rewriteValuegeneric_OpEqB_0(v)
case OpEqInter:
......@@ -8775,6 +8775,7 @@ func rewriteValuegeneric_OpDiv8u_0(v *Value) bool {
}
func rewriteValuegeneric_OpEq16_0(v *Value) bool {
b := v.Block
typ := &b.Func.Config.Types
// match: (Eq16 x x)
// cond:
// result: (ConstBool [1])
......@@ -8951,6 +8952,389 @@ func rewriteValuegeneric_OpEq16_0(v *Value) bool {
v.AuxInt = b2i(c == d)
return true
}
// match: (Eq16 n (Lsh16x64 (Rsh16x64 (Add16 <t> n (Rsh16Ux64 <t> (Rsh16x64 <t> n (Const64 <typ.UInt64> [15])) (Const64 <typ.UInt64> [kbar]))) (Const64 <typ.UInt64> [k])) (Const64 <typ.UInt64> [k])))
// cond: k > 0 && k < 15 && kbar == 16 - k
// result: (Eq16 (And16 <t> n (Const16 <t> [int64(1<<uint(k)-1)])) (Const16 <t> [0]))
for {
_ = v.Args[1]
n := v.Args[0]
v_1 := v.Args[1]
if v_1.Op != OpLsh16x64 {
break
}
_ = v_1.Args[1]
v_1_0 := v_1.Args[0]
if v_1_0.Op != OpRsh16x64 {
break
}
_ = v_1_0.Args[1]
v_1_0_0 := v_1_0.Args[0]
if v_1_0_0.Op != OpAdd16 {
break
}
t := v_1_0_0.Type
_ = v_1_0_0.Args[1]
if n != v_1_0_0.Args[0] {
break
}
v_1_0_0_1 := v_1_0_0.Args[1]
if v_1_0_0_1.Op != OpRsh16Ux64 {
break
}
if v_1_0_0_1.Type != t {
break
}
_ = v_1_0_0_1.Args[1]
v_1_0_0_1_0 := v_1_0_0_1.Args[0]
if v_1_0_0_1_0.Op != OpRsh16x64 {
break
}
if v_1_0_0_1_0.Type != t {
break
}
_ = v_1_0_0_1_0.Args[1]
if n != v_1_0_0_1_0.Args[0] {
break
}
v_1_0_0_1_0_1 := v_1_0_0_1_0.Args[1]
if v_1_0_0_1_0_1.Op != OpConst64 {
break
}
if v_1_0_0_1_0_1.Type != typ.UInt64 {
break
}
if v_1_0_0_1_0_1.AuxInt != 15 {
break
}
v_1_0_0_1_1 := v_1_0_0_1.Args[1]
if v_1_0_0_1_1.Op != OpConst64 {
break
}
if v_1_0_0_1_1.Type != typ.UInt64 {
break
}
kbar := v_1_0_0_1_1.AuxInt
v_1_0_1 := v_1_0.Args[1]
if v_1_0_1.Op != OpConst64 {
break
}
if v_1_0_1.Type != typ.UInt64 {
break
}
k := v_1_0_1.AuxInt
v_1_1 := v_1.Args[1]
if v_1_1.Op != OpConst64 {
break
}
if v_1_1.Type != typ.UInt64 {
break
}
if v_1_1.AuxInt != k {
break
}
if !(k > 0 && k < 15 && kbar == 16-k) {
break
}
v.reset(OpEq16)
v0 := b.NewValue0(v.Pos, OpAnd16, t)
v0.AddArg(n)
v1 := b.NewValue0(v.Pos, OpConst16, t)
v1.AuxInt = int64(1<<uint(k) - 1)
v0.AddArg(v1)
v.AddArg(v0)
v2 := b.NewValue0(v.Pos, OpConst16, t)
v2.AuxInt = 0
v.AddArg(v2)
return true
}
// match: (Eq16 n (Lsh16x64 (Rsh16x64 (Add16 <t> (Rsh16Ux64 <t> (Rsh16x64 <t> n (Const64 <typ.UInt64> [15])) (Const64 <typ.UInt64> [kbar])) n) (Const64 <typ.UInt64> [k])) (Const64 <typ.UInt64> [k])))
// cond: k > 0 && k < 15 && kbar == 16 - k
// result: (Eq16 (And16 <t> n (Const16 <t> [int64(1<<uint(k)-1)])) (Const16 <t> [0]))
for {
_ = v.Args[1]
n := v.Args[0]
v_1 := v.Args[1]
if v_1.Op != OpLsh16x64 {
break
}
_ = v_1.Args[1]
v_1_0 := v_1.Args[0]
if v_1_0.Op != OpRsh16x64 {
break
}
_ = v_1_0.Args[1]
v_1_0_0 := v_1_0.Args[0]
if v_1_0_0.Op != OpAdd16 {
break
}
t := v_1_0_0.Type
_ = v_1_0_0.Args[1]
v_1_0_0_0 := v_1_0_0.Args[0]
if v_1_0_0_0.Op != OpRsh16Ux64 {
break
}
if v_1_0_0_0.Type != t {
break
}
_ = v_1_0_0_0.Args[1]
v_1_0_0_0_0 := v_1_0_0_0.Args[0]
if v_1_0_0_0_0.Op != OpRsh16x64 {
break
}
if v_1_0_0_0_0.Type != t {
break
}
_ = v_1_0_0_0_0.Args[1]
if n != v_1_0_0_0_0.Args[0] {
break
}
v_1_0_0_0_0_1 := v_1_0_0_0_0.Args[1]
if v_1_0_0_0_0_1.Op != OpConst64 {
break
}
if v_1_0_0_0_0_1.Type != typ.UInt64 {
break
}
if v_1_0_0_0_0_1.AuxInt != 15 {
break
}
v_1_0_0_0_1 := v_1_0_0_0.Args[1]
if v_1_0_0_0_1.Op != OpConst64 {
break
}
if v_1_0_0_0_1.Type != typ.UInt64 {
break
}
kbar := v_1_0_0_0_1.AuxInt
if n != v_1_0_0.Args[1] {
break
}
v_1_0_1 := v_1_0.Args[1]
if v_1_0_1.Op != OpConst64 {
break
}
if v_1_0_1.Type != typ.UInt64 {
break
}
k := v_1_0_1.AuxInt
v_1_1 := v_1.Args[1]
if v_1_1.Op != OpConst64 {
break
}
if v_1_1.Type != typ.UInt64 {
break
}
if v_1_1.AuxInt != k {
break
}
if !(k > 0 && k < 15 && kbar == 16-k) {
break
}
v.reset(OpEq16)
v0 := b.NewValue0(v.Pos, OpAnd16, t)
v0.AddArg(n)
v1 := b.NewValue0(v.Pos, OpConst16, t)
v1.AuxInt = int64(1<<uint(k) - 1)
v0.AddArg(v1)
v.AddArg(v0)
v2 := b.NewValue0(v.Pos, OpConst16, t)
v2.AuxInt = 0
v.AddArg(v2)
return true
}
// match: (Eq16 (Lsh16x64 (Rsh16x64 (Add16 <t> n (Rsh16Ux64 <t> (Rsh16x64 <t> n (Const64 <typ.UInt64> [15])) (Const64 <typ.UInt64> [kbar]))) (Const64 <typ.UInt64> [k])) (Const64 <typ.UInt64> [k])) n)
// cond: k > 0 && k < 15 && kbar == 16 - k
// result: (Eq16 (And16 <t> n (Const16 <t> [int64(1<<uint(k)-1)])) (Const16 <t> [0]))
for {
n := v.Args[1]
v_0 := v.Args[0]
if v_0.Op != OpLsh16x64 {
break
}
_ = v_0.Args[1]
v_0_0 := v_0.Args[0]
if v_0_0.Op != OpRsh16x64 {
break
}
_ = v_0_0.Args[1]
v_0_0_0 := v_0_0.Args[0]
if v_0_0_0.Op != OpAdd16 {
break
}
t := v_0_0_0.Type
_ = v_0_0_0.Args[1]
if n != v_0_0_0.Args[0] {
break
}
v_0_0_0_1 := v_0_0_0.Args[1]
if v_0_0_0_1.Op != OpRsh16Ux64 {
break
}
if v_0_0_0_1.Type != t {
break
}
_ = v_0_0_0_1.Args[1]
v_0_0_0_1_0 := v_0_0_0_1.Args[0]
if v_0_0_0_1_0.Op != OpRsh16x64 {
break
}
if v_0_0_0_1_0.Type != t {
break
}
_ = v_0_0_0_1_0.Args[1]
if n != v_0_0_0_1_0.Args[0] {
break
}
v_0_0_0_1_0_1 := v_0_0_0_1_0.Args[1]
if v_0_0_0_1_0_1.Op != OpConst64 {
break
}
if v_0_0_0_1_0_1.Type != typ.UInt64 {
break
}
if v_0_0_0_1_0_1.AuxInt != 15 {
break
}
v_0_0_0_1_1 := v_0_0_0_1.Args[1]
if v_0_0_0_1_1.Op != OpConst64 {
break
}
if v_0_0_0_1_1.Type != typ.UInt64 {
break
}
kbar := v_0_0_0_1_1.AuxInt
v_0_0_1 := v_0_0.Args[1]
if v_0_0_1.Op != OpConst64 {
break
}
if v_0_0_1.Type != typ.UInt64 {
break
}
k := v_0_0_1.AuxInt
v_0_1 := v_0.Args[1]
if v_0_1.Op != OpConst64 {
break
}
if v_0_1.Type != typ.UInt64 {
break
}
if v_0_1.AuxInt != k {
break
}
if !(k > 0 && k < 15 && kbar == 16-k) {
break
}
v.reset(OpEq16)
v0 := b.NewValue0(v.Pos, OpAnd16, t)
v0.AddArg(n)
v1 := b.NewValue0(v.Pos, OpConst16, t)
v1.AuxInt = int64(1<<uint(k) - 1)
v0.AddArg(v1)
v.AddArg(v0)
v2 := b.NewValue0(v.Pos, OpConst16, t)
v2.AuxInt = 0
v.AddArg(v2)
return true
}
return false
}
func rewriteValuegeneric_OpEq16_10(v *Value) bool {
b := v.Block
typ := &b.Func.Config.Types
// match: (Eq16 (Lsh16x64 (Rsh16x64 (Add16 <t> (Rsh16Ux64 <t> (Rsh16x64 <t> n (Const64 <typ.UInt64> [15])) (Const64 <typ.UInt64> [kbar])) n) (Const64 <typ.UInt64> [k])) (Const64 <typ.UInt64> [k])) n)
// cond: k > 0 && k < 15 && kbar == 16 - k
// result: (Eq16 (And16 <t> n (Const16 <t> [int64(1<<uint(k)-1)])) (Const16 <t> [0]))
for {
n := v.Args[1]
v_0 := v.Args[0]
if v_0.Op != OpLsh16x64 {
break
}
_ = v_0.Args[1]
v_0_0 := v_0.Args[0]
if v_0_0.Op != OpRsh16x64 {
break
}
_ = v_0_0.Args[1]
v_0_0_0 := v_0_0.Args[0]
if v_0_0_0.Op != OpAdd16 {
break
}
t := v_0_0_0.Type
_ = v_0_0_0.Args[1]
v_0_0_0_0 := v_0_0_0.Args[0]
if v_0_0_0_0.Op != OpRsh16Ux64 {
break
}
if v_0_0_0_0.Type != t {
break
}
_ = v_0_0_0_0.Args[1]
v_0_0_0_0_0 := v_0_0_0_0.Args[0]
if v_0_0_0_0_0.Op != OpRsh16x64 {
break
}
if v_0_0_0_0_0.Type != t {
break
}
_ = v_0_0_0_0_0.Args[1]
if n != v_0_0_0_0_0.Args[0] {
break
}
v_0_0_0_0_0_1 := v_0_0_0_0_0.Args[1]
if v_0_0_0_0_0_1.Op != OpConst64 {
break
}
if v_0_0_0_0_0_1.Type != typ.UInt64 {
break
}
if v_0_0_0_0_0_1.AuxInt != 15 {
break
}
v_0_0_0_0_1 := v_0_0_0_0.Args[1]
if v_0_0_0_0_1.Op != OpConst64 {
break
}
if v_0_0_0_0_1.Type != typ.UInt64 {
break
}
kbar := v_0_0_0_0_1.AuxInt
if n != v_0_0_0.Args[1] {
break
}
v_0_0_1 := v_0_0.Args[1]
if v_0_0_1.Op != OpConst64 {
break
}
if v_0_0_1.Type != typ.UInt64 {
break
}
k := v_0_0_1.AuxInt
v_0_1 := v_0.Args[1]
if v_0_1.Op != OpConst64 {
break
}
if v_0_1.Type != typ.UInt64 {
break
}
if v_0_1.AuxInt != k {
break
}
if !(k > 0 && k < 15 && kbar == 16-k) {
break
}
v.reset(OpEq16)
v0 := b.NewValue0(v.Pos, OpAnd16, t)
v0.AddArg(n)
v1 := b.NewValue0(v.Pos, OpConst16, t)
v1.AuxInt = int64(1<<uint(k) - 1)
v0.AddArg(v1)
v.AddArg(v0)
v2 := b.NewValue0(v.Pos, OpConst16, t)
v2.AuxInt = 0
v.AddArg(v2)
return true
}
// match: (Eq16 s:(Sub16 x y) (Const16 [0]))
// cond: s.Uses == 1
// result: (Eq16 x y)
......@@ -9007,6 +9391,7 @@ func rewriteValuegeneric_OpEq16_0(v *Value) bool {
}
func rewriteValuegeneric_OpEq32_0(v *Value) bool {
b := v.Block
typ := &b.Func.Config.Types
// match: (Eq32 x x)
// cond:
// result: (ConstBool [1])
......@@ -9183,7 +9568,390 @@ func rewriteValuegeneric_OpEq32_0(v *Value) bool {
v.AuxInt = b2i(c == d)
return true
}
// match: (Eq32 s:(Sub32 x y) (Const32 [0]))
// match: (Eq32 n (Lsh32x64 (Rsh32x64 (Add32 <t> n (Rsh32Ux64 <t> (Rsh32x64 <t> n (Const64 <typ.UInt64> [31])) (Const64 <typ.UInt64> [kbar]))) (Const64 <typ.UInt64> [k])) (Const64 <typ.UInt64> [k])))
// cond: k > 0 && k < 31 && kbar == 32 - k
// result: (Eq32 (And32 <t> n (Const32 <t> [int64(1<<uint(k)-1)])) (Const32 <t> [0]))
for {
_ = v.Args[1]
n := v.Args[0]
v_1 := v.Args[1]
if v_1.Op != OpLsh32x64 {
break
}
_ = v_1.Args[1]
v_1_0 := v_1.Args[0]
if v_1_0.Op != OpRsh32x64 {
break
}
_ = v_1_0.Args[1]
v_1_0_0 := v_1_0.Args[0]
if v_1_0_0.Op != OpAdd32 {
break
}
t := v_1_0_0.Type
_ = v_1_0_0.Args[1]
if n != v_1_0_0.Args[0] {
break
}
v_1_0_0_1 := v_1_0_0.Args[1]
if v_1_0_0_1.Op != OpRsh32Ux64 {
break
}
if v_1_0_0_1.Type != t {
break
}
_ = v_1_0_0_1.Args[1]
v_1_0_0_1_0 := v_1_0_0_1.Args[0]
if v_1_0_0_1_0.Op != OpRsh32x64 {
break
}
if v_1_0_0_1_0.Type != t {
break
}
_ = v_1_0_0_1_0.Args[1]
if n != v_1_0_0_1_0.Args[0] {
break
}
v_1_0_0_1_0_1 := v_1_0_0_1_0.Args[1]
if v_1_0_0_1_0_1.Op != OpConst64 {
break
}
if v_1_0_0_1_0_1.Type != typ.UInt64 {
break
}
if v_1_0_0_1_0_1.AuxInt != 31 {
break
}
v_1_0_0_1_1 := v_1_0_0_1.Args[1]
if v_1_0_0_1_1.Op != OpConst64 {
break
}
if v_1_0_0_1_1.Type != typ.UInt64 {
break
}
kbar := v_1_0_0_1_1.AuxInt
v_1_0_1 := v_1_0.Args[1]
if v_1_0_1.Op != OpConst64 {
break
}
if v_1_0_1.Type != typ.UInt64 {
break
}
k := v_1_0_1.AuxInt
v_1_1 := v_1.Args[1]
if v_1_1.Op != OpConst64 {
break
}
if v_1_1.Type != typ.UInt64 {
break
}
if v_1_1.AuxInt != k {
break
}
if !(k > 0 && k < 31 && kbar == 32-k) {
break
}
v.reset(OpEq32)
v0 := b.NewValue0(v.Pos, OpAnd32, t)
v0.AddArg(n)
v1 := b.NewValue0(v.Pos, OpConst32, t)
v1.AuxInt = int64(1<<uint(k) - 1)
v0.AddArg(v1)
v.AddArg(v0)
v2 := b.NewValue0(v.Pos, OpConst32, t)
v2.AuxInt = 0
v.AddArg(v2)
return true
}
// match: (Eq32 n (Lsh32x64 (Rsh32x64 (Add32 <t> (Rsh32Ux64 <t> (Rsh32x64 <t> n (Const64 <typ.UInt64> [31])) (Const64 <typ.UInt64> [kbar])) n) (Const64 <typ.UInt64> [k])) (Const64 <typ.UInt64> [k])))
// cond: k > 0 && k < 31 && kbar == 32 - k
// result: (Eq32 (And32 <t> n (Const32 <t> [int64(1<<uint(k)-1)])) (Const32 <t> [0]))
for {
_ = v.Args[1]
n := v.Args[0]
v_1 := v.Args[1]
if v_1.Op != OpLsh32x64 {
break
}
_ = v_1.Args[1]
v_1_0 := v_1.Args[0]
if v_1_0.Op != OpRsh32x64 {
break
}
_ = v_1_0.Args[1]
v_1_0_0 := v_1_0.Args[0]
if v_1_0_0.Op != OpAdd32 {
break
}
t := v_1_0_0.Type
_ = v_1_0_0.Args[1]
v_1_0_0_0 := v_1_0_0.Args[0]
if v_1_0_0_0.Op != OpRsh32Ux64 {
break
}
if v_1_0_0_0.Type != t {
break
}
_ = v_1_0_0_0.Args[1]
v_1_0_0_0_0 := v_1_0_0_0.Args[0]
if v_1_0_0_0_0.Op != OpRsh32x64 {
break
}
if v_1_0_0_0_0.Type != t {
break
}
_ = v_1_0_0_0_0.Args[1]
if n != v_1_0_0_0_0.Args[0] {
break
}
v_1_0_0_0_0_1 := v_1_0_0_0_0.Args[1]
if v_1_0_0_0_0_1.Op != OpConst64 {
break
}
if v_1_0_0_0_0_1.Type != typ.UInt64 {
break
}
if v_1_0_0_0_0_1.AuxInt != 31 {
break
}
v_1_0_0_0_1 := v_1_0_0_0.Args[1]
if v_1_0_0_0_1.Op != OpConst64 {
break
}
if v_1_0_0_0_1.Type != typ.UInt64 {
break
}
kbar := v_1_0_0_0_1.AuxInt
if n != v_1_0_0.Args[1] {
break
}
v_1_0_1 := v_1_0.Args[1]
if v_1_0_1.Op != OpConst64 {
break
}
if v_1_0_1.Type != typ.UInt64 {
break
}
k := v_1_0_1.AuxInt
v_1_1 := v_1.Args[1]
if v_1_1.Op != OpConst64 {
break
}
if v_1_1.Type != typ.UInt64 {
break
}
if v_1_1.AuxInt != k {
break
}
if !(k > 0 && k < 31 && kbar == 32-k) {
break
}
v.reset(OpEq32)
v0 := b.NewValue0(v.Pos, OpAnd32, t)
v0.AddArg(n)
v1 := b.NewValue0(v.Pos, OpConst32, t)
v1.AuxInt = int64(1<<uint(k) - 1)
v0.AddArg(v1)
v.AddArg(v0)
v2 := b.NewValue0(v.Pos, OpConst32, t)
v2.AuxInt = 0
v.AddArg(v2)
return true
}
// match: (Eq32 (Lsh32x64 (Rsh32x64 (Add32 <t> n (Rsh32Ux64 <t> (Rsh32x64 <t> n (Const64 <typ.UInt64> [31])) (Const64 <typ.UInt64> [kbar]))) (Const64 <typ.UInt64> [k])) (Const64 <typ.UInt64> [k])) n)
// cond: k > 0 && k < 31 && kbar == 32 - k
// result: (Eq32 (And32 <t> n (Const32 <t> [int64(1<<uint(k)-1)])) (Const32 <t> [0]))
for {
n := v.Args[1]
v_0 := v.Args[0]
if v_0.Op != OpLsh32x64 {
break
}
_ = v_0.Args[1]
v_0_0 := v_0.Args[0]
if v_0_0.Op != OpRsh32x64 {
break
}
_ = v_0_0.Args[1]
v_0_0_0 := v_0_0.Args[0]
if v_0_0_0.Op != OpAdd32 {
break
}
t := v_0_0_0.Type
_ = v_0_0_0.Args[1]
if n != v_0_0_0.Args[0] {
break
}
v_0_0_0_1 := v_0_0_0.Args[1]
if v_0_0_0_1.Op != OpRsh32Ux64 {
break
}
if v_0_0_0_1.Type != t {
break
}
_ = v_0_0_0_1.Args[1]
v_0_0_0_1_0 := v_0_0_0_1.Args[0]
if v_0_0_0_1_0.Op != OpRsh32x64 {
break
}
if v_0_0_0_1_0.Type != t {
break
}
_ = v_0_0_0_1_0.Args[1]
if n != v_0_0_0_1_0.Args[0] {
break
}
v_0_0_0_1_0_1 := v_0_0_0_1_0.Args[1]
if v_0_0_0_1_0_1.Op != OpConst64 {
break
}
if v_0_0_0_1_0_1.Type != typ.UInt64 {
break
}
if v_0_0_0_1_0_1.AuxInt != 31 {
break
}
v_0_0_0_1_1 := v_0_0_0_1.Args[1]
if v_0_0_0_1_1.Op != OpConst64 {
break
}
if v_0_0_0_1_1.Type != typ.UInt64 {
break
}
kbar := v_0_0_0_1_1.AuxInt
v_0_0_1 := v_0_0.Args[1]
if v_0_0_1.Op != OpConst64 {
break
}
if v_0_0_1.Type != typ.UInt64 {
break
}
k := v_0_0_1.AuxInt
v_0_1 := v_0.Args[1]
if v_0_1.Op != OpConst64 {
break
}
if v_0_1.Type != typ.UInt64 {
break
}
if v_0_1.AuxInt != k {
break
}
if !(k > 0 && k < 31 && kbar == 32-k) {
break
}
v.reset(OpEq32)
v0 := b.NewValue0(v.Pos, OpAnd32, t)
v0.AddArg(n)
v1 := b.NewValue0(v.Pos, OpConst32, t)
v1.AuxInt = int64(1<<uint(k) - 1)
v0.AddArg(v1)
v.AddArg(v0)
v2 := b.NewValue0(v.Pos, OpConst32, t)
v2.AuxInt = 0
v.AddArg(v2)
return true
}
return false
}
func rewriteValuegeneric_OpEq32_10(v *Value) bool {
b := v.Block
typ := &b.Func.Config.Types
// match: (Eq32 (Lsh32x64 (Rsh32x64 (Add32 <t> (Rsh32Ux64 <t> (Rsh32x64 <t> n (Const64 <typ.UInt64> [31])) (Const64 <typ.UInt64> [kbar])) n) (Const64 <typ.UInt64> [k])) (Const64 <typ.UInt64> [k])) n)
// cond: k > 0 && k < 31 && kbar == 32 - k
// result: (Eq32 (And32 <t> n (Const32 <t> [int64(1<<uint(k)-1)])) (Const32 <t> [0]))
for {
n := v.Args[1]
v_0 := v.Args[0]
if v_0.Op != OpLsh32x64 {
break
}
_ = v_0.Args[1]
v_0_0 := v_0.Args[0]
if v_0_0.Op != OpRsh32x64 {
break
}
_ = v_0_0.Args[1]
v_0_0_0 := v_0_0.Args[0]
if v_0_0_0.Op != OpAdd32 {
break
}
t := v_0_0_0.Type
_ = v_0_0_0.Args[1]
v_0_0_0_0 := v_0_0_0.Args[0]
if v_0_0_0_0.Op != OpRsh32Ux64 {
break
}
if v_0_0_0_0.Type != t {
break
}
_ = v_0_0_0_0.Args[1]
v_0_0_0_0_0 := v_0_0_0_0.Args[0]
if v_0_0_0_0_0.Op != OpRsh32x64 {
break
}
if v_0_0_0_0_0.Type != t {
break
}
_ = v_0_0_0_0_0.Args[1]
if n != v_0_0_0_0_0.Args[0] {
break
}
v_0_0_0_0_0_1 := v_0_0_0_0_0.Args[1]
if v_0_0_0_0_0_1.Op != OpConst64 {
break
}
if v_0_0_0_0_0_1.Type != typ.UInt64 {
break
}
if v_0_0_0_0_0_1.AuxInt != 31 {
break
}
v_0_0_0_0_1 := v_0_0_0_0.Args[1]
if v_0_0_0_0_1.Op != OpConst64 {
break
}
if v_0_0_0_0_1.Type != typ.UInt64 {
break
}
kbar := v_0_0_0_0_1.AuxInt
if n != v_0_0_0.Args[1] {
break
}
v_0_0_1 := v_0_0.Args[1]
if v_0_0_1.Op != OpConst64 {
break
}
if v_0_0_1.Type != typ.UInt64 {
break
}
k := v_0_0_1.AuxInt
v_0_1 := v_0.Args[1]
if v_0_1.Op != OpConst64 {
break
}
if v_0_1.Type != typ.UInt64 {
break
}
if v_0_1.AuxInt != k {
break
}
if !(k > 0 && k < 31 && kbar == 32-k) {
break
}
v.reset(OpEq32)
v0 := b.NewValue0(v.Pos, OpAnd32, t)
v0.AddArg(n)
v1 := b.NewValue0(v.Pos, OpConst32, t)
v1.AuxInt = int64(1<<uint(k) - 1)
v0.AddArg(v1)
v.AddArg(v0)
v2 := b.NewValue0(v.Pos, OpConst32, t)
v2.AuxInt = 0
v.AddArg(v2)
return true
}
// match: (Eq32 s:(Sub32 x y) (Const32 [0]))
// cond: s.Uses == 1
// result: (Eq32 x y)
for {
......@@ -9280,6 +10048,7 @@ func rewriteValuegeneric_OpEq32F_0(v *Value) bool {
}
func rewriteValuegeneric_OpEq64_0(v *Value) bool {
b := v.Block
typ := &b.Func.Config.Types
// match: (Eq64 x x)
// cond:
// result: (ConstBool [1])
......@@ -9456,6 +10225,389 @@ func rewriteValuegeneric_OpEq64_0(v *Value) bool {
v.AuxInt = b2i(c == d)
return true
}
// match: (Eq64 n (Lsh64x64 (Rsh64x64 (Add64 <t> n (Rsh64Ux64 <t> (Rsh64x64 <t> n (Const64 <typ.UInt64> [63])) (Const64 <typ.UInt64> [kbar]))) (Const64 <typ.UInt64> [k])) (Const64 <typ.UInt64> [k])))
// cond: k > 0 && k < 63 && kbar == 64 - k
// result: (Eq64 (And64 <t> n (Const64 <t> [int64(1<<uint(k)-1)])) (Const64 <t> [0]))
for {
_ = v.Args[1]
n := v.Args[0]
v_1 := v.Args[1]
if v_1.Op != OpLsh64x64 {
break
}
_ = v_1.Args[1]
v_1_0 := v_1.Args[0]
if v_1_0.Op != OpRsh64x64 {
break
}
_ = v_1_0.Args[1]
v_1_0_0 := v_1_0.Args[0]
if v_1_0_0.Op != OpAdd64 {
break
}
t := v_1_0_0.Type
_ = v_1_0_0.Args[1]
if n != v_1_0_0.Args[0] {
break
}
v_1_0_0_1 := v_1_0_0.Args[1]
if v_1_0_0_1.Op != OpRsh64Ux64 {
break
}
if v_1_0_0_1.Type != t {
break
}
_ = v_1_0_0_1.Args[1]
v_1_0_0_1_0 := v_1_0_0_1.Args[0]
if v_1_0_0_1_0.Op != OpRsh64x64 {
break
}
if v_1_0_0_1_0.Type != t {
break
}
_ = v_1_0_0_1_0.Args[1]
if n != v_1_0_0_1_0.Args[0] {
break
}
v_1_0_0_1_0_1 := v_1_0_0_1_0.Args[1]
if v_1_0_0_1_0_1.Op != OpConst64 {
break
}
if v_1_0_0_1_0_1.Type != typ.UInt64 {
break
}
if v_1_0_0_1_0_1.AuxInt != 63 {
break
}
v_1_0_0_1_1 := v_1_0_0_1.Args[1]
if v_1_0_0_1_1.Op != OpConst64 {
break
}
if v_1_0_0_1_1.Type != typ.UInt64 {
break
}
kbar := v_1_0_0_1_1.AuxInt
v_1_0_1 := v_1_0.Args[1]
if v_1_0_1.Op != OpConst64 {
break
}
if v_1_0_1.Type != typ.UInt64 {
break
}
k := v_1_0_1.AuxInt
v_1_1 := v_1.Args[1]
if v_1_1.Op != OpConst64 {
break
}
if v_1_1.Type != typ.UInt64 {
break
}
if v_1_1.AuxInt != k {
break
}
if !(k > 0 && k < 63 && kbar == 64-k) {
break
}
v.reset(OpEq64)
v0 := b.NewValue0(v.Pos, OpAnd64, t)
v0.AddArg(n)
v1 := b.NewValue0(v.Pos, OpConst64, t)
v1.AuxInt = int64(1<<uint(k) - 1)
v0.AddArg(v1)
v.AddArg(v0)
v2 := b.NewValue0(v.Pos, OpConst64, t)
v2.AuxInt = 0
v.AddArg(v2)
return true
}
// match: (Eq64 n (Lsh64x64 (Rsh64x64 (Add64 <t> (Rsh64Ux64 <t> (Rsh64x64 <t> n (Const64 <typ.UInt64> [63])) (Const64 <typ.UInt64> [kbar])) n) (Const64 <typ.UInt64> [k])) (Const64 <typ.UInt64> [k])))
// cond: k > 0 && k < 63 && kbar == 64 - k
// result: (Eq64 (And64 <t> n (Const64 <t> [int64(1<<uint(k)-1)])) (Const64 <t> [0]))
for {
_ = v.Args[1]
n := v.Args[0]
v_1 := v.Args[1]
if v_1.Op != OpLsh64x64 {
break
}
_ = v_1.Args[1]
v_1_0 := v_1.Args[0]
if v_1_0.Op != OpRsh64x64 {
break
}
_ = v_1_0.Args[1]
v_1_0_0 := v_1_0.Args[0]
if v_1_0_0.Op != OpAdd64 {
break
}
t := v_1_0_0.Type
_ = v_1_0_0.Args[1]
v_1_0_0_0 := v_1_0_0.Args[0]
if v_1_0_0_0.Op != OpRsh64Ux64 {
break
}
if v_1_0_0_0.Type != t {
break
}
_ = v_1_0_0_0.Args[1]
v_1_0_0_0_0 := v_1_0_0_0.Args[0]
if v_1_0_0_0_0.Op != OpRsh64x64 {
break
}
if v_1_0_0_0_0.Type != t {
break
}
_ = v_1_0_0_0_0.Args[1]
if n != v_1_0_0_0_0.Args[0] {
break
}
v_1_0_0_0_0_1 := v_1_0_0_0_0.Args[1]
if v_1_0_0_0_0_1.Op != OpConst64 {
break
}
if v_1_0_0_0_0_1.Type != typ.UInt64 {
break
}
if v_1_0_0_0_0_1.AuxInt != 63 {
break
}
v_1_0_0_0_1 := v_1_0_0_0.Args[1]
if v_1_0_0_0_1.Op != OpConst64 {
break
}
if v_1_0_0_0_1.Type != typ.UInt64 {
break
}
kbar := v_1_0_0_0_1.AuxInt
if n != v_1_0_0.Args[1] {
break
}
v_1_0_1 := v_1_0.Args[1]
if v_1_0_1.Op != OpConst64 {
break
}
if v_1_0_1.Type != typ.UInt64 {
break
}
k := v_1_0_1.AuxInt
v_1_1 := v_1.Args[1]
if v_1_1.Op != OpConst64 {
break
}
if v_1_1.Type != typ.UInt64 {
break
}
if v_1_1.AuxInt != k {
break
}
if !(k > 0 && k < 63 && kbar == 64-k) {
break
}
v.reset(OpEq64)
v0 := b.NewValue0(v.Pos, OpAnd64, t)
v0.AddArg(n)
v1 := b.NewValue0(v.Pos, OpConst64, t)
v1.AuxInt = int64(1<<uint(k) - 1)
v0.AddArg(v1)
v.AddArg(v0)
v2 := b.NewValue0(v.Pos, OpConst64, t)
v2.AuxInt = 0
v.AddArg(v2)
return true
}
// match: (Eq64 (Lsh64x64 (Rsh64x64 (Add64 <t> n (Rsh64Ux64 <t> (Rsh64x64 <t> n (Const64 <typ.UInt64> [63])) (Const64 <typ.UInt64> [kbar]))) (Const64 <typ.UInt64> [k])) (Const64 <typ.UInt64> [k])) n)
// cond: k > 0 && k < 63 && kbar == 64 - k
// result: (Eq64 (And64 <t> n (Const64 <t> [int64(1<<uint(k)-1)])) (Const64 <t> [0]))
for {
n := v.Args[1]
v_0 := v.Args[0]
if v_0.Op != OpLsh64x64 {
break
}
_ = v_0.Args[1]
v_0_0 := v_0.Args[0]
if v_0_0.Op != OpRsh64x64 {
break
}
_ = v_0_0.Args[1]
v_0_0_0 := v_0_0.Args[0]
if v_0_0_0.Op != OpAdd64 {
break
}
t := v_0_0_0.Type
_ = v_0_0_0.Args[1]
if n != v_0_0_0.Args[0] {
break
}
v_0_0_0_1 := v_0_0_0.Args[1]
if v_0_0_0_1.Op != OpRsh64Ux64 {
break
}
if v_0_0_0_1.Type != t {
break
}
_ = v_0_0_0_1.Args[1]
v_0_0_0_1_0 := v_0_0_0_1.Args[0]
if v_0_0_0_1_0.Op != OpRsh64x64 {
break
}
if v_0_0_0_1_0.Type != t {
break
}
_ = v_0_0_0_1_0.Args[1]
if n != v_0_0_0_1_0.Args[0] {
break
}
v_0_0_0_1_0_1 := v_0_0_0_1_0.Args[1]
if v_0_0_0_1_0_1.Op != OpConst64 {
break
}
if v_0_0_0_1_0_1.Type != typ.UInt64 {
break
}
if v_0_0_0_1_0_1.AuxInt != 63 {
break
}
v_0_0_0_1_1 := v_0_0_0_1.Args[1]
if v_0_0_0_1_1.Op != OpConst64 {
break
}
if v_0_0_0_1_1.Type != typ.UInt64 {
break
}
kbar := v_0_0_0_1_1.AuxInt
v_0_0_1 := v_0_0.Args[1]
if v_0_0_1.Op != OpConst64 {
break
}
if v_0_0_1.Type != typ.UInt64 {
break
}
k := v_0_0_1.AuxInt
v_0_1 := v_0.Args[1]
if v_0_1.Op != OpConst64 {
break
}
if v_0_1.Type != typ.UInt64 {
break
}
if v_0_1.AuxInt != k {
break
}
if !(k > 0 && k < 63 && kbar == 64-k) {
break
}
v.reset(OpEq64)
v0 := b.NewValue0(v.Pos, OpAnd64, t)
v0.AddArg(n)
v1 := b.NewValue0(v.Pos, OpConst64, t)
v1.AuxInt = int64(1<<uint(k) - 1)
v0.AddArg(v1)
v.AddArg(v0)
v2 := b.NewValue0(v.Pos, OpConst64, t)
v2.AuxInt = 0
v.AddArg(v2)
return true
}
return false
}
func rewriteValuegeneric_OpEq64_10(v *Value) bool {
b := v.Block
typ := &b.Func.Config.Types
// match: (Eq64 (Lsh64x64 (Rsh64x64 (Add64 <t> (Rsh64Ux64 <t> (Rsh64x64 <t> n (Const64 <typ.UInt64> [63])) (Const64 <typ.UInt64> [kbar])) n) (Const64 <typ.UInt64> [k])) (Const64 <typ.UInt64> [k])) n)
// cond: k > 0 && k < 63 && kbar == 64 - k
// result: (Eq64 (And64 <t> n (Const64 <t> [int64(1<<uint(k)-1)])) (Const64 <t> [0]))
for {
n := v.Args[1]
v_0 := v.Args[0]
if v_0.Op != OpLsh64x64 {
break
}
_ = v_0.Args[1]
v_0_0 := v_0.Args[0]
if v_0_0.Op != OpRsh64x64 {
break
}
_ = v_0_0.Args[1]
v_0_0_0 := v_0_0.Args[0]
if v_0_0_0.Op != OpAdd64 {
break
}
t := v_0_0_0.Type
_ = v_0_0_0.Args[1]
v_0_0_0_0 := v_0_0_0.Args[0]
if v_0_0_0_0.Op != OpRsh64Ux64 {
break
}
if v_0_0_0_0.Type != t {
break
}
_ = v_0_0_0_0.Args[1]
v_0_0_0_0_0 := v_0_0_0_0.Args[0]
if v_0_0_0_0_0.Op != OpRsh64x64 {
break
}
if v_0_0_0_0_0.Type != t {
break
}
_ = v_0_0_0_0_0.Args[1]
if n != v_0_0_0_0_0.Args[0] {
break
}
v_0_0_0_0_0_1 := v_0_0_0_0_0.Args[1]
if v_0_0_0_0_0_1.Op != OpConst64 {
break
}
if v_0_0_0_0_0_1.Type != typ.UInt64 {
break
}
if v_0_0_0_0_0_1.AuxInt != 63 {
break
}
v_0_0_0_0_1 := v_0_0_0_0.Args[1]
if v_0_0_0_0_1.Op != OpConst64 {
break
}
if v_0_0_0_0_1.Type != typ.UInt64 {
break
}
kbar := v_0_0_0_0_1.AuxInt
if n != v_0_0_0.Args[1] {
break
}
v_0_0_1 := v_0_0.Args[1]
if v_0_0_1.Op != OpConst64 {
break
}
if v_0_0_1.Type != typ.UInt64 {
break
}
k := v_0_0_1.AuxInt
v_0_1 := v_0.Args[1]
if v_0_1.Op != OpConst64 {
break
}
if v_0_1.Type != typ.UInt64 {
break
}
if v_0_1.AuxInt != k {
break
}
if !(k > 0 && k < 63 && kbar == 64-k) {
break
}
v.reset(OpEq64)
v0 := b.NewValue0(v.Pos, OpAnd64, t)
v0.AddArg(n)
v1 := b.NewValue0(v.Pos, OpConst64, t)
v1.AuxInt = int64(1<<uint(k) - 1)
v0.AddArg(v1)
v.AddArg(v0)
v2 := b.NewValue0(v.Pos, OpConst64, t)
v2.AuxInt = 0
v.AddArg(v2)
return true
}
// match: (Eq64 s:(Sub64 x y) (Const64 [0]))
// cond: s.Uses == 1
// result: (Eq64 x y)
......@@ -9553,6 +10705,7 @@ func rewriteValuegeneric_OpEq64F_0(v *Value) bool {
}
func rewriteValuegeneric_OpEq8_0(v *Value) bool {
b := v.Block
typ := &b.Func.Config.Types
// match: (Eq8 x x)
// cond:
// result: (ConstBool [1])
......@@ -9729,6 +10882,389 @@ func rewriteValuegeneric_OpEq8_0(v *Value) bool {
v.AuxInt = b2i(c == d)
return true
}
// match: (Eq8 n (Lsh8x64 (Rsh8x64 (Add8 <t> n (Rsh8Ux64 <t> (Rsh8x64 <t> n (Const64 <typ.UInt64> [ 7])) (Const64 <typ.UInt64> [kbar]))) (Const64 <typ.UInt64> [k])) (Const64 <typ.UInt64> [k])))
// cond: k > 0 && k < 7 && kbar == 8 - k
// result: (Eq8 (And8 <t> n (Const8 <t> [int64(1<<uint(k)-1)])) (Const8 <t> [0]))
for {
_ = v.Args[1]
n := v.Args[0]
v_1 := v.Args[1]
if v_1.Op != OpLsh8x64 {
break
}
_ = v_1.Args[1]
v_1_0 := v_1.Args[0]
if v_1_0.Op != OpRsh8x64 {
break
}
_ = v_1_0.Args[1]
v_1_0_0 := v_1_0.Args[0]
if v_1_0_0.Op != OpAdd8 {
break
}
t := v_1_0_0.Type
_ = v_1_0_0.Args[1]
if n != v_1_0_0.Args[0] {
break
}
v_1_0_0_1 := v_1_0_0.Args[1]
if v_1_0_0_1.Op != OpRsh8Ux64 {
break
}
if v_1_0_0_1.Type != t {
break
}
_ = v_1_0_0_1.Args[1]
v_1_0_0_1_0 := v_1_0_0_1.Args[0]
if v_1_0_0_1_0.Op != OpRsh8x64 {
break
}
if v_1_0_0_1_0.Type != t {
break
}
_ = v_1_0_0_1_0.Args[1]
if n != v_1_0_0_1_0.Args[0] {
break
}
v_1_0_0_1_0_1 := v_1_0_0_1_0.Args[1]
if v_1_0_0_1_0_1.Op != OpConst64 {
break
}
if v_1_0_0_1_0_1.Type != typ.UInt64 {
break
}
if v_1_0_0_1_0_1.AuxInt != 7 {
break
}
v_1_0_0_1_1 := v_1_0_0_1.Args[1]
if v_1_0_0_1_1.Op != OpConst64 {
break
}
if v_1_0_0_1_1.Type != typ.UInt64 {
break
}
kbar := v_1_0_0_1_1.AuxInt
v_1_0_1 := v_1_0.Args[1]
if v_1_0_1.Op != OpConst64 {
break
}
if v_1_0_1.Type != typ.UInt64 {
break
}
k := v_1_0_1.AuxInt
v_1_1 := v_1.Args[1]
if v_1_1.Op != OpConst64 {
break
}
if v_1_1.Type != typ.UInt64 {
break
}
if v_1_1.AuxInt != k {
break
}
if !(k > 0 && k < 7 && kbar == 8-k) {
break
}
v.reset(OpEq8)
v0 := b.NewValue0(v.Pos, OpAnd8, t)
v0.AddArg(n)
v1 := b.NewValue0(v.Pos, OpConst8, t)
v1.AuxInt = int64(1<<uint(k) - 1)
v0.AddArg(v1)
v.AddArg(v0)
v2 := b.NewValue0(v.Pos, OpConst8, t)
v2.AuxInt = 0
v.AddArg(v2)
return true
}
// match: (Eq8 n (Lsh8x64 (Rsh8x64 (Add8 <t> (Rsh8Ux64 <t> (Rsh8x64 <t> n (Const64 <typ.UInt64> [ 7])) (Const64 <typ.UInt64> [kbar])) n) (Const64 <typ.UInt64> [k])) (Const64 <typ.UInt64> [k])))
// cond: k > 0 && k < 7 && kbar == 8 - k
// result: (Eq8 (And8 <t> n (Const8 <t> [int64(1<<uint(k)-1)])) (Const8 <t> [0]))
for {
_ = v.Args[1]
n := v.Args[0]
v_1 := v.Args[1]
if v_1.Op != OpLsh8x64 {
break
}
_ = v_1.Args[1]
v_1_0 := v_1.Args[0]
if v_1_0.Op != OpRsh8x64 {
break
}
_ = v_1_0.Args[1]
v_1_0_0 := v_1_0.Args[0]
if v_1_0_0.Op != OpAdd8 {
break
}
t := v_1_0_0.Type
_ = v_1_0_0.Args[1]
v_1_0_0_0 := v_1_0_0.Args[0]
if v_1_0_0_0.Op != OpRsh8Ux64 {
break
}
if v_1_0_0_0.Type != t {
break
}
_ = v_1_0_0_0.Args[1]
v_1_0_0_0_0 := v_1_0_0_0.Args[0]
if v_1_0_0_0_0.Op != OpRsh8x64 {
break
}
if v_1_0_0_0_0.Type != t {
break
}
_ = v_1_0_0_0_0.Args[1]
if n != v_1_0_0_0_0.Args[0] {
break
}
v_1_0_0_0_0_1 := v_1_0_0_0_0.Args[1]
if v_1_0_0_0_0_1.Op != OpConst64 {
break
}
if v_1_0_0_0_0_1.Type != typ.UInt64 {
break
}
if v_1_0_0_0_0_1.AuxInt != 7 {
break
}
v_1_0_0_0_1 := v_1_0_0_0.Args[1]
if v_1_0_0_0_1.Op != OpConst64 {
break
}
if v_1_0_0_0_1.Type != typ.UInt64 {
break
}
kbar := v_1_0_0_0_1.AuxInt
if n != v_1_0_0.Args[1] {
break
}
v_1_0_1 := v_1_0.Args[1]
if v_1_0_1.Op != OpConst64 {
break
}
if v_1_0_1.Type != typ.UInt64 {
break
}
k := v_1_0_1.AuxInt
v_1_1 := v_1.Args[1]
if v_1_1.Op != OpConst64 {
break
}
if v_1_1.Type != typ.UInt64 {
break
}
if v_1_1.AuxInt != k {
break
}
if !(k > 0 && k < 7 && kbar == 8-k) {
break
}
v.reset(OpEq8)
v0 := b.NewValue0(v.Pos, OpAnd8, t)
v0.AddArg(n)
v1 := b.NewValue0(v.Pos, OpConst8, t)
v1.AuxInt = int64(1<<uint(k) - 1)
v0.AddArg(v1)
v.AddArg(v0)
v2 := b.NewValue0(v.Pos, OpConst8, t)
v2.AuxInt = 0
v.AddArg(v2)
return true
}
// match: (Eq8 (Lsh8x64 (Rsh8x64 (Add8 <t> n (Rsh8Ux64 <t> (Rsh8x64 <t> n (Const64 <typ.UInt64> [ 7])) (Const64 <typ.UInt64> [kbar]))) (Const64 <typ.UInt64> [k])) (Const64 <typ.UInt64> [k])) n)
// cond: k > 0 && k < 7 && kbar == 8 - k
// result: (Eq8 (And8 <t> n (Const8 <t> [int64(1<<uint(k)-1)])) (Const8 <t> [0]))
for {
n := v.Args[1]
v_0 := v.Args[0]
if v_0.Op != OpLsh8x64 {
break
}
_ = v_0.Args[1]
v_0_0 := v_0.Args[0]
if v_0_0.Op != OpRsh8x64 {
break
}
_ = v_0_0.Args[1]
v_0_0_0 := v_0_0.Args[0]
if v_0_0_0.Op != OpAdd8 {
break
}
t := v_0_0_0.Type
_ = v_0_0_0.Args[1]
if n != v_0_0_0.Args[0] {
break
}
v_0_0_0_1 := v_0_0_0.Args[1]
if v_0_0_0_1.Op != OpRsh8Ux64 {
break
}
if v_0_0_0_1.Type != t {
break
}
_ = v_0_0_0_1.Args[1]
v_0_0_0_1_0 := v_0_0_0_1.Args[0]
if v_0_0_0_1_0.Op != OpRsh8x64 {
break
}
if v_0_0_0_1_0.Type != t {
break
}
_ = v_0_0_0_1_0.Args[1]
if n != v_0_0_0_1_0.Args[0] {
break
}
v_0_0_0_1_0_1 := v_0_0_0_1_0.Args[1]
if v_0_0_0_1_0_1.Op != OpConst64 {
break
}
if v_0_0_0_1_0_1.Type != typ.UInt64 {
break
}
if v_0_0_0_1_0_1.AuxInt != 7 {
break
}
v_0_0_0_1_1 := v_0_0_0_1.Args[1]
if v_0_0_0_1_1.Op != OpConst64 {
break
}
if v_0_0_0_1_1.Type != typ.UInt64 {
break
}
kbar := v_0_0_0_1_1.AuxInt
v_0_0_1 := v_0_0.Args[1]
if v_0_0_1.Op != OpConst64 {
break
}
if v_0_0_1.Type != typ.UInt64 {
break
}
k := v_0_0_1.AuxInt
v_0_1 := v_0.Args[1]
if v_0_1.Op != OpConst64 {
break
}
if v_0_1.Type != typ.UInt64 {
break
}
if v_0_1.AuxInt != k {
break
}
if !(k > 0 && k < 7 && kbar == 8-k) {
break
}
v.reset(OpEq8)
v0 := b.NewValue0(v.Pos, OpAnd8, t)
v0.AddArg(n)
v1 := b.NewValue0(v.Pos, OpConst8, t)
v1.AuxInt = int64(1<<uint(k) - 1)
v0.AddArg(v1)
v.AddArg(v0)
v2 := b.NewValue0(v.Pos, OpConst8, t)
v2.AuxInt = 0
v.AddArg(v2)
return true
}
return false
}
func rewriteValuegeneric_OpEq8_10(v *Value) bool {
b := v.Block
typ := &b.Func.Config.Types
// match: (Eq8 (Lsh8x64 (Rsh8x64 (Add8 <t> (Rsh8Ux64 <t> (Rsh8x64 <t> n (Const64 <typ.UInt64> [ 7])) (Const64 <typ.UInt64> [kbar])) n) (Const64 <typ.UInt64> [k])) (Const64 <typ.UInt64> [k])) n)
// cond: k > 0 && k < 7 && kbar == 8 - k
// result: (Eq8 (And8 <t> n (Const8 <t> [int64(1<<uint(k)-1)])) (Const8 <t> [0]))
for {
n := v.Args[1]
v_0 := v.Args[0]
if v_0.Op != OpLsh8x64 {
break
}
_ = v_0.Args[1]
v_0_0 := v_0.Args[0]
if v_0_0.Op != OpRsh8x64 {
break
}
_ = v_0_0.Args[1]
v_0_0_0 := v_0_0.Args[0]
if v_0_0_0.Op != OpAdd8 {
break
}
t := v_0_0_0.Type
_ = v_0_0_0.Args[1]
v_0_0_0_0 := v_0_0_0.Args[0]
if v_0_0_0_0.Op != OpRsh8Ux64 {
break
}
if v_0_0_0_0.Type != t {
break
}
_ = v_0_0_0_0.Args[1]
v_0_0_0_0_0 := v_0_0_0_0.Args[0]
if v_0_0_0_0_0.Op != OpRsh8x64 {
break
}
if v_0_0_0_0_0.Type != t {
break
}
_ = v_0_0_0_0_0.Args[1]
if n != v_0_0_0_0_0.Args[0] {
break
}
v_0_0_0_0_0_1 := v_0_0_0_0_0.Args[1]
if v_0_0_0_0_0_1.Op != OpConst64 {
break
}
if v_0_0_0_0_0_1.Type != typ.UInt64 {
break
}
if v_0_0_0_0_0_1.AuxInt != 7 {
break
}
v_0_0_0_0_1 := v_0_0_0_0.Args[1]
if v_0_0_0_0_1.Op != OpConst64 {
break
}
if v_0_0_0_0_1.Type != typ.UInt64 {
break
}
kbar := v_0_0_0_0_1.AuxInt
if n != v_0_0_0.Args[1] {
break
}
v_0_0_1 := v_0_0.Args[1]
if v_0_0_1.Op != OpConst64 {
break
}
if v_0_0_1.Type != typ.UInt64 {
break
}
k := v_0_0_1.AuxInt
v_0_1 := v_0.Args[1]
if v_0_1.Op != OpConst64 {
break
}
if v_0_1.Type != typ.UInt64 {
break
}
if v_0_1.AuxInt != k {
break
}
if !(k > 0 && k < 7 && kbar == 8-k) {
break
}
v.reset(OpEq8)
v0 := b.NewValue0(v.Pos, OpAnd8, t)
v0.AddArg(n)
v1 := b.NewValue0(v.Pos, OpConst8, t)
v1.AuxInt = int64(1<<uint(k) - 1)
v0.AddArg(v1)
v.AddArg(v0)
v2 := b.NewValue0(v.Pos, OpConst8, t)
v2.AuxInt = 0
v.AddArg(v2)
return true
}
// match: (Eq8 s:(Sub8 x y) (Const8 [0]))
// cond: s.Uses == 1
// result: (Eq8 x y)
......
......@@ -8,6 +8,8 @@ import (
"testing"
)
var boolres bool
var i64res int64
func BenchmarkDivconstI64(b *testing.B) {
......@@ -16,6 +18,12 @@ func BenchmarkDivconstI64(b *testing.B) {
}
}
func BenchmarkDivisiblePow2constI64(b *testing.B) {
for i := 0; i < b.N; i++ {
boolres = int64(i)%16 == 0
}
}
var u64res uint64
func BenchmarkDivconstU64(b *testing.B) {
......@@ -32,6 +40,12 @@ func BenchmarkDivconstI32(b *testing.B) {
}
}
func BenchmarkDivisiblePow2constI32(b *testing.B) {
for i := 0; i < b.N; i++ {
boolres = int32(i)%16 == 0
}
}
var u32res uint32
func BenchmarkDivconstU32(b *testing.B) {
......@@ -48,6 +62,12 @@ func BenchmarkDivconstI16(b *testing.B) {
}
}
func BenchmarkDivisiblePow2constI16(b *testing.B) {
for i := 0; i < b.N; i++ {
boolres = int16(i)%16 == 0
}
}
var u16res uint16
func BenchmarkDivconstU16(b *testing.B) {
......@@ -64,6 +84,12 @@ func BenchmarkDivconstI8(b *testing.B) {
}
}
func BenchmarkDivisiblePow2constI8(b *testing.B) {
for i := 0; i < b.N; i++ {
boolres = int8(i)%16 == 0
}
}
var u8res uint8
func BenchmarkDivconstU8(b *testing.B) {
......
......@@ -176,15 +176,28 @@ func Pow2Mods(n1 uint, n2 int) (uint, int) {
// ppc64le:"ANDCC\t[$]31"
a := n1 % 32 // unsigned
// 386:-"IDIVL"
// amd64:-"IDIVQ"
// arm:-".*udiv"
// arm64:-"REM"
// 386:"SHRL",-"IDIVL"
// amd64:"SHRQ",-"IDIVQ"
// arm:"SRA",-".*udiv"
// arm64:"ASR",-"REM"
// ppc64:"SRAD"
// ppc64le:"SRAD"
b := n2 % 64 // signed
return a, b
}
// Check that signed divisibility checks get converted to AND on low bits
func Pow2DivisibleSigned(n int) bool {
// 386:"TESTL\t[$]63",-"DIVL",-"SHRL"
// amd64:"TESTQ\t[$]63",-"DIVQ",-"SHRQ"
// arm:"AND\t[$]63",-".*udiv",-"SRA"
// arm64:"AND\t[$]63",-"UDIV",-"ASR"
// ppc64:"ANDCC\t[$]63",-"SRAD"
// ppc64le:"ANDCC\t[$]63",-"SRAD"
return n%64 == 0 // signed
}
// Check that constant modulo divs get turned into MULs
func ConstMods(n1 uint, n2 int) (uint, int) {
// amd64:"MOVQ\t[$]-1085102592571150095","MULQ",-"DIVQ"
......
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