blob: 8c19883826722635b95fa4e9c6618b9c3cc9d698 [file] [log] [blame] [edit]
// Copyright 2025 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Divisibility checks (x%c == 0 or x%c != 0) convert to multiply, rotate, compare.
// The opt pass rewrote x%c to x-(x/c)*c
// and then also rewrote x-(x/c)*c == 0 to x == (x/c)*c.
// If x/c is being used for a division already (div.Uses != 1)
// then we leave the expression alone.
//
// See ../magic.go for a detailed description of these algorithms.
// See test/codegen/divmod.go for tests.
// See divmod.rules for other division rules that run after these.
// Divisiblity by unsigned or signed power of two.
(Eq(8|16|32|64) x (Mul(8|16|32|64) <t> (Div(8|16|32|64)u x (Const(8|16|32|64) [c])) (Const(8|16|32|64) [c])))
&& x.Op != OpConst64 && isPowerOfTwo(c) =>
(Eq(8|16|32|64) (And(8|16|32|64) <t> x (Const(8|16|32|64) <t> [c-1])) (Const(8|16|32|64) <t> [0]))
(Eq(8|16|32|64) x (Mul(8|16|32|64) <t> (Div(8|16|32|64) x (Const(8|16|32|64) [c])) (Const(8|16|32|64) [c])))
&& x.Op != OpConst64 && isPowerOfTwo(c) =>
(Eq(8|16|32|64) (And(8|16|32|64) <t> x (Const(8|16|32|64) <t> [c-1])) (Const(8|16|32|64) <t> [0]))
(Neq(8|16|32|64) x (Mul(8|16|32|64) <t> (Div(8|16|32|64)u x (Const(8|16|32|64) [c])) (Const(8|16|32|64) [c])))
&& x.Op != OpConst64 && isPowerOfTwo(c) =>
(Neq(8|16|32|64) (And(8|16|32|64) <t> x (Const(8|16|32|64) <t> [c-1])) (Const(8|16|32|64) <t> [0]))
(Neq(8|16|32|64) x (Mul(8|16|32|64) <t> (Div(8|16|32|64) x (Const(8|16|32|64) [c])) (Const(8|16|32|64) [c])))
&& x.Op != OpConst64 && isPowerOfTwo(c) =>
(Neq(8|16|32|64) (And(8|16|32|64) <t> x (Const(8|16|32|64) <t> [c-1])) (Const(8|16|32|64) <t> [0]))
// Divisiblity by unsigned.
(Eq8 x (Mul8 <t> div:(Div8u x (Const8 [c])) (Const8 [c])))
&& div.Uses == 1
&& x.Op != OpConst8 && udivisibleOK8(c) =>
(Leq8U
(RotateLeft8 <t>
(Mul8 <t> x (Const8 <t> [int8(udivisible8(c).m)]))
(Const8 <t> [int8(8 - udivisible8(c).k)]))
(Const8 <t> [int8(udivisible8(c).max)]))
(Neq8 x (Mul8 <t> div:(Div8u x (Const8 [c])) (Const8 [c])))
&& div.Uses == 1
&& x.Op != OpConst8 && udivisibleOK8(c) =>
(Less8U
(Const8 <t> [int8(udivisible8(c).max)])
(RotateLeft8 <t>
(Mul8 <t> x (Const8 <t> [int8(udivisible8(c).m)]))
(Const8 <t> [int8(8 - udivisible8(c).k)])))
(Eq16 x (Mul16 <t> div:(Div16u x (Const16 [c])) (Const16 [c])))
&& div.Uses == 1
&& x.Op != OpConst16 && udivisibleOK16(c) =>
(Leq16U
(RotateLeft16 <t>
(Mul16 <t> x (Const16 <t> [int16(udivisible16(c).m)]))
(Const16 <t> [int16(16 - udivisible16(c).k)]))
(Const16 <t> [int16(udivisible16(c).max)]))
(Neq16 x (Mul16 <t> div:(Div16u x (Const16 [c])) (Const16 [c])))
&& div.Uses == 1
&& x.Op != OpConst16 && udivisibleOK16(c) =>
(Less16U
(Const16 <t> [int16(udivisible16(c).max)])
(RotateLeft16 <t>
(Mul16 <t> x (Const16 <t> [int16(udivisible16(c).m)]))
(Const16 <t> [int16(16 - udivisible16(c).k)])))
(Eq32 x (Mul32 <t> div:(Div32u x (Const32 [c])) (Const32 [c])))
&& div.Uses == 1
&& x.Op != OpConst32 && udivisibleOK32(c) =>
(Leq32U
(RotateLeft32 <t>
(Mul32 <t> x (Const32 <t> [int32(udivisible32(c).m)]))
(Const32 <t> [int32(32 - udivisible32(c).k)]))
(Const32 <t> [int32(udivisible32(c).max)]))
(Neq32 x (Mul32 <t> div:(Div32u x (Const32 [c])) (Const32 [c])))
&& div.Uses == 1
&& x.Op != OpConst32 && udivisibleOK32(c) =>
(Less32U
(Const32 <t> [int32(udivisible32(c).max)])
(RotateLeft32 <t>
(Mul32 <t> x (Const32 <t> [int32(udivisible32(c).m)]))
(Const32 <t> [int32(32 - udivisible32(c).k)])))
(Eq64 x (Mul64 <t> div:(Div64u x (Const64 [c])) (Const64 [c])))
&& div.Uses == 1
&& x.Op != OpConst64 && udivisibleOK64(c) =>
(Leq64U
(RotateLeft64 <t>
(Mul64 <t> x (Const64 <t> [int64(udivisible64(c).m)]))
(Const64 <t> [int64(64 - udivisible64(c).k)]))
(Const64 <t> [int64(udivisible64(c).max)]))
(Neq64 x (Mul64 <t> div:(Div64u x (Const64 [c])) (Const64 [c])))
&& div.Uses == 1
&& x.Op != OpConst64 && udivisibleOK64(c) =>
(Less64U
(Const64 <t> [int64(udivisible64(c).max)])
(RotateLeft64 <t>
(Mul64 <t> x (Const64 <t> [int64(udivisible64(c).m)]))
(Const64 <t> [int64(64 - udivisible64(c).k)])))
// Divisiblity by signed.
(Eq8 x (Mul8 <t> div:(Div8 x (Const8 [c])) (Const8 [c])))
&& div.Uses == 1
&& x.Op != OpConst8 && sdivisibleOK8(c) =>
(Leq8U
(RotateLeft8 <t>
(Add8 <t> (Mul8 <t> x (Const8 <t> [int8(sdivisible8(c).m)]))
(Const8 <t> [int8(sdivisible8(c).a)]))
(Const8 <t> [int8(8 - sdivisible8(c).k)]))
(Const8 <t> [int8(sdivisible8(c).max)]))
(Neq8 x (Mul8 <t> div:(Div8 x (Const8 [c])) (Const8 [c])))
&& div.Uses == 1
&& x.Op != OpConst8 && sdivisibleOK8(c) =>
(Less8U
(Const8 <t> [int8(sdivisible8(c).max)])
(RotateLeft8 <t>
(Add8 <t> (Mul8 <t> x (Const8 <t> [int8(sdivisible8(c).m)]))
(Const8 <t> [int8(sdivisible8(c).a)]))
(Const8 <t> [int8(8 - sdivisible8(c).k)])))
(Eq16 x (Mul16 <t> div:(Div16 x (Const16 [c])) (Const16 [c])))
&& div.Uses == 1
&& x.Op != OpConst16 && sdivisibleOK16(c) =>
(Leq16U
(RotateLeft16 <t>
(Add16 <t> (Mul16 <t> x (Const16 <t> [int16(sdivisible16(c).m)]))
(Const16 <t> [int16(sdivisible16(c).a)]))
(Const16 <t> [int16(16 - sdivisible16(c).k)]))
(Const16 <t> [int16(sdivisible16(c).max)]))
(Neq16 x (Mul16 <t> div:(Div16 x (Const16 [c])) (Const16 [c])))
&& div.Uses == 1
&& x.Op != OpConst16 && sdivisibleOK16(c) =>
(Less16U
(Const16 <t> [int16(sdivisible16(c).max)])
(RotateLeft16 <t>
(Add16 <t> (Mul16 <t> x (Const16 <t> [int16(sdivisible16(c).m)]))
(Const16 <t> [int16(sdivisible16(c).a)]))
(Const16 <t> [int16(16 - sdivisible16(c).k)])))
(Eq32 x (Mul32 <t> div:(Div32 x (Const32 [c])) (Const32 [c])))
&& div.Uses == 1
&& x.Op != OpConst32 && sdivisibleOK32(c) =>
(Leq32U
(RotateLeft32 <t>
(Add32 <t> (Mul32 <t> x (Const32 <t> [int32(sdivisible32(c).m)]))
(Const32 <t> [int32(sdivisible32(c).a)]))
(Const32 <t> [int32(32 - sdivisible32(c).k)]))
(Const32 <t> [int32(sdivisible32(c).max)]))
(Neq32 x (Mul32 <t> div:(Div32 x (Const32 [c])) (Const32 [c])))
&& div.Uses == 1
&& x.Op != OpConst32 && sdivisibleOK32(c) =>
(Less32U
(Const32 <t> [int32(sdivisible32(c).max)])
(RotateLeft32 <t>
(Add32 <t> (Mul32 <t> x (Const32 <t> [int32(sdivisible32(c).m)]))
(Const32 <t> [int32(sdivisible32(c).a)]))
(Const32 <t> [int32(32 - sdivisible32(c).k)])))
(Eq64 x (Mul64 <t> div:(Div64 x (Const64 [c])) (Const64 [c])))
&& div.Uses == 1
&& x.Op != OpConst64 && sdivisibleOK64(c) =>
(Leq64U
(RotateLeft64 <t>
(Add64 <t> (Mul64 <t> x (Const64 <t> [int64(sdivisible64(c).m)]))
(Const64 <t> [int64(sdivisible64(c).a)]))
(Const64 <t> [int64(64 - sdivisible64(c).k)]))
(Const64 <t> [int64(sdivisible64(c).max)]))
(Neq64 x (Mul64 <t> div:(Div64 x (Const64 [c])) (Const64 [c])))
&& div.Uses == 1
&& x.Op != OpConst64 && sdivisibleOK64(c) =>
(Less64U
(Const64 <t> [int64(sdivisible64(c).max)])
(RotateLeft64 <t>
(Add64 <t> (Mul64 <t> x (Const64 <t> [int64(sdivisible64(c).m)]))
(Const64 <t> [int64(sdivisible64(c).a)]))
(Const64 <t> [int64(64 - sdivisible64(c).k)])))