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

Commit 44343c777c (CL 173557) added rules for handling
divisibility checks for powers of 2 for signed integers, x%c ==0.
This change adds the complementary indivisibility rules, x%c != 0.

Fixes #34166

Change-Id: I87379e30af7aff633371acca82db2397da9b2c07
Reviewed-on: https://go-review.googlesource.com/c/go/+/194219
Run-TryBot: Brian Kessler <brian.m.kessler@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
Brian Kessler 2019-09-08 21:50:07 -06:00 committed by Martin Möhrmann
parent 14849f0fa5
commit 6b1d5471b9
7 changed files with 1174 additions and 76 deletions

View File

@ -1697,37 +1697,37 @@
// 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
((Eq8|Neq8) 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]))
-> ((Eq8|Neq8) (And8 <t> n (Const8 <t> [int64(1<<uint(k)-1)])) (Const8 <t> [0]))
(Eq16 n (Lsh16x64
((Eq16|Neq16) 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]))
-> ((Eq16|Neq16) (And16 <t> n (Const16 <t> [int64(1<<uint(k)-1)])) (Const16 <t> [0]))
(Eq32 n (Lsh32x64
((Eq32|Neq32) 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]))
-> ((Eq32|Neq32) (And32 <t> n (Const32 <t> [int64(1<<uint(k)-1)])) (Const32 <t> [0]))
(Eq64 n (Lsh64x64
((Eq64|Neq64) 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]))
-> ((Eq64|Neq64) (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)

View File

@ -768,10 +768,10 @@ func rewriteValueAMD64(v *Value) bool {
return rewriteValueAMD64_OpEqB_0(v)
case OpEqPtr:
return rewriteValueAMD64_OpEqPtr_0(v)
case OpFloor:
return rewriteValueAMD64_OpFloor_0(v)
case OpFMA:
return rewriteValueAMD64_OpFMA_0(v)
case OpFloor:
return rewriteValueAMD64_OpFloor_0(v)
case OpGeq16:
return rewriteValueAMD64_OpGeq16_0(v)
case OpGeq16U:
@ -52211,17 +52211,6 @@ func rewriteValueAMD64_OpEqPtr_0(v *Value) bool {
return true
}
}
func rewriteValueAMD64_OpFloor_0(v *Value) bool {
// match: (Floor x)
// result: (ROUNDSD [1] x)
for {
x := v.Args[0]
v.reset(OpAMD64ROUNDSD)
v.AuxInt = 1
v.AddArg(x)
return true
}
}
func rewriteValueAMD64_OpFMA_0(v *Value) bool {
// match: (FMA x y z)
// result: (VFMADD231SD z x y)
@ -52236,6 +52225,17 @@ func rewriteValueAMD64_OpFMA_0(v *Value) bool {
return true
}
}
func rewriteValueAMD64_OpFloor_0(v *Value) bool {
// match: (Floor x)
// result: (ROUNDSD [1] x)
for {
x := v.Args[0]
v.reset(OpAMD64ROUNDSD)
v.AuxInt = 1
v.AddArg(x)
return true
}
}
func rewriteValueAMD64_OpGeq16_0(v *Value) bool {
b := v.Block
// match: (Geq16 x y)

View File

@ -571,10 +571,10 @@ func rewriteValueARM64(v *Value) bool {
return rewriteValueARM64_OpEqB_0(v)
case OpEqPtr:
return rewriteValueARM64_OpEqPtr_0(v)
case OpFloor:
return rewriteValueARM64_OpFloor_0(v)
case OpFMA:
return rewriteValueARM64_OpFMA_0(v)
case OpFloor:
return rewriteValueARM64_OpFloor_0(v)
case OpGeq16:
return rewriteValueARM64_OpGeq16_0(v)
case OpGeq16U:
@ -28573,16 +28573,6 @@ func rewriteValueARM64_OpEqPtr_0(v *Value) bool {
return true
}
}
func rewriteValueARM64_OpFloor_0(v *Value) bool {
// match: (Floor x)
// result: (FRINTMD x)
for {
x := v.Args[0]
v.reset(OpARM64FRINTMD)
v.AddArg(x)
return true
}
}
func rewriteValueARM64_OpFMA_0(v *Value) bool {
// match: (FMA x y z)
// result: (FMADDD z x y)
@ -28597,6 +28587,16 @@ func rewriteValueARM64_OpFMA_0(v *Value) bool {
return true
}
}
func rewriteValueARM64_OpFloor_0(v *Value) bool {
// match: (Floor x)
// result: (FRINTMD x)
for {
x := v.Args[0]
v.reset(OpARM64FRINTMD)
v.AddArg(x)
return true
}
}
func rewriteValueARM64_OpGeq16_0(v *Value) bool {
b := v.Block
typ := &b.Func.Config.Types

View File

@ -181,10 +181,10 @@ func rewriteValuePPC64(v *Value) bool {
return rewriteValuePPC64_OpEqB_0(v)
case OpEqPtr:
return rewriteValuePPC64_OpEqPtr_0(v)
case OpFloor:
return rewriteValuePPC64_OpFloor_0(v)
case OpFMA:
return rewriteValuePPC64_OpFMA_0(v)
case OpFloor:
return rewriteValuePPC64_OpFloor_0(v)
case OpGeq16:
return rewriteValuePPC64_OpGeq16_0(v)
case OpGeq16U:
@ -1997,16 +1997,6 @@ func rewriteValuePPC64_OpEqPtr_0(v *Value) bool {
return true
}
}
func rewriteValuePPC64_OpFloor_0(v *Value) bool {
// match: (Floor x)
// result: (FFLOOR x)
for {
x := v.Args[0]
v.reset(OpPPC64FFLOOR)
v.AddArg(x)
return true
}
}
func rewriteValuePPC64_OpFMA_0(v *Value) bool {
// match: (FMA x y z)
// result: (FMADD x y z)
@ -2021,6 +2011,16 @@ func rewriteValuePPC64_OpFMA_0(v *Value) bool {
return true
}
}
func rewriteValuePPC64_OpFloor_0(v *Value) bool {
// match: (Floor x)
// result: (FFLOOR x)
for {
x := v.Args[0]
v.reset(OpPPC64FFLOOR)
v.AddArg(x)
return true
}
}
func rewriteValuePPC64_OpGeq16_0(v *Value) bool {
b := v.Block
typ := &b.Func.Config.Types

View File

@ -166,10 +166,10 @@ func rewriteValueS390X(v *Value) bool {
return rewriteValueS390X_OpEqB_0(v)
case OpEqPtr:
return rewriteValueS390X_OpEqPtr_0(v)
case OpFloor:
return rewriteValueS390X_OpFloor_0(v)
case OpFMA:
return rewriteValueS390X_OpFMA_0(v)
case OpFloor:
return rewriteValueS390X_OpFloor_0(v)
case OpGeq16:
return rewriteValueS390X_OpGeq16_0(v)
case OpGeq16U:
@ -1928,17 +1928,6 @@ func rewriteValueS390X_OpEqPtr_0(v *Value) bool {
return true
}
}
func rewriteValueS390X_OpFloor_0(v *Value) bool {
// match: (Floor x)
// result: (FIDBR [7] x)
for {
x := v.Args[0]
v.reset(OpS390XFIDBR)
v.AuxInt = 7
v.AddArg(x)
return true
}
}
func rewriteValueS390X_OpFMA_0(v *Value) bool {
// match: (FMA x y z)
// result: (FMADD z x y)
@ -1953,6 +1942,17 @@ func rewriteValueS390X_OpFMA_0(v *Value) bool {
return true
}
}
func rewriteValueS390X_OpFloor_0(v *Value) bool {
// match: (Floor x)
// result: (FIDBR [7] x)
for {
x := v.Args[0]
v.reset(OpS390XFIDBR)
v.AuxInt = 7
v.AddArg(x)
return true
}
}
func rewriteValueS390X_OpGeq16_0(v *Value) bool {
b := v.Block
typ := &b.Func.Config.Types

File diff suppressed because it is too large Load Diff

View File

@ -188,14 +188,24 @@ func Pow2Mods(n1 uint, n2 int) (uint, int) {
}
// Check that signed divisibility checks get converted to AND on low bits
func Pow2DivisibleSigned(n int) bool {
func Pow2DivisibleSigned(n1, n2 int) (bool, 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
a := n1%64 == 0 // signed divisible
// 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"
b := n2%64 != 0 // signed indivisible
return a, b
}
// Check that constant modulo divs get turned into MULs