Source file test/codegen/arithmetic.go

     1  // asmcheck
     2  
     3  // Copyright 2018 The Go Authors. All rights reserved.
     4  // Use of this source code is governed by a BSD-style
     5  // license that can be found in the LICENSE file.
     6  
     7  package codegen
     8  
     9  // This file contains codegen tests related to arithmetic
    10  // simplifications and optimizations on integer types.
    11  // For codegen tests on float types, see floats.go.
    12  
    13  // ----------------- //
    14  //    Addition       //
    15  // ----------------- //
    16  
    17  func AddLargeConst(a uint64, out []uint64) {
    18  	// ppc64x/power10:"ADD\t[$]4294967296,"
    19  	// ppc64x/power9:"MOVD\t[$]1", "SLD\t[$]32" "ADD\tR[0-9]*"
    20  	// ppc64x/power8:"MOVD\t[$]1", "SLD\t[$]32" "ADD\tR[0-9]*"
    21  	out[0] = a + 0x100000000
    22  	// ppc64x/power10:"ADD\t[$]-8589934592,"
    23  	// ppc64x/power9:"MOVD\t[$]-1", "SLD\t[$]33" "ADD\tR[0-9]*"
    24  	// ppc64x/power8:"MOVD\t[$]-1", "SLD\t[$]33" "ADD\tR[0-9]*"
    25  	out[1] = a + 0xFFFFFFFE00000000
    26  	// ppc64x/power10:"ADD\t[$]1234567,"
    27  	// ppc64x/power9:"ADDIS\t[$]19,", "ADD\t[$]-10617,"
    28  	// ppc64x/power8:"ADDIS\t[$]19,", "ADD\t[$]-10617,"
    29  	out[2] = a + 1234567
    30  	// ppc64x/power10:"ADD\t[$]-1234567,"
    31  	// ppc64x/power9:"ADDIS\t[$]-19,", "ADD\t[$]10617,"
    32  	// ppc64x/power8:"ADDIS\t[$]-19,", "ADD\t[$]10617,"
    33  	out[3] = a - 1234567
    34  	// ppc64x/power10:"ADD\t[$]2147450879,"
    35  	// ppc64x/power9:"ADDIS\t[$]32767,", "ADD\t[$]32767,"
    36  	// ppc64x/power8:"ADDIS\t[$]32767,", "ADD\t[$]32767,"
    37  	out[4] = a + 0x7FFF7FFF
    38  	// ppc64x/power10:"ADD\t[$]-2147483647,"
    39  	// ppc64x/power9:"ADDIS\t[$]-32768,", "ADD\t[$]1,"
    40  	// ppc64x/power8:"ADDIS\t[$]-32768,", "ADD\t[$]1,"
    41  	out[5] = a - 2147483647
    42  	// ppc64x:"ADDIS\t[$]-32768,", ^"ADD\t"
    43  	out[6] = a - 2147483648
    44  	// ppc64x:"ADD\t[$]2147450880,", ^"ADDIS\t"
    45  	out[7] = a + 0x7FFF8000
    46  	// ppc64x:"ADD\t[$]-32768,", ^"ADDIS\t"
    47  	out[8] = a - 32768
    48  	// ppc64x/power10:"ADD\t[$]-32769,"
    49  	// ppc64x/power9:"ADDIS\t[$]-1,", "ADD\t[$]32767,"
    50  	// ppc64x/power8:"ADDIS\t[$]-1,", "ADD\t[$]32767,"
    51  	out[9] = a - 32769
    52  }
    53  
    54  // ----------------- //
    55  //    Subtraction    //
    56  // ----------------- //
    57  
    58  var ef int
    59  
    60  func SubMem(arr []int, b, c, d int) int {
    61  	// 386:`SUBL\s[A-Z]+,\s8\([A-Z]+\)`
    62  	// amd64:`SUBQ\s[A-Z]+,\s16\([A-Z]+\)`
    63  	arr[2] -= b
    64  	// 386:`SUBL\s[A-Z]+,\s12\([A-Z]+\)`
    65  	// amd64:`SUBQ\s[A-Z]+,\s24\([A-Z]+\)`
    66  	arr[3] -= b
    67  	// 386:`DECL\s16\([A-Z]+\)`
    68  	arr[4]--
    69  	// 386:`ADDL\s[$]-20,\s20\([A-Z]+\)`
    70  	arr[5] -= 20
    71  	// 386:`SUBL\s\([A-Z]+\)\([A-Z]+\*4\),\s[A-Z]+`
    72  	ef -= arr[b]
    73  	// 386:`SUBL\s[A-Z]+,\s\([A-Z]+\)\([A-Z]+\*4\)`
    74  	arr[c] -= b
    75  	// 386:`ADDL\s[$]-15,\s\([A-Z]+\)\([A-Z]+\*4\)`
    76  	arr[d] -= 15
    77  	// 386:`DECL\s\([A-Z]+\)\([A-Z]+\*4\)`
    78  	arr[b]--
    79  	// amd64:`DECQ\s64\([A-Z]+\)`
    80  	arr[8]--
    81  	// 386:"SUBL\t4"
    82  	// amd64:"SUBQ\t8"
    83  	return arr[0] - arr[1]
    84  }
    85  
    86  func SubFromConst(a int) int {
    87  	// ppc64x: `SUBC\tR[0-9]+,\s[$]40,\sR`
    88  	// riscv64: "ADDI\t\\$-40","NEG"
    89  	b := 40 - a
    90  	return b
    91  }
    92  
    93  func SubFromConstNeg(a int) int {
    94  	// arm64: "ADD\t\\$40"
    95  	// loong64: "ADDV[U]\t\\$40"
    96  	// mips: "ADD[U]\t\\$40"
    97  	// mips64: "ADDV[U]\t\\$40"
    98  	// ppc64x: `ADD\t[$]40,\sR[0-9]+,\sR`
    99  	// riscv64: "ADDI\t\\$40",-"NEG"
   100  	c := 40 - (-a)
   101  	return c
   102  }
   103  
   104  func SubSubFromConst(a int) int {
   105  	// arm64: "ADD\t\\$20"
   106  	// loong64: "ADDV[U]\t\\$20"
   107  	// mips: "ADD[U]\t\\$20"
   108  	// mips64: "ADDV[U]\t\\$20"
   109  	// ppc64x: `ADD\t[$]20,\sR[0-9]+,\sR`
   110  	// riscv64: "ADDI\t\\$20",-"NEG"
   111  	c := 40 - (20 - a)
   112  	return c
   113  }
   114  
   115  func AddSubFromConst(a int) int {
   116  	// ppc64x: `SUBC\tR[0-9]+,\s[$]60,\sR`
   117  	// riscv64: "ADDI\t\\$-60","NEG"
   118  	c := 40 + (20 - a)
   119  	return c
   120  }
   121  
   122  func NegSubFromConst(a int) int {
   123  	// arm64: "SUB\t\\$20"
   124  	// loong64: "ADDV[U]\t\\$-20"
   125  	// mips: "ADD[U]\t\\$-20"
   126  	// mips64: "ADDV[U]\t\\$-20"
   127  	// ppc64x: `ADD\t[$]-20,\sR[0-9]+,\sR`
   128  	// riscv64: "ADDI\t\\$-20"
   129  	c := -(20 - a)
   130  	return c
   131  }
   132  
   133  func NegAddFromConstNeg(a int) int {
   134  	// arm64: "SUB\t\\$40","NEG"
   135  	// loong64: "ADDV[U]\t\\$-40","SUBV"
   136  	// mips: "ADD[U]\t\\$-40","SUB"
   137  	// mips64: "ADDV[U]\t\\$-40","SUBV"
   138  	// ppc64x: `SUBC\tR[0-9]+,\s[$]40,\sR`
   139  	// riscv64: "ADDI\t\\$-40","NEG"
   140  	c := -(-40 + a)
   141  	return c
   142  }
   143  
   144  func SubSubNegSimplify(a, b int) int {
   145  	// amd64:"NEGQ"
   146  	// arm64:"NEG"
   147  	// loong64:"SUBV"
   148  	// mips:"SUB"
   149  	// mips64:"SUBV"
   150  	// ppc64x:"NEG"
   151  	// riscv64:"NEG",-"SUB"
   152  	r := (a - b) - a
   153  	return r
   154  }
   155  
   156  func SubAddSimplify(a, b int) int {
   157  	// amd64:-"SUBQ",-"ADDQ"
   158  	// arm64:-"SUB",-"ADD"
   159  	// loong64:-"SUBV",-"ADDV"
   160  	// mips:-"SUB",-"ADD"
   161  	// mips64:-"SUBV",-"ADDV"
   162  	// ppc64x:-"SUB",-"ADD"
   163  	// riscv64:-"SUB",-"ADD"
   164  	r := a + (b - a)
   165  	return r
   166  }
   167  
   168  func SubAddSimplify2(a, b, c int) (int, int, int, int, int, int) {
   169  	// amd64:-"ADDQ"
   170  	// arm64:-"ADD"
   171  	// mips:"SUB",-"ADD"
   172  	// mips64:"SUBV",-"ADDV"
   173  	// loong64:"SUBV",-"ADDV"
   174  	r := (a + b) - (a + c)
   175  	// amd64:-"ADDQ"
   176  	r1 := (a + b) - (c + a)
   177  	// amd64:-"ADDQ"
   178  	r2 := (b + a) - (a + c)
   179  	// amd64:-"ADDQ"
   180  	r3 := (b + a) - (c + a)
   181  	// amd64:-"SUBQ"
   182  	// arm64:-"SUB"
   183  	// mips:"ADD",-"SUB"
   184  	// mips64:"ADDV",-"SUBV"
   185  	// loong64:"ADDV",-"SUBV"
   186  	r4 := (a - c) + (c + b)
   187  	// amd64:-"SUBQ"
   188  	r5 := (a - c) + (b + c)
   189  	return r, r1, r2, r3, r4, r5
   190  }
   191  
   192  func SubAddNegSimplify(a, b int) int {
   193  	// amd64:"NEGQ",-"ADDQ",-"SUBQ"
   194  	// arm64:"NEG",-"ADD",-"SUB"
   195  	// loong64:"SUBV",-"ADDV"
   196  	// mips:"SUB",-"ADD"
   197  	// mips64:"SUBV",-"ADDV"
   198  	// ppc64x:"NEG",-"ADD",-"SUB"
   199  	// riscv64:"NEG",-"ADD",-"SUB"
   200  	r := a - (b + a)
   201  	return r
   202  }
   203  
   204  func AddAddSubSimplify(a, b, c int) int {
   205  	// amd64:-"SUBQ"
   206  	// arm64:"ADD",-"SUB"
   207  	// loong64:"ADDV",-"SUBV"
   208  	// mips:"ADD",-"SUB"
   209  	// mips64:"ADDV",-"SUBV"
   210  	// ppc64x:-"SUB"
   211  	// riscv64:"ADD","ADD",-"SUB"
   212  	r := a + (b + (c - a))
   213  	return r
   214  }
   215  
   216  func NegToInt32(a int) int {
   217  	// riscv64: "NEGW",-"MOVW"
   218  	r := int(int32(-a))
   219  	return r
   220  }
   221  
   222  // -------------------- //
   223  //    Multiplication    //
   224  // -------------------- //
   225  
   226  func Pow2Muls(n1, n2 int) (int, int) {
   227  	// amd64:"SHLQ\t[$]5",-"IMULQ"
   228  	// 386:"SHLL\t[$]5",-"IMULL"
   229  	// arm:"SLL\t[$]5",-"MUL"
   230  	// arm64:"LSL\t[$]5",-"MUL"
   231  	// ppc64x:"SLD\t[$]5",-"MUL"
   232  	a := n1 * 32
   233  
   234  	// amd64:"SHLQ\t[$]6",-"IMULQ"
   235  	// 386:"SHLL\t[$]6",-"IMULL"
   236  	// arm:"SLL\t[$]6",-"MUL"
   237  	// arm64:`NEG\sR[0-9]+<<6,\sR[0-9]+`,-`LSL`,-`MUL`
   238  	// ppc64x:"SLD\t[$]6","NEG\\sR[0-9]+,\\sR[0-9]+",-"MUL"
   239  	b := -64 * n2
   240  
   241  	return a, b
   242  }
   243  
   244  func Mul_2(n1 int32, n2 int64) (int32, int64) {
   245  	// amd64:"ADDL", -"SHLL"
   246  	a := n1 * 2
   247  	// amd64:"ADDQ", -"SHLQ"
   248  	b := n2 * 2
   249  
   250  	return a, b
   251  }
   252  
   253  func Mul_96(n int) int {
   254  	// amd64:`SHLQ\t[$]5`,`LEAQ\t\(.*\)\(.*\*2\),`,-`IMULQ`
   255  	// 386:`SHLL\t[$]5`,`LEAL\t\(.*\)\(.*\*2\),`,-`IMULL`
   256  	// arm64:`LSL\t[$]5`,`ADD\sR[0-9]+<<1,\sR[0-9]+`,-`MUL`
   257  	// arm:`SLL\t[$]5`,`ADD\sR[0-9]+<<1,\sR[0-9]+`,-`MUL`
   258  	// s390x:`SLD\t[$]5`,`SLD\t[$]6`,-`MULLD`
   259  	return n * 96
   260  }
   261  
   262  func Mul_n120(n int) int {
   263  	// s390x:`SLD\t[$]3`,`SLD\t[$]7`,-`MULLD`
   264  	return n * -120
   265  }
   266  
   267  func MulMemSrc(a []uint32, b []float32) {
   268  	// 386:`IMULL\s4\([A-Z]+\),\s[A-Z]+`
   269  	a[0] *= a[1]
   270  	// 386/sse2:`MULSS\s4\([A-Z]+\),\sX[0-9]+`
   271  	// amd64:`MULSS\s4\([A-Z]+\),\sX[0-9]+`
   272  	b[0] *= b[1]
   273  }
   274  
   275  // Multiplications merging tests
   276  
   277  func MergeMuls1(n int) int {
   278  	// amd64:"IMUL3Q\t[$]46"
   279  	// 386:"IMUL3L\t[$]46"
   280  	// ppc64x:"MULLD\t[$]46"
   281  	return 15*n + 31*n // 46n
   282  }
   283  
   284  func MergeMuls2(n int) int {
   285  	// amd64:"IMUL3Q\t[$]23","(ADDQ\t[$]29)|(LEAQ\t29)"
   286  	// 386:"IMUL3L\t[$]23","ADDL\t[$]29"
   287  	// ppc64x/power9:"MADDLD",-"MULLD\t[$]23",-"ADD\t[$]29"
   288  	// ppc64x/power8:"MULLD\t[$]23","ADD\t[$]29"
   289  	return 5*n + 7*(n+1) + 11*(n+2) // 23n + 29
   290  }
   291  
   292  func MergeMuls3(a, n int) int {
   293  	// amd64:"ADDQ\t[$]19",-"IMULQ\t[$]19"
   294  	// 386:"ADDL\t[$]19",-"IMULL\t[$]19"
   295  	// ppc64x:"ADD\t[$]19",-"MULLD\t[$]19"
   296  	return a*n + 19*n // (a+19)n
   297  }
   298  
   299  func MergeMuls4(n int) int {
   300  	// amd64:"IMUL3Q\t[$]14"
   301  	// 386:"IMUL3L\t[$]14"
   302  	// ppc64x:"MULLD\t[$]14"
   303  	return 23*n - 9*n // 14n
   304  }
   305  
   306  func MergeMuls5(a, n int) int {
   307  	// amd64:"ADDQ\t[$]-19",-"IMULQ\t[$]19"
   308  	// 386:"ADDL\t[$]-19",-"IMULL\t[$]19"
   309  	// ppc64x:"ADD\t[$]-19",-"MULLD\t[$]19"
   310  	return a*n - 19*n // (a-19)n
   311  }
   312  
   313  // -------------- //
   314  //    Division    //
   315  // -------------- //
   316  
   317  func DivMemSrc(a []float64) {
   318  	// 386/sse2:`DIVSD\s8\([A-Z]+\),\sX[0-9]+`
   319  	// amd64:`DIVSD\s8\([A-Z]+\),\sX[0-9]+`
   320  	a[0] /= a[1]
   321  }
   322  
   323  func Pow2Divs(n1 uint, n2 int) (uint, int) {
   324  	// 386:"SHRL\t[$]5",-"DIVL"
   325  	// amd64:"SHRQ\t[$]5",-"DIVQ"
   326  	// arm:"SRL\t[$]5",-".*udiv"
   327  	// arm64:"LSR\t[$]5",-"UDIV"
   328  	// ppc64x:"SRD"
   329  	a := n1 / 32 // unsigned
   330  
   331  	// amd64:"SARQ\t[$]6",-"IDIVQ"
   332  	// 386:"SARL\t[$]6",-"IDIVL"
   333  	// arm:"SRA\t[$]6",-".*udiv"
   334  	// arm64:"ASR\t[$]6",-"SDIV"
   335  	// ppc64x:"SRAD"
   336  	b := n2 / 64 // signed
   337  
   338  	return a, b
   339  }
   340  
   341  // Check that constant divisions get turned into MULs
   342  func ConstDivs(n1 uint, n2 int) (uint, int) {
   343  	// amd64:"MOVQ\t[$]-1085102592571150095","MULQ",-"DIVQ"
   344  	// 386:"MOVL\t[$]-252645135","MULL",-"DIVL"
   345  	// arm64:`MOVD`,`UMULH`,-`DIV`
   346  	// arm:`MOVW`,`MUL`,-`.*udiv`
   347  	a := n1 / 17 // unsigned
   348  
   349  	// amd64:"MOVQ\t[$]-1085102592571150095","IMULQ",-"IDIVQ"
   350  	// 386:"MOVL\t[$]-252645135","IMULL",-"IDIVL"
   351  	// arm64:`SMULH`,-`DIV`
   352  	// arm:`MOVW`,`MUL`,-`.*udiv`
   353  	b := n2 / 17 // signed
   354  
   355  	return a, b
   356  }
   357  
   358  func FloatDivs(a []float32) float32 {
   359  	// amd64:`DIVSS\s8\([A-Z]+\),\sX[0-9]+`
   360  	// 386/sse2:`DIVSS\s8\([A-Z]+\),\sX[0-9]+`
   361  	return a[1] / a[2]
   362  }
   363  
   364  func Pow2Mods(n1 uint, n2 int) (uint, int) {
   365  	// 386:"ANDL\t[$]31",-"DIVL"
   366  	// amd64:"ANDL\t[$]31",-"DIVQ"
   367  	// arm:"AND\t[$]31",-".*udiv"
   368  	// arm64:"AND\t[$]31",-"UDIV"
   369  	// ppc64x:"RLDICL"
   370  	a := n1 % 32 // unsigned
   371  
   372  	// 386:"SHRL",-"IDIVL"
   373  	// amd64:"SHRQ",-"IDIVQ"
   374  	// arm:"SRA",-".*udiv"
   375  	// arm64:"ASR",-"REM"
   376  	// ppc64x:"SRAD"
   377  	b := n2 % 64 // signed
   378  
   379  	return a, b
   380  }
   381  
   382  // Check that signed divisibility checks get converted to AND on low bits
   383  func Pow2DivisibleSigned(n1, n2 int) (bool, bool) {
   384  	// 386:"TESTL\t[$]63",-"DIVL",-"SHRL"
   385  	// amd64:"TESTQ\t[$]63",-"DIVQ",-"SHRQ"
   386  	// arm:"AND\t[$]63",-".*udiv",-"SRA"
   387  	// arm64:"TST\t[$]63",-"UDIV",-"ASR",-"AND"
   388  	// ppc64x:"ANDCC",-"RLDICL",-"SRAD",-"CMP"
   389  	a := n1%64 == 0 // signed divisible
   390  
   391  	// 386:"TESTL\t[$]63",-"DIVL",-"SHRL"
   392  	// amd64:"TESTQ\t[$]63",-"DIVQ",-"SHRQ"
   393  	// arm:"AND\t[$]63",-".*udiv",-"SRA"
   394  	// arm64:"TST\t[$]63",-"UDIV",-"ASR",-"AND"
   395  	// ppc64x:"ANDCC",-"RLDICL",-"SRAD",-"CMP"
   396  	b := n2%64 != 0 // signed indivisible
   397  
   398  	return a, b
   399  }
   400  
   401  // Check that constant modulo divs get turned into MULs
   402  func ConstMods(n1 uint, n2 int) (uint, int) {
   403  	// amd64:"MOVQ\t[$]-1085102592571150095","MULQ",-"DIVQ"
   404  	// 386:"MOVL\t[$]-252645135","MULL",-"DIVL"
   405  	// arm64:`MOVD`,`UMULH`,-`DIV`
   406  	// arm:`MOVW`,`MUL`,-`.*udiv`
   407  	a := n1 % 17 // unsigned
   408  
   409  	// amd64:"MOVQ\t[$]-1085102592571150095","IMULQ",-"IDIVQ"
   410  	// 386:"MOVL\t[$]-252645135","IMULL",-"IDIVL"
   411  	// arm64:`SMULH`,-`DIV`
   412  	// arm:`MOVW`,`MUL`,-`.*udiv`
   413  	b := n2 % 17 // signed
   414  
   415  	return a, b
   416  }
   417  
   418  // Check that divisibility checks x%c==0 are converted to MULs and rotates
   419  func DivisibleU(n uint) (bool, bool) {
   420  	// amd64:"MOVQ\t[$]-6148914691236517205","IMULQ","ROLQ\t[$]63",-"DIVQ"
   421  	// 386:"IMUL3L\t[$]-1431655765","ROLL\t[$]31",-"DIVQ"
   422  	// arm64:"MOVD\t[$]-6148914691236517205","MOVD\t[$]3074457345618258602","MUL","ROR",-"DIV"
   423  	// arm:"MUL","CMP\t[$]715827882",-".*udiv"
   424  	// ppc64x:"MULLD","ROTL\t[$]63"
   425  	even := n%6 == 0
   426  
   427  	// amd64:"MOVQ\t[$]-8737931403336103397","IMULQ",-"ROLQ",-"DIVQ"
   428  	// 386:"IMUL3L\t[$]678152731",-"ROLL",-"DIVQ"
   429  	// arm64:"MOVD\t[$]-8737931403336103397","MUL",-"ROR",-"DIV"
   430  	// arm:"MUL","CMP\t[$]226050910",-".*udiv"
   431  	// ppc64x:"MULLD",-"ROTL"
   432  	odd := n%19 == 0
   433  
   434  	return even, odd
   435  }
   436  
   437  func Divisible(n int) (bool, bool) {
   438  	// amd64:"IMULQ","ADD","ROLQ\t[$]63",-"DIVQ"
   439  	// 386:"IMUL3L\t[$]-1431655765","ADDL\t[$]715827882","ROLL\t[$]31",-"DIVQ"
   440  	// arm64:"MOVD\t[$]-6148914691236517205","MOVD\t[$]3074457345618258602","MUL","ADD\tR","ROR",-"DIV"
   441  	// arm:"MUL","ADD\t[$]715827882",-".*udiv"
   442  	// ppc64x/power8:"MULLD","ADD","ROTL\t[$]63"
   443  	// ppc64x/power9:"MADDLD","ROTL\t[$]63"
   444  	even := n%6 == 0
   445  
   446  	// amd64:"IMULQ","ADD",-"ROLQ",-"DIVQ"
   447  	// 386:"IMUL3L\t[$]678152731","ADDL\t[$]113025455",-"ROLL",-"DIVQ"
   448  	// arm64:"MUL","MOVD\t[$]485440633518672410","ADD",-"ROR",-"DIV"
   449  	// arm:"MUL","ADD\t[$]113025455",-".*udiv"
   450  	// ppc64x/power8:"MULLD","ADD",-"ROTL"
   451  	// ppc64x/power9:"MADDLD",-"ROTL"
   452  	odd := n%19 == 0
   453  
   454  	return even, odd
   455  }
   456  
   457  // Check that fix-up code is not generated for divisions where it has been proven that
   458  // that the divisor is not -1 or that the dividend is > MinIntNN.
   459  func NoFix64A(divr int64) (int64, int64) {
   460  	var d int64 = 42
   461  	var e int64 = 84
   462  	if divr > 5 {
   463  		d /= divr // amd64:-"JMP"
   464  		e %= divr // amd64:-"JMP"
   465  		// The following statement is to avoid conflict between the above check
   466  		// and the normal JMP generated at the end of the block.
   467  		d += e
   468  	}
   469  	return d, e
   470  }
   471  
   472  func NoFix64B(divd int64) (int64, int64) {
   473  	var d int64
   474  	var e int64
   475  	var divr int64 = -1
   476  	if divd > -9223372036854775808 {
   477  		d = divd / divr // amd64:-"JMP"
   478  		e = divd % divr // amd64:-"JMP"
   479  		d += e
   480  	}
   481  	return d, e
   482  }
   483  
   484  func NoFix32A(divr int32) (int32, int32) {
   485  	var d int32 = 42
   486  	var e int32 = 84
   487  	if divr > 5 {
   488  		// amd64:-"JMP"
   489  		// 386:-"JMP"
   490  		d /= divr
   491  		// amd64:-"JMP"
   492  		// 386:-"JMP"
   493  		e %= divr
   494  		d += e
   495  	}
   496  	return d, e
   497  }
   498  
   499  func NoFix32B(divd int32) (int32, int32) {
   500  	var d int32
   501  	var e int32
   502  	var divr int32 = -1
   503  	if divd > -2147483648 {
   504  		// amd64:-"JMP"
   505  		// 386:-"JMP"
   506  		d = divd / divr
   507  		// amd64:-"JMP"
   508  		// 386:-"JMP"
   509  		e = divd % divr
   510  		d += e
   511  	}
   512  	return d, e
   513  }
   514  
   515  func NoFix16A(divr int16) (int16, int16) {
   516  	var d int16 = 42
   517  	var e int16 = 84
   518  	if divr > 5 {
   519  		// amd64:-"JMP"
   520  		// 386:-"JMP"
   521  		d /= divr
   522  		// amd64:-"JMP"
   523  		// 386:-"JMP"
   524  		e %= divr
   525  		d += e
   526  	}
   527  	return d, e
   528  }
   529  
   530  func NoFix16B(divd int16) (int16, int16) {
   531  	var d int16
   532  	var e int16
   533  	var divr int16 = -1
   534  	if divd > -32768 {
   535  		// amd64:-"JMP"
   536  		// 386:-"JMP"
   537  		d = divd / divr
   538  		// amd64:-"JMP"
   539  		// 386:-"JMP"
   540  		e = divd % divr
   541  		d += e
   542  	}
   543  	return d, e
   544  }
   545  
   546  // Check that len() and cap() calls divided by powers of two are
   547  // optimized into shifts and ands
   548  
   549  func LenDiv1(a []int) int {
   550  	// 386:"SHRL\t[$]10"
   551  	// amd64:"SHRQ\t[$]10"
   552  	// arm64:"LSR\t[$]10",-"SDIV"
   553  	// arm:"SRL\t[$]10",-".*udiv"
   554  	// ppc64x:"SRD"\t[$]10"
   555  	return len(a) / 1024
   556  }
   557  
   558  func LenDiv2(s string) int {
   559  	// 386:"SHRL\t[$]11"
   560  	// amd64:"SHRQ\t[$]11"
   561  	// arm64:"LSR\t[$]11",-"SDIV"
   562  	// arm:"SRL\t[$]11",-".*udiv"
   563  	// ppc64x:"SRD\t[$]11"
   564  	return len(s) / (4097 >> 1)
   565  }
   566  
   567  func LenMod1(a []int) int {
   568  	// 386:"ANDL\t[$]1023"
   569  	// amd64:"ANDL\t[$]1023"
   570  	// arm64:"AND\t[$]1023",-"SDIV"
   571  	// arm/6:"AND",-".*udiv"
   572  	// arm/7:"BFC",-".*udiv",-"AND"
   573  	// ppc64x:"RLDICL"
   574  	return len(a) % 1024
   575  }
   576  
   577  func LenMod2(s string) int {
   578  	// 386:"ANDL\t[$]2047"
   579  	// amd64:"ANDL\t[$]2047"
   580  	// arm64:"AND\t[$]2047",-"SDIV"
   581  	// arm/6:"AND",-".*udiv"
   582  	// arm/7:"BFC",-".*udiv",-"AND"
   583  	// ppc64x:"RLDICL"
   584  	return len(s) % (4097 >> 1)
   585  }
   586  
   587  func CapDiv(a []int) int {
   588  	// 386:"SHRL\t[$]12"
   589  	// amd64:"SHRQ\t[$]12"
   590  	// arm64:"LSR\t[$]12",-"SDIV"
   591  	// arm:"SRL\t[$]12",-".*udiv"
   592  	// ppc64x:"SRD\t[$]12"
   593  	return cap(a) / ((1 << 11) + 2048)
   594  }
   595  
   596  func CapMod(a []int) int {
   597  	// 386:"ANDL\t[$]4095"
   598  	// amd64:"ANDL\t[$]4095"
   599  	// arm64:"AND\t[$]4095",-"SDIV"
   600  	// arm/6:"AND",-".*udiv"
   601  	// arm/7:"BFC",-".*udiv",-"AND"
   602  	// ppc64x:"RLDICL"
   603  	return cap(a) % ((1 << 11) + 2048)
   604  }
   605  
   606  func AddMul(x int) int {
   607  	// amd64:"LEAQ\t1"
   608  	return 2*x + 1
   609  }
   610  
   611  func MULA(a, b, c uint32) (uint32, uint32, uint32) {
   612  	// arm:`MULA`,-`MUL\s`
   613  	// arm64:`MADDW`,-`MULW`
   614  	r0 := a*b + c
   615  	// arm:`MULA`,-`MUL\s`
   616  	// arm64:`MADDW`,-`MULW`
   617  	r1 := c*79 + a
   618  	// arm:`ADD`,-`MULA`,-`MUL\s`
   619  	// arm64:`ADD`,-`MADD`,-`MULW`
   620  	// ppc64x:`ADD`,-`MULLD`
   621  	r2 := b*64 + c
   622  	return r0, r1, r2
   623  }
   624  
   625  func MULS(a, b, c uint32) (uint32, uint32, uint32) {
   626  	// arm/7:`MULS`,-`MUL\s`
   627  	// arm/6:`SUB`,`MUL\s`,-`MULS`
   628  	// arm64:`MSUBW`,-`MULW`
   629  	r0 := c - a*b
   630  	// arm/7:`MULS`,-`MUL\s`
   631  	// arm/6:`SUB`,`MUL\s`,-`MULS`
   632  	// arm64:`MSUBW`,-`MULW`
   633  	r1 := a - c*79
   634  	// arm/7:`SUB`,-`MULS`,-`MUL\s`
   635  	// arm64:`SUB`,-`MSUBW`,-`MULW`
   636  	// ppc64x:`SUB`,-`MULLD`
   637  	r2 := c - b*64
   638  	return r0, r1, r2
   639  }
   640  
   641  func addSpecial(a, b, c uint32) (uint32, uint32, uint32) {
   642  	// amd64:`INCL`
   643  	a++
   644  	// amd64:`DECL`
   645  	b--
   646  	// amd64:`SUBL.*-128`
   647  	c += 128
   648  	return a, b, c
   649  }
   650  
   651  // Divide -> shift rules usually require fixup for negative inputs.
   652  // If the input is non-negative, make sure the fixup is eliminated.
   653  func divInt(v int64) int64 {
   654  	if v < 0 {
   655  		return 0
   656  	}
   657  	// amd64:-`.*SARQ.*63,`, -".*SHRQ", ".*SARQ.*[$]9,"
   658  	return v / 512
   659  }
   660  
   661  // The reassociate rules "x - (z + C) -> (x - z) - C" and
   662  // "(z + C) -x -> C + (z - x)" can optimize the following cases.
   663  func constantFold1(i0, j0, i1, j1, i2, j2, i3, j3 int) (int, int, int, int) {
   664  	// arm64:"SUB","ADD\t[$]2"
   665  	// ppc64x:"SUB","ADD\t[$]2"
   666  	r0 := (i0 + 3) - (j0 + 1)
   667  	// arm64:"SUB","SUB\t[$]4"
   668  	// ppc64x:"SUB","ADD\t[$]-4"
   669  	r1 := (i1 - 3) - (j1 + 1)
   670  	// arm64:"SUB","ADD\t[$]4"
   671  	// ppc64x:"SUB","ADD\t[$]4"
   672  	r2 := (i2 + 3) - (j2 - 1)
   673  	// arm64:"SUB","SUB\t[$]2"
   674  	// ppc64x:"SUB","ADD\t[$]-2"
   675  	r3 := (i3 - 3) - (j3 - 1)
   676  	return r0, r1, r2, r3
   677  }
   678  
   679  // The reassociate rules "x - (z + C) -> (x - z) - C" and
   680  // "(C - z) - x -> C - (z + x)" can optimize the following cases.
   681  func constantFold2(i0, j0, i1, j1 int) (int, int) {
   682  	// arm64:"ADD","MOVD\t[$]2","SUB"
   683  	// ppc64x: `SUBC\tR[0-9]+,\s[$]2,\sR`
   684  	r0 := (3 - i0) - (j0 + 1)
   685  	// arm64:"ADD","MOVD\t[$]4","SUB"
   686  	// ppc64x: `SUBC\tR[0-9]+,\s[$]4,\sR`
   687  	r1 := (3 - i1) - (j1 - 1)
   688  	return r0, r1
   689  }
   690  
   691  func constantFold3(i, j int) int {
   692  	// arm64: "LSL\t[$]5,","SUB\tR[0-9]+<<1,",-"ADD"
   693  	// ppc64x:"MULLD\t[$]30","MULLD"
   694  	r := (5 * i) * (6 * j)
   695  	return r
   696  }
   697  
   698  // ----------------- //
   699  //  Integer Min/Max  //
   700  // ----------------- //
   701  
   702  func Int64Min(a, b int64) int64 {
   703  	// amd64: "CMPQ","CMOVQLT"
   704  	// arm64: "CMP","CSEL"
   705  	// riscv64/rva20u64:"BLT\t"
   706  	// riscv64/rva22u64,riscv64/rva23u64:"MIN\t"
   707  	return min(a, b)
   708  }
   709  
   710  func Int64Max(a, b int64) int64 {
   711  	// amd64: "CMPQ","CMOVQGT"
   712  	// arm64: "CMP","CSEL"
   713  	// riscv64/rva20u64:"BLT\t"
   714  	// riscv64/rva22u64,riscv64/rva23u64:"MAX\t"
   715  	return max(a, b)
   716  }
   717  
   718  func Uint64Min(a, b uint64) uint64 {
   719  	// amd64: "CMPQ","CMOVQCS"
   720  	// arm64: "CMP","CSEL"
   721  	// riscv64/rva20u64:"BLTU"
   722  	// riscv64/rva22u64,riscv64/rva23u64:"MINU"
   723  	return min(a, b)
   724  }
   725  
   726  func Uint64Max(a, b uint64) uint64 {
   727  	// amd64: "CMPQ","CMOVQHI"
   728  	// arm64: "CMP","CSEL"
   729  	// riscv64/rva20u64:"BLTU"
   730  	// riscv64/rva22u64,riscv64/rva23u64:"MAXU"
   731  	return max(a, b)
   732  }
   733  

View as plain text