mirror of
https://github.com/golang/go.git
synced 2025-12-07 13:50:04 +00:00
Change-Id: Ic0eca86d3c93707ebd7c716e774ebda55af4f196 Reviewed-on: https://go-review.googlesource.com/c/go/+/703755 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Julian Zhu <jz531210@gmail.com> Reviewed-by: Cherry Mui <cherryyz@google.com> Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> Reviewed-by: Joel Sing <joel@sing.id.au>
791 lines
19 KiB
Go
791 lines
19 KiB
Go
// asmcheck
|
|
|
|
// Copyright 2018 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.
|
|
|
|
package codegen
|
|
|
|
// This file contains codegen tests related to arithmetic
|
|
// simplifications and optimizations on integer types.
|
|
// For codegen tests on float types, see floats.go.
|
|
|
|
// Addition
|
|
|
|
func AddLargeConst(a uint64, out []uint64) {
|
|
// ppc64x/power10:"ADD [$]4294967296,"
|
|
// ppc64x/power9:"MOVD [$]1", "SLD [$]32" "ADD R[0-9]*"
|
|
// ppc64x/power8:"MOVD [$]1", "SLD [$]32" "ADD R[0-9]*"
|
|
out[0] = a + 0x100000000
|
|
// ppc64x/power10:"ADD [$]-8589934592,"
|
|
// ppc64x/power9:"MOVD [$]-1", "SLD [$]33" "ADD R[0-9]*"
|
|
// ppc64x/power8:"MOVD [$]-1", "SLD [$]33" "ADD R[0-9]*"
|
|
out[1] = a + 0xFFFFFFFE00000000
|
|
// ppc64x/power10:"ADD [$]1234567,"
|
|
// ppc64x/power9:"ADDIS [$]19,", "ADD [$]-10617,"
|
|
// ppc64x/power8:"ADDIS [$]19,", "ADD [$]-10617,"
|
|
out[2] = a + 1234567
|
|
// ppc64x/power10:"ADD [$]-1234567,"
|
|
// ppc64x/power9:"ADDIS [$]-19,", "ADD [$]10617,"
|
|
// ppc64x/power8:"ADDIS [$]-19,", "ADD [$]10617,"
|
|
out[3] = a - 1234567
|
|
// ppc64x/power10:"ADD [$]2147450879,"
|
|
// ppc64x/power9:"ADDIS [$]32767,", "ADD [$]32767,"
|
|
// ppc64x/power8:"ADDIS [$]32767,", "ADD [$]32767,"
|
|
out[4] = a + 0x7FFF7FFF
|
|
// ppc64x/power10:"ADD [$]-2147483647,"
|
|
// ppc64x/power9:"ADDIS [$]-32768,", "ADD [$]1,"
|
|
// ppc64x/power8:"ADDIS [$]-32768,", "ADD [$]1,"
|
|
out[5] = a - 2147483647
|
|
// ppc64x:"ADDIS [$]-32768,", ^"ADD "
|
|
out[6] = a - 2147483648
|
|
// ppc64x:"ADD [$]2147450880,", ^"ADDIS "
|
|
out[7] = a + 0x7FFF8000
|
|
// ppc64x:"ADD [$]-32768,", ^"ADDIS "
|
|
out[8] = a - 32768
|
|
// ppc64x/power10:"ADD [$]-32769,"
|
|
// ppc64x/power9:"ADDIS [$]-1,", "ADD [$]32767,"
|
|
// ppc64x/power8:"ADDIS [$]-1,", "ADD [$]32767,"
|
|
out[9] = a - 32769
|
|
}
|
|
|
|
func AddLargeConst2(a int, out []int) {
|
|
// loong64: -"ADDVU" "ADDV16"
|
|
out[0] = a + 0x10000
|
|
}
|
|
|
|
// Subtraction
|
|
|
|
var ef int
|
|
|
|
func SubMem(arr []int, b, c, d int) int {
|
|
// 386:`SUBL\s[A-Z]+,\s8\([A-Z]+\)`
|
|
// amd64:`SUBQ\s[A-Z]+,\s16\([A-Z]+\)`
|
|
arr[2] -= b
|
|
// 386:`SUBL\s[A-Z]+,\s12\([A-Z]+\)`
|
|
// amd64:`SUBQ\s[A-Z]+,\s24\([A-Z]+\)`
|
|
arr[3] -= b
|
|
// 386:`DECL\s16\([A-Z]+\)`
|
|
arr[4]--
|
|
// 386:`ADDL\s[$]-20,\s20\([A-Z]+\)`
|
|
arr[5] -= 20
|
|
// 386:`SUBL\s\([A-Z]+\)\([A-Z]+\*4\),\s[A-Z]+`
|
|
ef -= arr[b]
|
|
// 386:`SUBL\s[A-Z]+,\s\([A-Z]+\)\([A-Z]+\*4\)`
|
|
arr[c] -= b
|
|
// 386:`ADDL\s[$]-15,\s\([A-Z]+\)\([A-Z]+\*4\)`
|
|
arr[d] -= 15
|
|
// 386:`DECL\s\([A-Z]+\)\([A-Z]+\*4\)`
|
|
arr[b]--
|
|
// amd64:`DECQ\s64\([A-Z]+\)`
|
|
arr[8]--
|
|
// 386:"SUBL 4"
|
|
// amd64:"SUBQ 8"
|
|
return arr[0] - arr[1]
|
|
}
|
|
|
|
func SubFromConst(a int) int {
|
|
// ppc64x: `SUBC R[0-9]+,\s[$]40,\sR`
|
|
// riscv64: "ADDI [$]-40" "NEG"
|
|
b := 40 - a
|
|
return b
|
|
}
|
|
|
|
func SubFromConstNeg(a int) int {
|
|
// arm64: "ADD [$]40"
|
|
// loong64: "ADDV[U] [$]40"
|
|
// mips: "ADD[U] [$]40"
|
|
// mips64: "ADDV[U] [$]40"
|
|
// ppc64x: `ADD [$]40,\sR[0-9]+,\sR`
|
|
// riscv64: "ADDI [$]40" -"NEG"
|
|
c := 40 - (-a)
|
|
return c
|
|
}
|
|
|
|
func SubSubFromConst(a int) int {
|
|
// arm64: "ADD [$]20"
|
|
// loong64: "ADDV[U] [$]20"
|
|
// mips: "ADD[U] [$]20"
|
|
// mips64: "ADDV[U] [$]20"
|
|
// ppc64x: `ADD [$]20,\sR[0-9]+,\sR`
|
|
// riscv64: "ADDI [$]20" -"NEG"
|
|
c := 40 - (20 - a)
|
|
return c
|
|
}
|
|
|
|
func AddSubFromConst(a int) int {
|
|
// ppc64x: `SUBC R[0-9]+,\s[$]60,\sR`
|
|
// riscv64: "ADDI [$]-60" "NEG"
|
|
c := 40 + (20 - a)
|
|
return c
|
|
}
|
|
|
|
func NegSubFromConst(a int) int {
|
|
// arm64: "SUB [$]20"
|
|
// loong64: "ADDV[U] [$]-20"
|
|
// mips: "ADD[U] [$]-20"
|
|
// mips64: "ADDV[U] [$]-20"
|
|
// ppc64x: `ADD [$]-20,\sR[0-9]+,\sR`
|
|
// riscv64: "ADDI [$]-20"
|
|
c := -(20 - a)
|
|
return c
|
|
}
|
|
|
|
func NegAddFromConstNeg(a int) int {
|
|
// arm64: "SUB [$]40" "NEG"
|
|
// loong64: "ADDV[U] [$]-40" "SUBV"
|
|
// mips: "ADD[U] [$]-40" "SUB"
|
|
// mips64: "ADDV[U] [$]-40" "SUBV"
|
|
// ppc64x: `SUBC R[0-9]+,\s[$]40,\sR`
|
|
// riscv64: "ADDI [$]-40" "NEG"
|
|
c := -(-40 + a)
|
|
return c
|
|
}
|
|
|
|
func SubSubNegSimplify(a, b int) int {
|
|
// amd64:"NEGQ"
|
|
// arm64:"NEG"
|
|
// loong64:"SUBV"
|
|
// mips:"SUB"
|
|
// mips64:"SUBV"
|
|
// ppc64x:"NEG"
|
|
// riscv64:"NEG" -"SUB"
|
|
r := (a - b) - a
|
|
return r
|
|
}
|
|
|
|
func SubAddSimplify(a, b int) int {
|
|
// amd64:-"SUBQ" -"ADDQ"
|
|
// arm64:-"SUB" -"ADD"
|
|
// loong64:-"SUBV" -"ADDV"
|
|
// mips:-"SUB" -"ADD"
|
|
// mips64:-"SUBV" -"ADDV"
|
|
// ppc64x:-"SUB" -"ADD"
|
|
// riscv64:-"SUB" -"ADD"
|
|
r := a + (b - a)
|
|
return r
|
|
}
|
|
|
|
func SubAddSimplify2(a, b, c int) (int, int, int, int, int, int) {
|
|
// amd64:-"ADDQ"
|
|
// arm64:-"ADD"
|
|
// mips:"SUB" -"ADD"
|
|
// mips64:"SUBV" -"ADDV"
|
|
// loong64:"SUBV" -"ADDV"
|
|
// riscv64:-"ADD"
|
|
r := (a + b) - (a + c)
|
|
// amd64:-"ADDQ"
|
|
// riscv64:-"ADD"
|
|
r1 := (a + b) - (c + a)
|
|
// amd64:-"ADDQ"
|
|
// riscv64:-"ADD"
|
|
r2 := (b + a) - (a + c)
|
|
// amd64:-"ADDQ"
|
|
// riscv64:-"ADD"
|
|
r3 := (b + a) - (c + a)
|
|
// amd64:-"SUBQ"
|
|
// arm64:-"SUB"
|
|
// mips:"ADD" -"SUB"
|
|
// mips64:"ADDV" -"SUBV"
|
|
// loong64:"ADDV" -"SUBV"
|
|
// riscv64:-"SUB"
|
|
r4 := (a - c) + (c + b)
|
|
// amd64:-"SUBQ"
|
|
// riscv64:-"SUB"
|
|
r5 := (a - c) + (b + c)
|
|
return r, r1, r2, r3, r4, r5
|
|
}
|
|
|
|
func SubAddNegSimplify(a, b int) int {
|
|
// amd64:"NEGQ" -"ADDQ" -"SUBQ"
|
|
// arm64:"NEG" -"ADD" -"SUB"
|
|
// loong64:"SUBV" -"ADDV"
|
|
// mips:"SUB" -"ADD"
|
|
// mips64:"SUBV" -"ADDV"
|
|
// ppc64x:"NEG" -"ADD" -"SUB"
|
|
// riscv64:"NEG" -"ADD" -"SUB"
|
|
r := a - (b + a)
|
|
return r
|
|
}
|
|
|
|
func AddAddSubSimplify(a, b, c int) int {
|
|
// amd64:-"SUBQ"
|
|
// arm64:"ADD" -"SUB"
|
|
// loong64:"ADDV" -"SUBV"
|
|
// mips:"ADD" -"SUB"
|
|
// mips64:"ADDV" -"SUBV"
|
|
// ppc64x:-"SUB"
|
|
// riscv64:"ADD" "ADD" -"SUB"
|
|
r := a + (b + (c - a))
|
|
return r
|
|
}
|
|
|
|
func NegToInt32(a int) int {
|
|
// riscv64: "NEGW" -"MOVW"
|
|
r := int(int32(-a))
|
|
return r
|
|
}
|
|
|
|
// -------------------- //
|
|
// Multiplication //
|
|
// -------------------- //
|
|
|
|
func Pow2Muls(n1, n2 int) (int, int) {
|
|
// amd64:"SHLQ [$]5" -"IMULQ"
|
|
// 386:"SHLL [$]5" -"IMULL"
|
|
// arm:"SLL [$]5" -"MUL"
|
|
// arm64:"LSL [$]5" -"MUL"
|
|
// loong64:"SLLV [$]5" -"MULV"
|
|
// ppc64x:"SLD [$]5" -"MUL"
|
|
a := n1 * 32
|
|
|
|
// amd64:"SHLQ [$]6" -"IMULQ"
|
|
// 386:"SHLL [$]6" -"IMULL"
|
|
// arm:"SLL [$]6" -"MUL"
|
|
// arm64:`NEG\sR[0-9]+<<6,\sR[0-9]+`,-`LSL`,-`MUL`
|
|
// loong64:"SLLV [$]6" -"MULV"
|
|
// ppc64x:"SLD [$]6" "NEG\\sR[0-9]+,\\sR[0-9]+" -"MUL"
|
|
b := -64 * n2
|
|
|
|
return a, b
|
|
}
|
|
|
|
func Mul_2(n1 int32, n2 int64) (int32, int64) {
|
|
// amd64:"ADDL", -"SHLL"
|
|
a := n1 * 2
|
|
// amd64:"ADDQ", -"SHLQ"
|
|
b := n2 * 2
|
|
|
|
return a, b
|
|
}
|
|
|
|
func Mul_96(n int) int {
|
|
// amd64:`SHLQ [$]5`,`LEAQ \(.*\)\(.*\*2\),`,-`IMULQ`
|
|
// 386:`SHLL [$]5`,`LEAL \(.*\)\(.*\*2\),`,-`IMULL`
|
|
// arm64:`LSL [$]5`,`ADD\sR[0-9]+<<1,\sR[0-9]+`,-`MUL`
|
|
// arm:`SLL [$]5`,`ADD\sR[0-9]+<<1,\sR[0-9]+`,-`MUL`
|
|
// loong64:"SLLV [$]5" "ALSLV [$]1,"
|
|
// s390x:`SLD [$]5`,`SLD [$]6`,-`MULLD`
|
|
return n * 96
|
|
}
|
|
|
|
func Mul_n120(n int) int {
|
|
// loong64:"SLLV [$]3" "SLLV [$]7" "SUBVU" -"MULV"
|
|
// s390x:`SLD [$]3`,`SLD [$]7`,-`MULLD`
|
|
return n * -120
|
|
}
|
|
|
|
func MulMemSrc(a []uint32, b []float32) {
|
|
// 386:`IMULL\s4\([A-Z]+\),\s[A-Z]+`
|
|
a[0] *= a[1]
|
|
// 386/sse2:`MULSS\s4\([A-Z]+\),\sX[0-9]+`
|
|
// amd64:`MULSS\s4\([A-Z]+\),\sX[0-9]+`
|
|
b[0] *= b[1]
|
|
}
|
|
|
|
// Multiplications merging tests
|
|
|
|
func MergeMuls1(n int) int {
|
|
// amd64:"IMUL3Q [$]46"
|
|
// 386:"IMUL3L [$]46"
|
|
// ppc64x:"MULLD [$]46"
|
|
return 15*n + 31*n // 46n
|
|
}
|
|
|
|
func MergeMuls2(n int) int {
|
|
// amd64:"IMUL3Q [$]23" "(ADDQ [$]29)|(LEAQ 29)"
|
|
// 386:"IMUL3L [$]23" "ADDL [$]29"
|
|
// ppc64x/power9:"MADDLD" -"MULLD [$]23" -"ADD [$]29"
|
|
// ppc64x/power8:"MULLD [$]23" "ADD [$]29"
|
|
return 5*n + 7*(n+1) + 11*(n+2) // 23n + 29
|
|
}
|
|
|
|
func MergeMuls3(a, n int) int {
|
|
// amd64:"ADDQ [$]19" -"IMULQ [$]19"
|
|
// 386:"ADDL [$]19" -"IMULL [$]19"
|
|
// ppc64x:"ADD [$]19" -"MULLD [$]19"
|
|
return a*n + 19*n // (a+19)n
|
|
}
|
|
|
|
func MergeMuls4(n int) int {
|
|
// amd64:"IMUL3Q [$]14"
|
|
// 386:"IMUL3L [$]14"
|
|
// ppc64x:"MULLD [$]14"
|
|
return 23*n - 9*n // 14n
|
|
}
|
|
|
|
func MergeMuls5(a, n int) int {
|
|
// amd64:"ADDQ [$]-19" -"IMULQ [$]19"
|
|
// 386:"ADDL [$]-19" -"IMULL [$]19"
|
|
// ppc64x:"ADD [$]-19" -"MULLD [$]19"
|
|
return a*n - 19*n // (a-19)n
|
|
}
|
|
|
|
// Multiplications folded negation
|
|
|
|
func FoldNegMul(a int) int {
|
|
// amd64:"IMUL3Q [$]-11" -"NEGQ"
|
|
// arm64:"MOVD [$]-11" "MUL" -"NEG"
|
|
// loong64:"ALSLV [$]2" "SUBVU" "ALSLV [$]4"
|
|
// riscv64:"MOV [$]-11" "MUL" -"NEG"
|
|
return -a * 11
|
|
}
|
|
|
|
func Fold2NegMul(a, b int) int {
|
|
// amd64:"IMULQ" -"NEGQ"
|
|
// arm64:"MUL" -"NEG"
|
|
// loong64:"MULV" -"SUBVU R[0-9], R0,"
|
|
// riscv64:"MUL" -"NEG"
|
|
return -a * -b
|
|
}
|
|
|
|
func Mul32(a, b int32) int64 {
|
|
// arm64:"SMULL" -"MOVW"
|
|
// loong64:"MULWVW" -"MOVW"
|
|
return int64(a) * int64(b)
|
|
}
|
|
|
|
func Mul32U(a, b uint32) uint64 {
|
|
// arm64:"UMULL" -"MOVWU"
|
|
// loong64:"MULWVWU" -"MOVWU"
|
|
return uint64(a) * uint64(b)
|
|
}
|
|
|
|
func SimplifyNegMulConst(a int) int {
|
|
// amd64:-"NEGQ"
|
|
// arm64:"MOVD [$]11" "MUL" -"NEG"
|
|
// riscv64:"MOV [$]11" "MUL" -"NEG"
|
|
return -(a * -11)
|
|
}
|
|
|
|
func SimplifyNegMul(a, b int) int {
|
|
// amd64:-"NEGQ"
|
|
// arm64:"MUL" -"NEG"
|
|
// riscv64:"MUL" -"NEG"
|
|
return -(-a * b)
|
|
}
|
|
|
|
// -------------- //
|
|
// Division //
|
|
// -------------- //
|
|
|
|
func DivMemSrc(a []float64) {
|
|
// 386/sse2:`DIVSD\s8\([A-Z]+\),\sX[0-9]+`
|
|
// amd64:`DIVSD\s8\([A-Z]+\),\sX[0-9]+`
|
|
a[0] /= a[1]
|
|
}
|
|
|
|
func Pow2Divs(n1 uint, n2 int) (uint, int) {
|
|
// 386:"SHRL [$]5" -"DIVL"
|
|
// amd64:"SHRQ [$]5" -"DIVQ"
|
|
// arm:"SRL [$]5" -".*udiv"
|
|
// arm64:"LSR [$]5" -"UDIV"
|
|
// ppc64x:"SRD"
|
|
a := n1 / 32 // unsigned
|
|
|
|
// amd64:"SARQ [$]6" -"IDIVQ"
|
|
// 386:"SARL [$]6" -"IDIVL"
|
|
// arm:"SRA [$]6" -".*udiv"
|
|
// arm64:"ASR [$]6" -"SDIV"
|
|
// ppc64x:"SRAD"
|
|
b := n2 / 64 // signed
|
|
|
|
return a, b
|
|
}
|
|
|
|
// Check that constant divisions get turned into MULs
|
|
func ConstDivs(n1 uint, n2 int) (uint, int) {
|
|
// amd64: "MOVQ [$]-1085102592571150095" "MULQ" -"DIVQ"
|
|
// 386: "MOVL [$]-252645135" "MULL" -"DIVL"
|
|
// arm64: `MOVD`,`UMULH`,-`DIV`
|
|
// arm: `MOVW`,`MUL`,-`.*udiv`
|
|
a := n1 / 17 // unsigned
|
|
|
|
// amd64: "MOVQ [$]-1085102592571150095" "IMULQ" -"IDIVQ"
|
|
// 386: "IMULL" "SARL [$]4," "SARL [$]31," "SUBL" -".*DIV"
|
|
// arm64: `SMULH` -`DIV`
|
|
// arm: `MOVW` `MUL` -`.*udiv`
|
|
b := n2 / 17 // signed
|
|
|
|
return a, b
|
|
}
|
|
|
|
func FloatDivs(a []float32) float32 {
|
|
// amd64:`DIVSS\s8\([A-Z]+\),\sX[0-9]+`
|
|
// 386/sse2:`DIVSS\s8\([A-Z]+\),\sX[0-9]+`
|
|
return a[1] / a[2]
|
|
}
|
|
|
|
func Pow2Mods(n1 uint, n2 int) (uint, int) {
|
|
// 386:"ANDL [$]31" -"DIVL"
|
|
// amd64:"ANDL [$]31" -"DIVQ"
|
|
// arm:"AND [$]31" -".*udiv"
|
|
// arm64:"AND [$]31" -"UDIV"
|
|
// ppc64x:"RLDICL"
|
|
a := n1 % 32 // unsigned
|
|
|
|
// 386:"SHRL" -"IDIVL"
|
|
// amd64:"SHRQ" -"IDIVQ"
|
|
// arm:"SRA" -".*udiv"
|
|
// arm64:"ASR" -"REM"
|
|
// ppc64x:"SRAD"
|
|
b := n2 % 64 // signed
|
|
|
|
return a, b
|
|
}
|
|
|
|
// Check that signed divisibility checks get converted to AND on low bits
|
|
func Pow2DivisibleSigned(n1, n2 int) (bool, bool) {
|
|
// 386:"TESTL [$]63" -"DIVL" -"SHRL"
|
|
// amd64:"TESTQ [$]63" -"DIVQ" -"SHRQ"
|
|
// arm:"AND [$]63" -".*udiv" -"SRA"
|
|
// arm64:"TST [$]63" -"UDIV" -"ASR" -"AND"
|
|
// ppc64x:"ANDCC" -"RLDICL" -"SRAD" -"CMP"
|
|
a := n1%64 == 0 // signed divisible
|
|
|
|
// 386:"TESTL [$]63" -"DIVL" -"SHRL"
|
|
// amd64:"TESTQ [$]63" -"DIVQ" -"SHRQ"
|
|
// arm:"AND [$]63" -".*udiv" -"SRA"
|
|
// arm64:"TST [$]63" -"UDIV" -"ASR" -"AND"
|
|
// ppc64x:"ANDCC" -"RLDICL" -"SRAD" -"CMP"
|
|
b := n2%64 != 0 // signed indivisible
|
|
|
|
return a, b
|
|
}
|
|
|
|
// Check that constant modulo divs get turned into MULs
|
|
func ConstMods(n1 uint, n2 int) (uint, int) {
|
|
// amd64: "MOVQ [$]-1085102592571150095" "MULQ" -"DIVQ"
|
|
// 386: "MOVL [$]-252645135" "MULL" -".*DIVL"
|
|
// arm64: `MOVD` `UMULH` -`DIV`
|
|
// arm: `MOVW` `MUL` -`.*udiv`
|
|
a := n1 % 17 // unsigned
|
|
|
|
// amd64: "MOVQ [$]-1085102592571150095" "IMULQ" -"IDIVQ"
|
|
// 386: "IMULL" "SARL [$]4," "SARL [$]31," "SUBL" "SHLL [$]4," "SUBL" -".*DIV"
|
|
// arm64: `SMULH` -`DIV`
|
|
// arm: `MOVW` `MUL` -`.*udiv`
|
|
b := n2 % 17 // signed
|
|
|
|
return a, b
|
|
}
|
|
|
|
// Check that divisibility checks x%c==0 are converted to MULs and rotates
|
|
func DivisibleU(n uint) (bool, bool) {
|
|
// amd64:"MOVQ [$]-6148914691236517205" "IMULQ" "ROLQ [$]63" -"DIVQ"
|
|
// 386:"IMUL3L [$]-1431655765" "ROLL [$]31" -"DIVQ"
|
|
// arm64:"MOVD [$]-6148914691236517205" "MOVD [$]3074457345618258602" "MUL" "ROR" -"DIV"
|
|
// arm:"MUL" "CMP [$]715827882" -".*udiv"
|
|
// ppc64x:"MULLD" "ROTL [$]63"
|
|
even := n%6 == 0
|
|
|
|
// amd64:"MOVQ [$]-8737931403336103397" "IMULQ" -"ROLQ" -"DIVQ"
|
|
// 386:"IMUL3L [$]678152731" -"ROLL" -"DIVQ"
|
|
// arm64:"MOVD [$]-8737931403336103397" "MUL" -"ROR" -"DIV"
|
|
// arm:"MUL" "CMP [$]226050910" -".*udiv"
|
|
// ppc64x:"MULLD" -"ROTL"
|
|
odd := n%19 == 0
|
|
|
|
return even, odd
|
|
}
|
|
|
|
func Divisible(n int) (bool, bool) {
|
|
// amd64:"IMULQ" "ADD" "ROLQ [$]63" -"DIVQ"
|
|
// 386:"IMUL3L [$]-1431655765" "ADDL [$]715827882" "ROLL [$]31" -"DIVQ"
|
|
// arm64:"MOVD [$]-6148914691236517205" "MOVD [$]3074457345618258602" "MUL" "ADD R" "ROR" -"DIV"
|
|
// arm:"MUL" "ADD [$]715827882" -".*udiv"
|
|
// ppc64x/power8:"MULLD" "ADD" "ROTL [$]63"
|
|
// ppc64x/power9:"MADDLD" "ROTL [$]63"
|
|
even := n%6 == 0
|
|
|
|
// amd64:"IMULQ" "ADD" -"ROLQ" -"DIVQ"
|
|
// 386:"IMUL3L [$]678152731" "ADDL [$]113025455" -"ROLL" -"DIVQ"
|
|
// arm64:"MUL" "MOVD [$]485440633518672410" "ADD" -"ROR" -"DIV"
|
|
// arm:"MUL" "ADD [$]113025455" -".*udiv"
|
|
// ppc64x/power8:"MULLD" "ADD" -"ROTL"
|
|
// ppc64x/power9:"MADDLD" -"ROTL"
|
|
odd := n%19 == 0
|
|
|
|
return even, odd
|
|
}
|
|
|
|
// Check that fix-up code is not generated for divisions where it has been proven that
|
|
// that the divisor is not -1 or that the dividend is > MinIntNN.
|
|
func NoFix64A(divr int64) (int64, int64) {
|
|
var d int64 = 42
|
|
var e int64 = 84
|
|
if divr > 5 {
|
|
d /= divr // amd64:-"JMP"
|
|
e %= divr // amd64:-"JMP"
|
|
// The following statement is to avoid conflict between the above check
|
|
// and the normal JMP generated at the end of the block.
|
|
d += e
|
|
}
|
|
return d, e
|
|
}
|
|
|
|
func NoFix64B(divd int64) (int64, int64) {
|
|
var d int64
|
|
var e int64
|
|
var divr int64 = -1
|
|
if divd > -9223372036854775808 {
|
|
d = divd / divr // amd64:-"JMP"
|
|
e = divd % divr // amd64:-"JMP"
|
|
d += e
|
|
}
|
|
return d, e
|
|
}
|
|
|
|
func NoFix32A(divr int32) (int32, int32) {
|
|
var d int32 = 42
|
|
var e int32 = 84
|
|
if divr > 5 {
|
|
// amd64:-"JMP"
|
|
// 386:-"JMP"
|
|
d /= divr
|
|
// amd64:-"JMP"
|
|
// 386:-"JMP"
|
|
e %= divr
|
|
d += e
|
|
}
|
|
return d, e
|
|
}
|
|
|
|
func NoFix32B(divd int32) (int32, int32) {
|
|
var d int32
|
|
var e int32
|
|
var divr int32 = -1
|
|
if divd > -2147483648 {
|
|
// amd64:-"JMP"
|
|
// 386:-"JMP"
|
|
d = divd / divr
|
|
// amd64:-"JMP"
|
|
// 386:-"JMP"
|
|
e = divd % divr
|
|
d += e
|
|
}
|
|
return d, e
|
|
}
|
|
|
|
func NoFix16A(divr int16) (int16, int16) {
|
|
var d int16 = 42
|
|
var e int16 = 84
|
|
if divr > 5 {
|
|
// amd64:-"JMP"
|
|
// 386:-"JMP"
|
|
d /= divr
|
|
// amd64:-"JMP"
|
|
// 386:-"JMP"
|
|
e %= divr
|
|
d += e
|
|
}
|
|
return d, e
|
|
}
|
|
|
|
func NoFix16B(divd int16) (int16, int16) {
|
|
var d int16
|
|
var e int16
|
|
var divr int16 = -1
|
|
if divd > -32768 {
|
|
// amd64:-"JMP"
|
|
// 386:-"JMP"
|
|
d = divd / divr
|
|
// amd64:-"JMP"
|
|
// 386:-"JMP"
|
|
e = divd % divr
|
|
d += e
|
|
}
|
|
return d, e
|
|
}
|
|
|
|
// Check that len() and cap() calls divided by powers of two are
|
|
// optimized into shifts and ands
|
|
|
|
func LenDiv1(a []int) int {
|
|
// 386:"SHRL [$]10"
|
|
// amd64:"SHRQ [$]10"
|
|
// arm64:"LSR [$]10" -"SDIV"
|
|
// arm:"SRL [$]10" -".*udiv"
|
|
// ppc64x:"SRD" [$]10"
|
|
return len(a) / 1024
|
|
}
|
|
|
|
func LenDiv2(s string) int {
|
|
// 386:"SHRL [$]11"
|
|
// amd64:"SHRQ [$]11"
|
|
// arm64:"LSR [$]11" -"SDIV"
|
|
// arm:"SRL [$]11" -".*udiv"
|
|
// ppc64x:"SRD [$]11"
|
|
return len(s) / (4097 >> 1)
|
|
}
|
|
|
|
func LenMod1(a []int) int {
|
|
// 386:"ANDL [$]1023"
|
|
// amd64:"ANDL [$]1023"
|
|
// arm64:"AND [$]1023" -"SDIV"
|
|
// arm/6:"AND" -".*udiv"
|
|
// arm/7:"BFC" -".*udiv" -"AND"
|
|
// ppc64x:"RLDICL"
|
|
return len(a) % 1024
|
|
}
|
|
|
|
func LenMod2(s string) int {
|
|
// 386:"ANDL [$]2047"
|
|
// amd64:"ANDL [$]2047"
|
|
// arm64:"AND [$]2047" -"SDIV"
|
|
// arm/6:"AND" -".*udiv"
|
|
// arm/7:"BFC" -".*udiv" -"AND"
|
|
// ppc64x:"RLDICL"
|
|
return len(s) % (4097 >> 1)
|
|
}
|
|
|
|
func CapDiv(a []int) int {
|
|
// 386:"SHRL [$]12"
|
|
// amd64:"SHRQ [$]12"
|
|
// arm64:"LSR [$]12" -"SDIV"
|
|
// arm:"SRL [$]12" -".*udiv"
|
|
// ppc64x:"SRD [$]12"
|
|
return cap(a) / ((1 << 11) + 2048)
|
|
}
|
|
|
|
func CapMod(a []int) int {
|
|
// 386:"ANDL [$]4095"
|
|
// amd64:"ANDL [$]4095"
|
|
// arm64:"AND [$]4095" -"SDIV"
|
|
// arm/6:"AND" -".*udiv"
|
|
// arm/7:"BFC" -".*udiv" -"AND"
|
|
// ppc64x:"RLDICL"
|
|
return cap(a) % ((1 << 11) + 2048)
|
|
}
|
|
|
|
func AddMul(x int) int {
|
|
// amd64:"LEAQ 1"
|
|
return 2*x + 1
|
|
}
|
|
|
|
func AddShift(a, b int) int {
|
|
// loong64: "ALSLV"
|
|
return a + (b << 4)
|
|
}
|
|
|
|
func MULA(a, b, c uint32) (uint32, uint32, uint32) {
|
|
// arm:`MULA`,-`MUL\s`
|
|
// arm64:`MADDW`,-`MULW`
|
|
r0 := a*b + c
|
|
// arm:`MULA`,-`MUL\s`
|
|
// arm64:`MADDW`,-`MULW`
|
|
r1 := c*79 + a
|
|
// arm:`ADD`,-`MULA`,-`MUL\s`
|
|
// arm64:`ADD`,-`MADD`,-`MULW`
|
|
// ppc64x:`ADD`,-`MULLD`
|
|
r2 := b*64 + c
|
|
return r0, r1, r2
|
|
}
|
|
|
|
func MULS(a, b, c uint32) (uint32, uint32, uint32) {
|
|
// arm/7:`MULS`,-`MUL\s`
|
|
// arm/6:`SUB`,`MUL\s`,-`MULS`
|
|
// arm64:`MSUBW`,-`MULW`
|
|
r0 := c - a*b
|
|
// arm/7:`MULS`,-`MUL\s`
|
|
// arm/6:`SUB`,`MUL\s`,-`MULS`
|
|
// arm64:`MSUBW`,-`MULW`
|
|
r1 := a - c*79
|
|
// arm/7:`SUB`,-`MULS`,-`MUL\s`
|
|
// arm64:`SUB`,-`MSUBW`,-`MULW`
|
|
// ppc64x:`SUB`,-`MULLD`
|
|
r2 := c - b*64
|
|
return r0, r1, r2
|
|
}
|
|
|
|
func addSpecial(a, b, c uint32) (uint32, uint32, uint32) {
|
|
// amd64:`INCL`
|
|
a++
|
|
// amd64:`DECL`
|
|
b--
|
|
// amd64:`SUBL.*-128`
|
|
c += 128
|
|
return a, b, c
|
|
}
|
|
|
|
// Divide -> shift rules usually require fixup for negative inputs.
|
|
// If the input is non-negative, make sure the unsigned form is generated.
|
|
func divInt(v int64) int64 {
|
|
if v < 0 {
|
|
// amd64:`SARQ.*63,`, `SHRQ.*56,`, `SARQ.*8,`
|
|
return v / 256
|
|
}
|
|
// amd64:-`.*SARQ`, `SHRQ.*9,`
|
|
return v / 512
|
|
}
|
|
|
|
// The reassociate rules "x - (z + C) -> (x - z) - C" and
|
|
// "(z + C) -x -> C + (z - x)" can optimize the following cases.
|
|
func constantFold1(i0, j0, i1, j1, i2, j2, i3, j3 int) (int, int, int, int) {
|
|
// arm64:"SUB" "ADD [$]2"
|
|
// ppc64x:"SUB" "ADD [$]2"
|
|
r0 := (i0 + 3) - (j0 + 1)
|
|
// arm64:"SUB" "SUB [$]4"
|
|
// ppc64x:"SUB" "ADD [$]-4"
|
|
r1 := (i1 - 3) - (j1 + 1)
|
|
// arm64:"SUB" "ADD [$]4"
|
|
// ppc64x:"SUB" "ADD [$]4"
|
|
r2 := (i2 + 3) - (j2 - 1)
|
|
// arm64:"SUB" "SUB [$]2"
|
|
// ppc64x:"SUB" "ADD [$]-2"
|
|
r3 := (i3 - 3) - (j3 - 1)
|
|
return r0, r1, r2, r3
|
|
}
|
|
|
|
// The reassociate rules "x - (z + C) -> (x - z) - C" and
|
|
// "(C - z) - x -> C - (z + x)" can optimize the following cases.
|
|
func constantFold2(i0, j0, i1, j1 int) (int, int) {
|
|
// arm64:"ADD" "MOVD [$]2" "SUB"
|
|
// ppc64x: `SUBC R[0-9]+,\s[$]2,\sR`
|
|
r0 := (3 - i0) - (j0 + 1)
|
|
// arm64:"ADD" "MOVD [$]4" "SUB"
|
|
// ppc64x: `SUBC R[0-9]+,\s[$]4,\sR`
|
|
r1 := (3 - i1) - (j1 - 1)
|
|
return r0, r1
|
|
}
|
|
|
|
func constantFold3(i, j int) int {
|
|
// arm64: "LSL [$]5," "SUB R[0-9]+<<1," -"ADD"
|
|
// ppc64x:"MULLD [$]30" "MULLD"
|
|
r := (5 * i) * (6 * j)
|
|
return r
|
|
}
|
|
|
|
// Integer Min/Max
|
|
|
|
func Int64Min(a, b int64) int64 {
|
|
// amd64: "CMPQ" "CMOVQLT"
|
|
// arm64: "CMP" "CSEL"
|
|
// riscv64/rva20u64:"BLT "
|
|
// riscv64/rva22u64,riscv64/rva23u64:"MIN "
|
|
return min(a, b)
|
|
}
|
|
|
|
func Int64Max(a, b int64) int64 {
|
|
// amd64: "CMPQ" "CMOVQGT"
|
|
// arm64: "CMP" "CSEL"
|
|
// riscv64/rva20u64:"BLT "
|
|
// riscv64/rva22u64,riscv64/rva23u64:"MAX "
|
|
return max(a, b)
|
|
}
|
|
|
|
func Uint64Min(a, b uint64) uint64 {
|
|
// amd64: "CMPQ" "CMOVQCS"
|
|
// arm64: "CMP" "CSEL"
|
|
// riscv64/rva20u64:"BLTU"
|
|
// riscv64/rva22u64,riscv64/rva23u64:"MINU"
|
|
return min(a, b)
|
|
}
|
|
|
|
func Uint64Max(a, b uint64) uint64 {
|
|
// amd64: "CMPQ" "CMOVQHI"
|
|
// arm64: "CMP" "CSEL"
|
|
// riscv64/rva20u64:"BLTU"
|
|
// riscv64/rva22u64,riscv64/rva23u64:"MAXU"
|
|
return max(a, b)
|
|
}
|