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

View as plain text