1
0
mirror of https://github.com/golang/go synced 2024-11-18 11:44:45 -07:00

cmd/compile: convert constant divide strength reduction rules to typed aux

Passes toolstash-check.

Change-Id: Ia5d11c099b8c6c0ed670960b2af808200e3b1ca1
Reviewed-on: https://go-review.googlesource.com/c/go/+/230739
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
Keith Randall 2020-04-28 19:28:43 -07:00
parent 56933fb838
commit 3d34c77829
3 changed files with 608 additions and 572 deletions

View File

@ -946,118 +946,118 @@
// Unsigned divide, not a power of 2. Strength reduce to a multiply.
// For 8-bit divides, we just do a direct 9-bit by 8-bit multiply.
(Div8u x (Const8 [c])) && umagicOK(8, c) ->
(Div8u x (Const8 [c])) && umagicOK8(c) =>
(Trunc32to8
(Rsh32Ux64 <typ.UInt32>
(Mul32 <typ.UInt32>
(Const32 <typ.UInt32> [int64(1<<8+umagic(8,c).m)])
(Const32 <typ.UInt32> [int32(1<<8+umagic8(c).m)])
(ZeroExt8to32 x))
(Const64 <typ.UInt64> [8+umagic(8,c).s])))
(Const64 <typ.UInt64> [8+umagic8(c).s])))
// For 16-bit divides on 64-bit machines, we do a direct 17-bit by 16-bit multiply.
(Div16u x (Const16 [c])) && umagicOK(16, c) && config.RegSize == 8 ->
(Div16u x (Const16 [c])) && umagicOK16(c) && config.RegSize == 8 =>
(Trunc64to16
(Rsh64Ux64 <typ.UInt64>
(Mul64 <typ.UInt64>
(Const64 <typ.UInt64> [int64(1<<16+umagic(16,c).m)])
(Const64 <typ.UInt64> [int64(1<<16+umagic16(c).m)])
(ZeroExt16to64 x))
(Const64 <typ.UInt64> [16+umagic(16,c).s])))
(Const64 <typ.UInt64> [16+umagic16(c).s])))
// For 16-bit divides on 32-bit machines
(Div16u x (Const16 [c])) && umagicOK(16, c) && config.RegSize == 4 && umagic(16,c).m&1 == 0 ->
(Div16u x (Const16 [c])) && umagicOK16(c) && config.RegSize == 4 && umagic16(c).m&1 == 0 =>
(Trunc32to16
(Rsh32Ux64 <typ.UInt32>
(Mul32 <typ.UInt32>
(Const32 <typ.UInt32> [int64(1<<15+umagic(16,c).m/2)])
(Const32 <typ.UInt32> [int32(1<<15+umagic16(c).m/2)])
(ZeroExt16to32 x))
(Const64 <typ.UInt64> [16+umagic(16,c).s-1])))
(Div16u x (Const16 [c])) && umagicOK(16, c) && config.RegSize == 4 && c&1 == 0 ->
(Const64 <typ.UInt64> [16+umagic16(c).s-1])))
(Div16u x (Const16 [c])) && umagicOK16(c) && config.RegSize == 4 && c&1 == 0 =>
(Trunc32to16
(Rsh32Ux64 <typ.UInt32>
(Mul32 <typ.UInt32>
(Const32 <typ.UInt32> [int64(1<<15+(umagic(16,c).m+1)/2)])
(Const32 <typ.UInt32> [int32(1<<15+(umagic16(c).m+1)/2)])
(Rsh32Ux64 <typ.UInt32> (ZeroExt16to32 x) (Const64 <typ.UInt64> [1])))
(Const64 <typ.UInt64> [16+umagic(16,c).s-2])))
(Div16u x (Const16 [c])) && umagicOK(16, c) && config.RegSize == 4 && config.useAvg ->
(Const64 <typ.UInt64> [16+umagic16(c).s-2])))
(Div16u x (Const16 [c])) && umagicOK16(c) && config.RegSize == 4 && config.useAvg =>
(Trunc32to16
(Rsh32Ux64 <typ.UInt32>
(Avg32u
(Lsh32x64 <typ.UInt32> (ZeroExt16to32 x) (Const64 <typ.UInt64> [16]))
(Mul32 <typ.UInt32>
(Const32 <typ.UInt32> [int64(umagic(16,c).m)])
(Const32 <typ.UInt32> [int32(umagic16(c).m)])
(ZeroExt16to32 x)))
(Const64 <typ.UInt64> [16+umagic(16,c).s-1])))
(Const64 <typ.UInt64> [16+umagic16(c).s-1])))
// For 32-bit divides on 32-bit machines
(Div32u x (Const32 [c])) && umagicOK(32, c) && config.RegSize == 4 && umagic(32,c).m&1 == 0 && config.useHmul ->
(Div32u x (Const32 [c])) && umagicOK32(c) && config.RegSize == 4 && umagic32(c).m&1 == 0 && config.useHmul =>
(Rsh32Ux64 <typ.UInt32>
(Hmul32u <typ.UInt32>
(Const32 <typ.UInt32> [int64(int32(1<<31+umagic(32,c).m/2))])
(Const32 <typ.UInt32> [int32(1<<31+umagic32(c).m/2)])
x)
(Const64 <typ.UInt64> [umagic(32,c).s-1]))
(Div32u x (Const32 [c])) && umagicOK(32, c) && config.RegSize == 4 && c&1 == 0 && config.useHmul ->
(Const64 <typ.UInt64> [umagic32(c).s-1]))
(Div32u x (Const32 [c])) && umagicOK32(c) && config.RegSize == 4 && c&1 == 0 && config.useHmul =>
(Rsh32Ux64 <typ.UInt32>
(Hmul32u <typ.UInt32>
(Const32 <typ.UInt32> [int64(int32(1<<31+(umagic(32,c).m+1)/2))])
(Const32 <typ.UInt32> [int32(1<<31+(umagic32(c).m+1)/2)])
(Rsh32Ux64 <typ.UInt32> x (Const64 <typ.UInt64> [1])))
(Const64 <typ.UInt64> [umagic(32,c).s-2]))
(Div32u x (Const32 [c])) && umagicOK(32, c) && config.RegSize == 4 && config.useAvg && config.useHmul ->
(Const64 <typ.UInt64> [umagic32(c).s-2]))
(Div32u x (Const32 [c])) && umagicOK32(c) && config.RegSize == 4 && config.useAvg && config.useHmul =>
(Rsh32Ux64 <typ.UInt32>
(Avg32u
x
(Hmul32u <typ.UInt32>
(Const32 <typ.UInt32> [int64(int32(umagic(32,c).m))])
(Const32 <typ.UInt32> [int32(umagic32(c).m)])
x))
(Const64 <typ.UInt64> [umagic(32,c).s-1]))
(Const64 <typ.UInt64> [umagic32(c).s-1]))
// For 32-bit divides on 64-bit machines
// We'll use a regular (non-hi) multiply for this case.
(Div32u x (Const32 [c])) && umagicOK(32, c) && config.RegSize == 8 && umagic(32,c).m&1 == 0 ->
(Div32u x (Const32 [c])) && umagicOK32(c) && config.RegSize == 8 && umagic32(c).m&1 == 0 =>
(Trunc64to32
(Rsh64Ux64 <typ.UInt64>
(Mul64 <typ.UInt64>
(Const64 <typ.UInt64> [int64(1<<31+umagic(32,c).m/2)])
(Const64 <typ.UInt64> [int64(1<<31+umagic32(c).m/2)])
(ZeroExt32to64 x))
(Const64 <typ.UInt64> [32+umagic(32,c).s-1])))
(Div32u x (Const32 [c])) && umagicOK(32, c) && config.RegSize == 8 && c&1 == 0 ->
(Const64 <typ.UInt64> [32+umagic32(c).s-1])))
(Div32u x (Const32 [c])) && umagicOK32(c) && config.RegSize == 8 && c&1 == 0 =>
(Trunc64to32
(Rsh64Ux64 <typ.UInt64>
(Mul64 <typ.UInt64>
(Const64 <typ.UInt64> [int64(1<<31+(umagic(32,c).m+1)/2)])
(Const64 <typ.UInt64> [int64(1<<31+(umagic32(c).m+1)/2)])
(Rsh64Ux64 <typ.UInt64> (ZeroExt32to64 x) (Const64 <typ.UInt64> [1])))
(Const64 <typ.UInt64> [32+umagic(32,c).s-2])))
(Div32u x (Const32 [c])) && umagicOK(32, c) && config.RegSize == 8 && config.useAvg ->
(Const64 <typ.UInt64> [32+umagic32(c).s-2])))
(Div32u x (Const32 [c])) && umagicOK32(c) && config.RegSize == 8 && config.useAvg =>
(Trunc64to32
(Rsh64Ux64 <typ.UInt64>
(Avg64u
(Lsh64x64 <typ.UInt64> (ZeroExt32to64 x) (Const64 <typ.UInt64> [32]))
(Mul64 <typ.UInt64>
(Const64 <typ.UInt32> [int64(umagic(32,c).m)])
(Const64 <typ.UInt32> [int64(umagic32(c).m)])
(ZeroExt32to64 x)))
(Const64 <typ.UInt64> [32+umagic(32,c).s-1])))
(Const64 <typ.UInt64> [32+umagic32(c).s-1])))
// For 64-bit divides on 64-bit machines
// (64-bit divides on 32-bit machines are lowered to a runtime call by the walk pass.)
(Div64u x (Const64 [c])) && umagicOK(64, c) && config.RegSize == 8 && umagic(64,c).m&1 == 0 && config.useHmul ->
(Div64u x (Const64 [c])) && umagicOK64(c) && config.RegSize == 8 && umagic64(c).m&1 == 0 && config.useHmul =>
(Rsh64Ux64 <typ.UInt64>
(Hmul64u <typ.UInt64>
(Const64 <typ.UInt64> [int64(1<<63+umagic(64,c).m/2)])
(Const64 <typ.UInt64> [int64(1<<63+umagic64(c).m/2)])
x)
(Const64 <typ.UInt64> [umagic(64,c).s-1]))
(Div64u x (Const64 [c])) && umagicOK(64, c) && config.RegSize == 8 && c&1 == 0 && config.useHmul ->
(Const64 <typ.UInt64> [umagic64(c).s-1]))
(Div64u x (Const64 [c])) && umagicOK64(c) && config.RegSize == 8 && c&1 == 0 && config.useHmul =>
(Rsh64Ux64 <typ.UInt64>
(Hmul64u <typ.UInt64>
(Const64 <typ.UInt64> [int64(1<<63+(umagic(64,c).m+1)/2)])
(Const64 <typ.UInt64> [int64(1<<63+(umagic64(c).m+1)/2)])
(Rsh64Ux64 <typ.UInt64> x (Const64 <typ.UInt64> [1])))
(Const64 <typ.UInt64> [umagic(64,c).s-2]))
(Div64u x (Const64 [c])) && umagicOK(64, c) && config.RegSize == 8 && config.useAvg && config.useHmul ->
(Const64 <typ.UInt64> [umagic64(c).s-2]))
(Div64u x (Const64 [c])) && umagicOK64(c) && config.RegSize == 8 && config.useAvg && config.useHmul =>
(Rsh64Ux64 <typ.UInt64>
(Avg64u
x
(Hmul64u <typ.UInt64>
(Const64 <typ.UInt64> [int64(umagic(64,c).m)])
(Const64 <typ.UInt64> [int64(umagic64(c).m)])
x))
(Const64 <typ.UInt64> [umagic(64,c).s-1]))
(Const64 <typ.UInt64> [umagic64(c).s-1]))
// Signed divide by a negative constant. Rewrite to divide by a positive constant.
(Div8 <t> n (Const8 [c])) && c < 0 && c != -1<<7 => (Neg8 (Div8 <t> n (Const8 <t> [-c])))
@ -1095,77 +1095,77 @@
(Const64 <typ.UInt64> [int64(log64(c))]))
// Signed divide, not a power of 2. Strength reduce to a multiply.
(Div8 <t> x (Const8 [c])) && smagicOK(8,c) ->
(Div8 <t> x (Const8 [c])) && smagicOK8(c) =>
(Sub8 <t>
(Rsh32x64 <t>
(Mul32 <typ.UInt32>
(Const32 <typ.UInt32> [int64(smagic(8,c).m)])
(Const32 <typ.UInt32> [int32(smagic8(c).m)])
(SignExt8to32 x))
(Const64 <typ.UInt64> [8+smagic(8,c).s]))
(Const64 <typ.UInt64> [8+smagic8(c).s]))
(Rsh32x64 <t>
(SignExt8to32 x)
(Const64 <typ.UInt64> [31])))
(Div16 <t> x (Const16 [c])) && smagicOK(16,c) ->
(Div16 <t> x (Const16 [c])) && smagicOK16(c) =>
(Sub16 <t>
(Rsh32x64 <t>
(Mul32 <typ.UInt32>
(Const32 <typ.UInt32> [int64(smagic(16,c).m)])
(Const32 <typ.UInt32> [int32(smagic16(c).m)])
(SignExt16to32 x))
(Const64 <typ.UInt64> [16+smagic(16,c).s]))
(Const64 <typ.UInt64> [16+smagic16(c).s]))
(Rsh32x64 <t>
(SignExt16to32 x)
(Const64 <typ.UInt64> [31])))
(Div32 <t> x (Const32 [c])) && smagicOK(32,c) && config.RegSize == 8 ->
(Div32 <t> x (Const32 [c])) && smagicOK32(c) && config.RegSize == 8 =>
(Sub32 <t>
(Rsh64x64 <t>
(Mul64 <typ.UInt64>
(Const64 <typ.UInt64> [int64(smagic(32,c).m)])
(Const64 <typ.UInt64> [int64(smagic32(c).m)])
(SignExt32to64 x))
(Const64 <typ.UInt64> [32+smagic(32,c).s]))
(Const64 <typ.UInt64> [32+smagic32(c).s]))
(Rsh64x64 <t>
(SignExt32to64 x)
(Const64 <typ.UInt64> [63])))
(Div32 <t> x (Const32 [c])) && smagicOK(32,c) && config.RegSize == 4 && smagic(32,c).m&1 == 0 && config.useHmul ->
(Div32 <t> x (Const32 [c])) && smagicOK32(c) && config.RegSize == 4 && smagic32(c).m&1 == 0 && config.useHmul =>
(Sub32 <t>
(Rsh32x64 <t>
(Hmul32 <t>
(Const32 <typ.UInt32> [int64(int32(smagic(32,c).m/2))])
(Const32 <typ.UInt32> [int32(smagic32(c).m/2)])
x)
(Const64 <typ.UInt64> [smagic(32,c).s-1]))
(Const64 <typ.UInt64> [smagic32(c).s-1]))
(Rsh32x64 <t>
x
(Const64 <typ.UInt64> [31])))
(Div32 <t> x (Const32 [c])) && smagicOK(32,c) && config.RegSize == 4 && smagic(32,c).m&1 != 0 && config.useHmul ->
(Div32 <t> x (Const32 [c])) && smagicOK32(c) && config.RegSize == 4 && smagic32(c).m&1 != 0 && config.useHmul =>
(Sub32 <t>
(Rsh32x64 <t>
(Add32 <t>
(Hmul32 <t>
(Const32 <typ.UInt32> [int64(int32(smagic(32,c).m))])
(Const32 <typ.UInt32> [int32(smagic32(c).m)])
x)
x)
(Const64 <typ.UInt64> [smagic(32,c).s]))
(Const64 <typ.UInt64> [smagic32(c).s]))
(Rsh32x64 <t>
x
(Const64 <typ.UInt64> [31])))
(Div64 <t> x (Const64 [c])) && smagicOK(64,c) && smagic(64,c).m&1 == 0 && config.useHmul ->
(Div64 <t> x (Const64 [c])) && smagicOK64(c) && smagic64(c).m&1 == 0 && config.useHmul =>
(Sub64 <t>
(Rsh64x64 <t>
(Hmul64 <t>
(Const64 <typ.UInt64> [int64(smagic(64,c).m/2)])
(Const64 <typ.UInt64> [int64(smagic64(c).m/2)])
x)
(Const64 <typ.UInt64> [smagic(64,c).s-1]))
(Const64 <typ.UInt64> [smagic64(c).s-1]))
(Rsh64x64 <t>
x
(Const64 <typ.UInt64> [63])))
(Div64 <t> x (Const64 [c])) && smagicOK(64,c) && smagic(64,c).m&1 != 0 && config.useHmul ->
(Div64 <t> x (Const64 [c])) && smagicOK64(c) && smagic64(c).m&1 != 0 && config.useHmul =>
(Sub64 <t>
(Rsh64x64 <t>
(Add64 <t>
(Hmul64 <t>
(Const64 <typ.UInt64> [int64(smagic(64,c).m)])
(Const64 <typ.UInt64> [int64(smagic64(c).m)])
x)
x)
(Const64 <typ.UInt64> [smagic(64,c).s]))
(Const64 <typ.UInt64> [smagic64(c).s]))
(Rsh64x64 <t>
x
(Const64 <typ.UInt64> [63])))
@ -1211,14 +1211,14 @@
=> (Sub64 x (Mul64 <t> (Div64u <t> x (Const64 <t> [c])) (Const64 <t> [c])))
// For architectures without rotates on less than 32-bits, promote these checks to 32-bit.
(Eq8 (Mod8u x (Const8 [c])) (Const8 [0])) && x.Op != OpConst8 && udivisibleOK(8,c) && !hasSmallRotate(config) ->
(Eq32 (Mod32u <typ.UInt32> (ZeroExt8to32 <typ.UInt32> x) (Const32 <typ.UInt32> [c&0xff])) (Const32 <typ.UInt32> [0]))
(Eq16 (Mod16u x (Const16 [c])) (Const16 [0])) && x.Op != OpConst16 && udivisibleOK(16,c) && !hasSmallRotate(config) ->
(Eq32 (Mod32u <typ.UInt32> (ZeroExt16to32 <typ.UInt32> x) (Const32 <typ.UInt32> [c&0xffff])) (Const32 <typ.UInt32> [0]))
(Eq8 (Mod8 x (Const8 [c])) (Const8 [0])) && x.Op != OpConst8 && sdivisibleOK(8,c) && !hasSmallRotate(config) ->
(Eq32 (Mod32 <typ.Int32> (SignExt8to32 <typ.Int32> x) (Const32 <typ.Int32> [c])) (Const32 <typ.Int32> [0]))
(Eq16 (Mod16 x (Const16 [c])) (Const16 [0])) && x.Op != OpConst16 && sdivisibleOK(16,c) && !hasSmallRotate(config) ->
(Eq32 (Mod32 <typ.Int32> (SignExt16to32 <typ.Int32> x) (Const32 <typ.Int32> [c])) (Const32 <typ.Int32> [0]))
(Eq8 (Mod8u x (Const8 [c])) (Const8 [0])) && x.Op != OpConst8 && udivisibleOK8(c) && !hasSmallRotate(config) =>
(Eq32 (Mod32u <typ.UInt32> (ZeroExt8to32 <typ.UInt32> x) (Const32 <typ.UInt32> [int32(uint8(c))])) (Const32 <typ.UInt32> [0]))
(Eq16 (Mod16u x (Const16 [c])) (Const16 [0])) && x.Op != OpConst16 && udivisibleOK16(c) && !hasSmallRotate(config) =>
(Eq32 (Mod32u <typ.UInt32> (ZeroExt16to32 <typ.UInt32> x) (Const32 <typ.UInt32> [int32(uint16(c))])) (Const32 <typ.UInt32> [0]))
(Eq8 (Mod8 x (Const8 [c])) (Const8 [0])) && x.Op != OpConst8 && sdivisibleOK8(c) && !hasSmallRotate(config) =>
(Eq32 (Mod32 <typ.Int32> (SignExt8to32 <typ.Int32> x) (Const32 <typ.Int32> [int32(c)])) (Const32 <typ.Int32> [0]))
(Eq16 (Mod16 x (Const16 [c])) (Const16 [0])) && x.Op != OpConst16 && sdivisibleOK16(c) && !hasSmallRotate(config) =>
(Eq32 (Mod32 <typ.Int32> (SignExt16to32 <typ.Int32> x) (Const32 <typ.Int32> [int32(c)])) (Const32 <typ.Int32> [0]))
// Divisibility checks x%c == 0 convert to multiply and rotate.
// Note, x%c == 0 is rewritten as x == c*(x/c) during the opt pass
@ -1240,16 +1240,16 @@
)
)
&& v.Block.Func.pass.name != "opt" && mul.Uses == 1
&& m == int64(1<<8+umagic(8,c).m) && s == 8+umagic(8,c).s
&& x.Op != OpConst8 && udivisibleOK(8,c)
-> (Leq8U
&& m == int32(1<<8+umagic8(c).m) && s == 8+umagic8(c).s
&& x.Op != OpConst8 && udivisibleOK8(c)
=> (Leq8U
(RotateLeft8 <typ.UInt8>
(Mul8 <typ.UInt8>
(Const8 <typ.UInt8> [int64(int8(udivisible(8,c).m))])
(Const8 <typ.UInt8> [int8(udivisible8(c).m)])
x)
(Const8 <typ.UInt8> [int64(8-udivisible(8,c).k)])
(Const8 <typ.UInt8> [int8(8-udivisible8(c).k)])
)
(Const8 <typ.UInt8> [int64(int8(udivisible(8,c).max))])
(Const8 <typ.UInt8> [int8(udivisible8(c).max)])
)
(Eq16 x (Mul16 (Const16 [c])
@ -1262,16 +1262,16 @@
)
)
&& v.Block.Func.pass.name != "opt" && mul.Uses == 1
&& m == int64(1<<16+umagic(16,c).m) && s == 16+umagic(16,c).s
&& x.Op != OpConst16 && udivisibleOK(16,c)
-> (Leq16U
&& m == int64(1<<16+umagic16(c).m) && s == 16+umagic16(c).s
&& x.Op != OpConst16 && udivisibleOK16(c)
=> (Leq16U
(RotateLeft16 <typ.UInt16>
(Mul16 <typ.UInt16>
(Const16 <typ.UInt16> [int64(int16(udivisible(16,c).m))])
(Const16 <typ.UInt16> [int16(udivisible16(c).m)])
x)
(Const16 <typ.UInt16> [int64(16-udivisible(16,c).k)])
(Const16 <typ.UInt16> [int16(16-udivisible16(c).k)])
)
(Const16 <typ.UInt16> [int64(int16(udivisible(16,c).max))])
(Const16 <typ.UInt16> [int16(udivisible16(c).max)])
)
(Eq16 x (Mul16 (Const16 [c])
@ -1284,16 +1284,16 @@
)
)
&& v.Block.Func.pass.name != "opt" && mul.Uses == 1
&& m == int64(1<<15+umagic(16,c).m/2) && s == 16+umagic(16,c).s-1
&& x.Op != OpConst16 && udivisibleOK(16,c)
-> (Leq16U
&& m == int32(1<<15+umagic16(c).m/2) && s == 16+umagic16(c).s-1
&& x.Op != OpConst16 && udivisibleOK16(c)
=> (Leq16U
(RotateLeft16 <typ.UInt16>
(Mul16 <typ.UInt16>
(Const16 <typ.UInt16> [int64(int16(udivisible(16,c).m))])
(Const16 <typ.UInt16> [int16(udivisible16(c).m)])
x)
(Const16 <typ.UInt16> [int64(16-udivisible(16,c).k)])
(Const16 <typ.UInt16> [int16(16-udivisible16(c).k)])
)
(Const16 <typ.UInt16> [int64(int16(udivisible(16,c).max))])
(Const16 <typ.UInt16> [int16(udivisible16(c).max)])
)
(Eq16 x (Mul16 (Const16 [c])
@ -1306,16 +1306,16 @@
)
)
&& v.Block.Func.pass.name != "opt" && mul.Uses == 1
&& m == int64(1<<15+(umagic(16,c).m+1)/2) && s == 16+umagic(16,c).s-2
&& x.Op != OpConst16 && udivisibleOK(16,c)
-> (Leq16U
&& m == int32(1<<15+(umagic16(c).m+1)/2) && s == 16+umagic16(c).s-2
&& x.Op != OpConst16 && udivisibleOK16(c)
=> (Leq16U
(RotateLeft16 <typ.UInt16>
(Mul16 <typ.UInt16>
(Const16 <typ.UInt16> [int64(int16(udivisible(16,c).m))])
(Const16 <typ.UInt16> [int16(udivisible16(c).m)])
x)
(Const16 <typ.UInt16> [int64(16-udivisible(16,c).k)])
(Const16 <typ.UInt16> [int16(16-udivisible16(c).k)])
)
(Const16 <typ.UInt16> [int64(int16(udivisible(16,c).max))])
(Const16 <typ.UInt16> [int16(udivisible16(c).max)])
)
(Eq16 x (Mul16 (Const16 [c])
@ -1330,16 +1330,16 @@
)
)
&& v.Block.Func.pass.name != "opt" && mul.Uses == 1
&& m == int64(umagic(16,c).m) && s == 16+umagic(16,c).s-1
&& x.Op != OpConst16 && udivisibleOK(16,c)
-> (Leq16U
&& m == int32(umagic16(c).m) && s == 16+umagic16(c).s-1
&& x.Op != OpConst16 && udivisibleOK16(c)
=> (Leq16U
(RotateLeft16 <typ.UInt16>
(Mul16 <typ.UInt16>
(Const16 <typ.UInt16> [int64(int16(udivisible(16,c).m))])
(Const16 <typ.UInt16> [int16(udivisible16(c).m)])
x)
(Const16 <typ.UInt16> [int64(16-udivisible(16,c).k)])
(Const16 <typ.UInt16> [int16(16-udivisible16(c).k)])
)
(Const16 <typ.UInt16> [int64(int16(udivisible(16,c).max))])
(Const16 <typ.UInt16> [int16(udivisible16(c).max)])
)
(Eq32 x (Mul32 (Const32 [c])
@ -1351,16 +1351,16 @@
)
)
&& v.Block.Func.pass.name != "opt" && mul.Uses == 1
&& m == int64(int32(1<<31+umagic(32,c).m/2)) && s == umagic(32,c).s-1
&& x.Op != OpConst32 && udivisibleOK(32,c)
-> (Leq32U
&& m == int32(1<<31+umagic32(c).m/2) && s == umagic32(c).s-1
&& x.Op != OpConst32 && udivisibleOK32(c)
=> (Leq32U
(RotateLeft32 <typ.UInt32>
(Mul32 <typ.UInt32>
(Const32 <typ.UInt32> [int64(int32(udivisible(32,c).m))])
(Const32 <typ.UInt32> [int32(udivisible32(c).m)])
x)
(Const32 <typ.UInt32> [int64(32-udivisible(32,c).k)])
(Const32 <typ.UInt32> [int32(32-udivisible32(c).k)])
)
(Const32 <typ.UInt32> [int64(int32(udivisible(32,c).max))])
(Const32 <typ.UInt32> [int32(udivisible32(c).max)])
)
(Eq32 x (Mul32 (Const32 [c])
@ -1372,16 +1372,16 @@
)
)
&& v.Block.Func.pass.name != "opt" && mul.Uses == 1
&& m == int64(int32(1<<31+(umagic(32,c).m+1)/2)) && s == umagic(32,c).s-2
&& x.Op != OpConst32 && udivisibleOK(32,c)
-> (Leq32U
&& m == int32(1<<31+(umagic32(c).m+1)/2) && s == umagic32(c).s-2
&& x.Op != OpConst32 && udivisibleOK32(c)
=> (Leq32U
(RotateLeft32 <typ.UInt32>
(Mul32 <typ.UInt32>
(Const32 <typ.UInt32> [int64(int32(udivisible(32,c).m))])
(Const32 <typ.UInt32> [int32(udivisible32(c).m)])
x)
(Const32 <typ.UInt32> [int64(32-udivisible(32,c).k)])
(Const32 <typ.UInt32> [int32(32-udivisible32(c).k)])
)
(Const32 <typ.UInt32> [int64(int32(udivisible(32,c).max))])
(Const32 <typ.UInt32> [int32(udivisible32(c).max)])
)
(Eq32 x (Mul32 (Const32 [c])
@ -1395,16 +1395,16 @@
)
)
&& v.Block.Func.pass.name != "opt" && mul.Uses == 1
&& m == int64(int32(umagic(32,c).m)) && s == umagic(32,c).s-1
&& x.Op != OpConst32 && udivisibleOK(32,c)
-> (Leq32U
&& m == int32(umagic32(c).m) && s == umagic32(c).s-1
&& x.Op != OpConst32 && udivisibleOK32(c)
=> (Leq32U
(RotateLeft32 <typ.UInt32>
(Mul32 <typ.UInt32>
(Const32 <typ.UInt32> [int64(int32(udivisible(32,c).m))])
(Const32 <typ.UInt32> [int32(udivisible32(c).m)])
x)
(Const32 <typ.UInt32> [int64(32-udivisible(32,c).k)])
(Const32 <typ.UInt32> [int32(32-udivisible32(c).k)])
)
(Const32 <typ.UInt32> [int64(int32(udivisible(32,c).max))])
(Const32 <typ.UInt32> [int32(udivisible32(c).max)])
)
(Eq32 x (Mul32 (Const32 [c])
@ -1417,16 +1417,16 @@
)
)
&& v.Block.Func.pass.name != "opt" && mul.Uses == 1
&& m == int64(1<<31+umagic(32,c).m/2) && s == 32+umagic(32,c).s-1
&& x.Op != OpConst32 && udivisibleOK(32,c)
-> (Leq32U
&& m == int64(1<<31+umagic32(c).m/2) && s == 32+umagic32(c).s-1
&& x.Op != OpConst32 && udivisibleOK32(c)
=> (Leq32U
(RotateLeft32 <typ.UInt32>
(Mul32 <typ.UInt32>
(Const32 <typ.UInt32> [int64(int32(udivisible(32,c).m))])
(Const32 <typ.UInt32> [int32(udivisible32(c).m)])
x)
(Const32 <typ.UInt32> [int64(32-udivisible(32,c).k)])
(Const32 <typ.UInt32> [int32(32-udivisible32(c).k)])
)
(Const32 <typ.UInt32> [int64(int32(udivisible(32,c).max))])
(Const32 <typ.UInt32> [int32(udivisible32(c).max)])
)
(Eq32 x (Mul32 (Const32 [c])
@ -1439,16 +1439,16 @@
)
)
&& v.Block.Func.pass.name != "opt" && mul.Uses == 1
&& m == int64(1<<31+(umagic(32,c).m+1)/2) && s == 32+umagic(32,c).s-2
&& x.Op != OpConst32 && udivisibleOK(32,c)
-> (Leq32U
&& m == int64(1<<31+(umagic32(c).m+1)/2) && s == 32+umagic32(c).s-2
&& x.Op != OpConst32 && udivisibleOK32(c)
=> (Leq32U
(RotateLeft32 <typ.UInt32>
(Mul32 <typ.UInt32>
(Const32 <typ.UInt32> [int64(int32(udivisible(32,c).m))])
(Const32 <typ.UInt32> [int32(udivisible32(c).m)])
x)
(Const32 <typ.UInt32> [int64(32-udivisible(32,c).k)])
(Const32 <typ.UInt32> [int32(32-udivisible32(c).k)])
)
(Const32 <typ.UInt32> [int64(int32(udivisible(32,c).max))])
(Const32 <typ.UInt32> [int32(udivisible32(c).max)])
)
(Eq32 x (Mul32 (Const32 [c])
@ -1463,16 +1463,16 @@
)
)
&& v.Block.Func.pass.name != "opt" && mul.Uses == 1
&& m == int64(umagic(32,c).m) && s == 32+umagic(32,c).s-1
&& x.Op != OpConst32 && udivisibleOK(32,c)
-> (Leq32U
&& m == int64(umagic32(c).m) && s == 32+umagic32(c).s-1
&& x.Op != OpConst32 && udivisibleOK32(c)
=> (Leq32U
(RotateLeft32 <typ.UInt32>
(Mul32 <typ.UInt32>
(Const32 <typ.UInt32> [int64(int32(udivisible(32,c).m))])
(Const32 <typ.UInt32> [int32(udivisible32(c).m)])
x)
(Const32 <typ.UInt32> [int64(32-udivisible(32,c).k)])
(Const32 <typ.UInt32> [int32(32-udivisible32(c).k)])
)
(Const32 <typ.UInt32> [int64(int32(udivisible(32,c).max))])
(Const32 <typ.UInt32> [int32(udivisible32(c).max)])
)
(Eq64 x (Mul64 (Const64 [c])
@ -1483,16 +1483,16 @@
(Const64 [s]))
)
) && v.Block.Func.pass.name != "opt" && mul.Uses == 1
&& m == int64(1<<63+umagic(64,c).m/2) && s == umagic(64,c).s-1
&& x.Op != OpConst64 && udivisibleOK(64,c)
-> (Leq64U
&& m == int64(1<<63+umagic64(c).m/2) && s == umagic64(c).s-1
&& x.Op != OpConst64 && udivisibleOK64(c)
=> (Leq64U
(RotateLeft64 <typ.UInt64>
(Mul64 <typ.UInt64>
(Const64 <typ.UInt64> [int64(udivisible(64,c).m)])
(Const64 <typ.UInt64> [int64(udivisible64(c).m)])
x)
(Const64 <typ.UInt64> [int64(64-udivisible(64,c).k)])
(Const64 <typ.UInt64> [64-udivisible64(c).k])
)
(Const64 <typ.UInt64> [int64(udivisible(64,c).max)])
(Const64 <typ.UInt64> [int64(udivisible64(c).max)])
)
(Eq64 x (Mul64 (Const64 [c])
(Rsh64Ux64
@ -1502,16 +1502,16 @@
(Const64 [s]))
)
) && v.Block.Func.pass.name != "opt" && mul.Uses == 1
&& m == int64(1<<63+(umagic(64,c).m+1)/2) && s == umagic(64,c).s-2
&& x.Op != OpConst64 && udivisibleOK(64,c)
-> (Leq64U
&& m == int64(1<<63+(umagic64(c).m+1)/2) && s == umagic64(c).s-2
&& x.Op != OpConst64 && udivisibleOK64(c)
=> (Leq64U
(RotateLeft64 <typ.UInt64>
(Mul64 <typ.UInt64>
(Const64 <typ.UInt64> [int64(udivisible(64,c).m)])
(Const64 <typ.UInt64> [int64(udivisible64(c).m)])
x)
(Const64 <typ.UInt64> [int64(64-udivisible(64,c).k)])
(Const64 <typ.UInt64> [64-udivisible64(c).k])
)
(Const64 <typ.UInt64> [int64(udivisible(64,c).max)])
(Const64 <typ.UInt64> [int64(udivisible64(c).max)])
)
(Eq64 x (Mul64 (Const64 [c])
(Rsh64Ux64
@ -1523,16 +1523,16 @@
(Const64 [s]))
)
) && v.Block.Func.pass.name != "opt" && mul.Uses == 1
&& m == int64(umagic(64,c).m) && s == umagic(64,c).s-1
&& x.Op != OpConst64 && udivisibleOK(64,c)
-> (Leq64U
&& m == int64(umagic64(c).m) && s == umagic64(c).s-1
&& x.Op != OpConst64 && udivisibleOK64(c)
=> (Leq64U
(RotateLeft64 <typ.UInt64>
(Mul64 <typ.UInt64>
(Const64 <typ.UInt64> [int64(udivisible(64,c).m)])
(Const64 <typ.UInt64> [int64(udivisible64(c).m)])
x)
(Const64 <typ.UInt64> [int64(64-udivisible(64,c).k)])
(Const64 <typ.UInt64> [64-udivisible64(c).k])
)
(Const64 <typ.UInt64> [int64(udivisible(64,c).max)])
(Const64 <typ.UInt64> [int64(udivisible64(c).max)])
)
// Signed divisibility checks convert to multiply, add and rotate.
@ -1549,19 +1549,19 @@
)
)
&& v.Block.Func.pass.name != "opt" && mul.Uses == 1
&& m == int64(smagic(8,c).m) && s == 8+smagic(8,c).s
&& x.Op != OpConst8 && sdivisibleOK(8,c)
-> (Leq8U
&& m == int32(smagic8(c).m) && s == 8+smagic8(c).s
&& x.Op != OpConst8 && sdivisibleOK8(c)
=> (Leq8U
(RotateLeft8 <typ.UInt8>
(Add8 <typ.UInt8>
(Mul8 <typ.UInt8>
(Const8 <typ.UInt8> [int64(int8(sdivisible(8,c).m))])
(Const8 <typ.UInt8> [int8(sdivisible8(c).m)])
x)
(Const8 <typ.UInt8> [int64(int8(sdivisible(8,c).a))])
(Const8 <typ.UInt8> [int8(sdivisible8(c).a)])
)
(Const8 <typ.UInt8> [int64(8-sdivisible(8,c).k)])
(Const8 <typ.UInt8> [int8(8-sdivisible8(c).k)])
)
(Const8 <typ.UInt8> [int64(int8(sdivisible(8,c).max))])
(Const8 <typ.UInt8> [int8(sdivisible8(c).max)])
)
(Eq16 x (Mul16 (Const16 [c])
@ -1577,19 +1577,19 @@
)
)
&& v.Block.Func.pass.name != "opt" && mul.Uses == 1
&& m == int64(smagic(16,c).m) && s == 16+smagic(16,c).s
&& x.Op != OpConst16 && sdivisibleOK(16,c)
-> (Leq16U
&& m == int32(smagic16(c).m) && s == 16+smagic16(c).s
&& x.Op != OpConst16 && sdivisibleOK16(c)
=> (Leq16U
(RotateLeft16 <typ.UInt16>
(Add16 <typ.UInt16>
(Mul16 <typ.UInt16>
(Const16 <typ.UInt16> [int64(int16(sdivisible(16,c).m))])
(Const16 <typ.UInt16> [int16(sdivisible16(c).m)])
x)
(Const16 <typ.UInt16> [int64(int16(sdivisible(16,c).a))])
(Const16 <typ.UInt16> [int16(sdivisible16(c).a)])
)
(Const16 <typ.UInt16> [int64(16-sdivisible(16,c).k)])
(Const16 <typ.UInt16> [int16(16-sdivisible16(c).k)])
)
(Const16 <typ.UInt16> [int64(int16(sdivisible(16,c).max))])
(Const16 <typ.UInt16> [int16(sdivisible16(c).max)])
)
(Eq32 x (Mul32 (Const32 [c])
@ -1605,19 +1605,19 @@
)
)
&& v.Block.Func.pass.name != "opt" && mul.Uses == 1
&& m == int64(smagic(32,c).m) && s == 32+smagic(32,c).s
&& x.Op != OpConst32 && sdivisibleOK(32,c)
-> (Leq32U
&& m == int64(smagic32(c).m) && s == 32+smagic32(c).s
&& x.Op != OpConst32 && sdivisibleOK32(c)
=> (Leq32U
(RotateLeft32 <typ.UInt32>
(Add32 <typ.UInt32>
(Mul32 <typ.UInt32>
(Const32 <typ.UInt32> [int64(int32(sdivisible(32,c).m))])
(Const32 <typ.UInt32> [int32(sdivisible32(c).m)])
x)
(Const32 <typ.UInt32> [int64(int32(sdivisible(32,c).a))])
(Const32 <typ.UInt32> [int32(sdivisible32(c).a)])
)
(Const32 <typ.UInt32> [int64(32-sdivisible(32,c).k)])
(Const32 <typ.UInt32> [int32(32-sdivisible32(c).k)])
)
(Const32 <typ.UInt32> [int64(int32(sdivisible(32,c).max))])
(Const32 <typ.UInt32> [int32(sdivisible32(c).max)])
)
(Eq32 x (Mul32 (Const32 [c])
@ -1633,19 +1633,19 @@
)
)
&& v.Block.Func.pass.name != "opt" && mul.Uses == 1
&& m == int64(int32(smagic(32,c).m/2)) && s == smagic(32,c).s-1
&& x.Op != OpConst32 && sdivisibleOK(32,c)
-> (Leq32U
&& m == int32(smagic32(c).m/2) && s == smagic32(c).s-1
&& x.Op != OpConst32 && sdivisibleOK32(c)
=> (Leq32U
(RotateLeft32 <typ.UInt32>
(Add32 <typ.UInt32>
(Mul32 <typ.UInt32>
(Const32 <typ.UInt32> [int64(int32(sdivisible(32,c).m))])
(Const32 <typ.UInt32> [int32(sdivisible32(c).m)])
x)
(Const32 <typ.UInt32> [int64(int32(sdivisible(32,c).a))])
(Const32 <typ.UInt32> [int32(sdivisible32(c).a)])
)
(Const32 <typ.UInt32> [int64(32-sdivisible(32,c).k)])
(Const32 <typ.UInt32> [int32(32-sdivisible32(c).k)])
)
(Const32 <typ.UInt32> [int64(int32(sdivisible(32,c).max))])
(Const32 <typ.UInt32> [int32(sdivisible32(c).max)])
)
(Eq32 x (Mul32 (Const32 [c])
@ -1663,19 +1663,19 @@
)
)
&& v.Block.Func.pass.name != "opt" && mul.Uses == 1
&& m == int64(int32(smagic(32,c).m)) && s == smagic(32,c).s
&& x.Op != OpConst32 && sdivisibleOK(32,c)
-> (Leq32U
&& m == int32(smagic32(c).m) && s == smagic32(c).s
&& x.Op != OpConst32 && sdivisibleOK32(c)
=> (Leq32U
(RotateLeft32 <typ.UInt32>
(Add32 <typ.UInt32>
(Mul32 <typ.UInt32>
(Const32 <typ.UInt32> [int64(int32(sdivisible(32,c).m))])
(Const32 <typ.UInt32> [int32(sdivisible32(c).m)])
x)
(Const32 <typ.UInt32> [int64(int32(sdivisible(32,c).a))])
(Const32 <typ.UInt32> [int32(sdivisible32(c).a)])
)
(Const32 <typ.UInt32> [int64(32-sdivisible(32,c).k)])
(Const32 <typ.UInt32> [int32(32-sdivisible32(c).k)])
)
(Const32 <typ.UInt32> [int64(int32(sdivisible(32,c).max))])
(Const32 <typ.UInt32> [int32(sdivisible32(c).max)])
)
(Eq64 x (Mul64 (Const64 [c])
@ -1691,19 +1691,19 @@
)
)
&& v.Block.Func.pass.name != "opt" && mul.Uses == 1
&& m == int64(smagic(64,c).m/2) && s == smagic(64,c).s-1
&& x.Op != OpConst64 && sdivisibleOK(64,c)
-> (Leq64U
&& m == int64(smagic64(c).m/2) && s == smagic64(c).s-1
&& x.Op != OpConst64 && sdivisibleOK64(c)
=> (Leq64U
(RotateLeft64 <typ.UInt64>
(Add64 <typ.UInt64>
(Mul64 <typ.UInt64>
(Const64 <typ.UInt64> [int64(sdivisible(64,c).m)])
(Const64 <typ.UInt64> [int64(sdivisible64(c).m)])
x)
(Const64 <typ.UInt64> [int64(sdivisible(64,c).a)])
(Const64 <typ.UInt64> [int64(sdivisible64(c).a)])
)
(Const64 <typ.UInt64> [int64(64-sdivisible(64,c).k)])
(Const64 <typ.UInt64> [64-sdivisible64(c).k])
)
(Const64 <typ.UInt64> [int64(sdivisible(64,c).max)])
(Const64 <typ.UInt64> [int64(sdivisible64(c).max)])
)
(Eq64 x (Mul64 (Const64 [c])
@ -1721,19 +1721,19 @@
)
)
&& v.Block.Func.pass.name != "opt" && mul.Uses == 1
&& m == int64(smagic(64,c).m) && s == smagic(64,c).s
&& x.Op != OpConst64 && sdivisibleOK(64,c)
-> (Leq64U
&& m == int64(smagic64(c).m) && s == smagic64(c).s
&& x.Op != OpConst64 && sdivisibleOK64(c)
=> (Leq64U
(RotateLeft64 <typ.UInt64>
(Add64 <typ.UInt64>
(Mul64 <typ.UInt64>
(Const64 <typ.UInt64> [int64(sdivisible(64,c).m)])
(Const64 <typ.UInt64> [int64(sdivisible64(c).m)])
x)
(Const64 <typ.UInt64> [int64(sdivisible(64,c).a)])
(Const64 <typ.UInt64> [int64(sdivisible64(c).a)])
)
(Const64 <typ.UInt64> [int64(64-sdivisible(64,c).k)])
(Const64 <typ.UInt64> [64-sdivisible64(c).k])
)
(Const64 <typ.UInt64> [int64(sdivisible(64,c).max)])
(Const64 <typ.UInt64> [int64(sdivisible64(c).max)])
)
// Divisibility check for signed integers for power of two constant are simple mask.

View File

@ -96,7 +96,7 @@ func umagicOK(n uint, c int64) bool {
return d&(d-1) != 0
}
// umagicOKn reports whether we should strength reduce an n-bit divide by c.
// umagicOKn reports whether we should strength reduce an unsigned n-bit divide by c.
// We can strength reduce when c != 0 and c is not a power of two.
func umagicOK8(c int8) bool { return c&(c-1) != 0 }
func umagicOK16(c int16) bool { return c&(c-1) != 0 }
@ -130,6 +130,11 @@ func umagic(n uint, c int64) umagicData {
return umagicData{s: int64(s), m: m}
}
func umagic8(c int8) umagicData { return umagic(8, int64(c)) }
func umagic16(c int16) umagicData { return umagic(16, int64(c)) }
func umagic32(c int32) umagicData { return umagic(32, int64(c)) }
func umagic64(c int64) umagicData { return umagic(64, c) }
// For signed division, we use a similar strategy.
// First, we enforce a positive c.
// x / c = -(x / (-c))
@ -164,6 +169,12 @@ func smagicOK(n uint, c int64) bool {
return c&(c-1) != 0
}
// smagicOKn reports whether we should strength reduce an signed n-bit divide by c.
func smagicOK8(c int8) bool { return smagicOK(8, int64(c)) }
func smagicOK16(c int16) bool { return smagicOK(16, int64(c)) }
func smagicOK32(c int32) bool { return smagicOK(32, int64(c)) }
func smagicOK64(c int64) bool { return smagicOK(64, c) }
type smagicData struct {
s int64 // ⎡log2(c)⎤-1
m uint64 // ⎡2^(n+s)/c⎤
@ -191,6 +202,11 @@ func smagic(n uint, c int64) smagicData {
return smagicData{s: int64(s), m: m}
}
func smagic8(c int8) smagicData { return smagic(8, int64(c)) }
func smagic16(c int16) smagicData { return smagic(16, int64(c)) }
func smagic32(c int32) smagicData { return smagic(32, int64(c)) }
func smagic64(c int64) smagicData { return smagic(64, c) }
// Divisibility x%c == 0 can be checked more efficiently than directly computing
// the modulus x%c and comparing against 0.
//
@ -249,7 +265,7 @@ func smagic(n uint, c int64) smagicData {
//
// Where d0*2^k was replaced by c on the right hand side.
// uivisibleOK reports whether we should strength reduce a n-bit dividisibilty check by c.
// udivisibleOK reports whether we should strength reduce an unsigned n-bit divisibilty check by c.
func udivisibleOK(n uint, c int64) bool {
// Convert from ConstX auxint values to the real uint64 constant they represent.
d := uint64(c) << (64 - n) >> (64 - n)
@ -259,6 +275,11 @@ func udivisibleOK(n uint, c int64) bool {
return d&(d-1) != 0
}
func udivisibleOK8(c int8) bool { return udivisibleOK(8, int64(c)) }
func udivisibleOK16(c int16) bool { return udivisibleOK(16, int64(c)) }
func udivisibleOK32(c int32) bool { return udivisibleOK(32, int64(c)) }
func udivisibleOK64(c int64) bool { return udivisibleOK(64, c) }
type udivisibleData struct {
k int64 // trailingZeros(c)
m uint64 // m * (c>>k) mod 2^n == 1 multiplicative inverse of odd portion modulo 2^n
@ -293,6 +314,11 @@ func udivisible(n uint, c int64) udivisibleData {
}
}
func udivisible8(c int8) udivisibleData { return udivisible(8, int64(c)) }
func udivisible16(c int16) udivisibleData { return udivisible(16, int64(c)) }
func udivisible32(c int32) udivisibleData { return udivisible(32, int64(c)) }
func udivisible64(c int64) udivisibleData { return udivisible(64, c) }
// For signed integers, a similar method follows.
//
// Given c > 1 and odd, compute m such that (c * m) mod 2^n == 1
@ -341,7 +367,7 @@ func udivisible(n uint, c int64) udivisibleData {
// Note that the calculation is performed using unsigned integers.
// Since a' can have n-1 bits, 2a' may have n bits and there is no risk of overflow.
// sdivisibleOK reports whether we should strength reduce a n-bit dividisibilty check by c.
// sdivisibleOK reports whether we should strength reduce a signed n-bit divisibilty check by c.
func sdivisibleOK(n uint, c int64) bool {
if c < 0 {
// Doesn't work for negative c.
@ -352,6 +378,11 @@ func sdivisibleOK(n uint, c int64) bool {
return c&(c-1) != 0
}
func sdivisibleOK8(c int8) bool { return sdivisibleOK(8, int64(c)) }
func sdivisibleOK16(c int16) bool { return sdivisibleOK(16, int64(c)) }
func sdivisibleOK32(c int32) bool { return sdivisibleOK(32, int64(c)) }
func sdivisibleOK64(c int64) bool { return sdivisibleOK(64, c) }
type sdivisibleData struct {
k int64 // trailingZeros(c)
m uint64 // m * (c>>k) mod 2^n == 1 multiplicative inverse of odd portion modulo 2^n
@ -386,3 +417,8 @@ func sdivisible(n uint, c int64) sdivisibleData {
max: max,
}
}
func sdivisible8(c int8) sdivisibleData { return sdivisible(8, int64(c)) }
func sdivisible16(c int16) sdivisibleData { return sdivisible(16, int64(c)) }
func sdivisible32(c int32) sdivisibleData { return sdivisible(32, int64(c)) }
func sdivisible64(c int64) sdivisibleData { return sdivisible(64, c) }

File diff suppressed because it is too large Load Diff