Source file test/codegen/condmove.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  import (
    10  	"crypto/subtle"
    11  	"math/bits"
    12  )
    13  
    14  func cmovint(c int) int {
    15  	x := c + 4
    16  	if x < 0 {
    17  		x = 182
    18  	}
    19  	// amd64:"CMOVQLT"
    20  	// arm64:"CSEL LT"
    21  	// ppc64x:"ISEL [$]0"
    22  	// wasm:"Select"
    23  	return x
    24  }
    25  
    26  func cmovchan(x, y chan int) chan int {
    27  	if x != y {
    28  		x = y
    29  	}
    30  	// amd64:"CMOVQNE"
    31  	// arm64:"CSEL NE"
    32  	// ppc64x:"ISEL [$]2"
    33  	// wasm:"Select"
    34  	return x
    35  }
    36  
    37  func cmovuintptr(x, y uintptr) uintptr {
    38  	if x < y {
    39  		x = -y
    40  	}
    41  	// amd64:"CMOVQ(HI|CS)"
    42  	// arm64:"CSNEG LS"
    43  	// ppc64x:"ISEL [$]1"
    44  	// wasm:"Select"
    45  	return x
    46  }
    47  
    48  func cmov32bit(x, y uint32) uint32 {
    49  	if x < y {
    50  		x = -y
    51  	}
    52  	// amd64:"CMOVL(HI|CS)"
    53  	// arm64:"CSNEG (LS|HS)"
    54  	// ppc64x:"ISEL [$]1"
    55  	// wasm:"Select"
    56  	return x
    57  }
    58  
    59  func cmov16bit(x, y uint16) uint16 {
    60  	if x < y {
    61  		x = -y
    62  	}
    63  	// amd64:"CMOVW(HI|CS)"
    64  	// arm64:"CSNEG (LS|HS)"
    65  	// ppc64x:"ISEL [$][01]"
    66  	// wasm:"Select"
    67  	return x
    68  }
    69  
    70  // Floating point comparison. For EQ/NE, we must
    71  // generate special code to handle NaNs.
    72  func cmovfloateq(x, y float64) int {
    73  	a := 128
    74  	if x == y {
    75  		a = 256
    76  	}
    77  	// amd64:"CMOVQNE" "CMOVQPC"
    78  	// arm64:"CSEL EQ"
    79  	// ppc64x:"ISEL [$]2"
    80  	// wasm:"Select"
    81  	return a
    82  }
    83  
    84  func cmovfloatne(x, y float64) int {
    85  	a := 128
    86  	if x != y {
    87  		a = 256
    88  	}
    89  	// amd64:"CMOVQNE" "CMOVQPS"
    90  	// arm64:"CSEL NE"
    91  	// ppc64x:"ISEL [$]2"
    92  	// wasm:"Select"
    93  	return a
    94  }
    95  
    96  //go:noinline
    97  func frexp(f float64) (frac float64, exp int) {
    98  	return 1.0, 4
    99  }
   100  
   101  //go:noinline
   102  func ldexp(frac float64, exp int) float64 {
   103  	return 1.0
   104  }
   105  
   106  // Generate a CMOV with a floating comparison and integer move.
   107  func cmovfloatint2(x, y float64) float64 {
   108  	yfr, yexp := 4.0, 5
   109  
   110  	r := x
   111  	for r >= y {
   112  		rfr, rexp := frexp(r)
   113  		if rfr < yfr {
   114  			rexp = rexp - 42
   115  		}
   116  		// amd64:"CMOVQHI"
   117  		// arm64:"CSEL MI"
   118  		// ppc64x:"ISEL [$]0"
   119  		// wasm:"Select"
   120  		r = r - ldexp(y, rexp-yexp)
   121  	}
   122  	return r
   123  }
   124  
   125  func cmovloaded(x [4]int, y int) int {
   126  	if x[2] != 0 {
   127  		y = x[2]
   128  	} else {
   129  		y = y >> 2
   130  	}
   131  	// amd64:"CMOVQNE"
   132  	// arm64:"CSEL NE"
   133  	// ppc64x:"ISEL [$]2"
   134  	// wasm:"Select"
   135  	return y
   136  }
   137  
   138  func cmovuintptr2(x, y uintptr) uintptr {
   139  	a := x * 2
   140  	if a == 0 {
   141  		a = 256
   142  	}
   143  	// amd64:"CMOVQEQ"
   144  	// arm64:"CSEL EQ"
   145  	// ppc64x:"ISEL [$]2"
   146  	// wasm:"Select"
   147  	return a
   148  }
   149  
   150  // Floating point CMOVs are not supported by amd64/arm64/ppc64x
   151  func cmovfloatmove(x, y int) float64 {
   152  	a := 1.0
   153  	if x <= y {
   154  		a = 2.0
   155  	}
   156  	// amd64:-"CMOV"
   157  	// arm64:-"CSEL"
   158  	// ppc64x:-"ISEL"
   159  	// wasm:-"Select"
   160  	return a
   161  }
   162  
   163  // On amd64, the following patterns trigger comparison inversion.
   164  // Test that we correctly invert the CMOV condition
   165  var gsink int64
   166  var gusink uint64
   167  
   168  func cmovinvert1(x, y int64) int64 {
   169  	if x < gsink {
   170  		y = -y
   171  	}
   172  	// amd64:"CMOVQGT"
   173  	return y
   174  }
   175  func cmovinvert2(x, y int64) int64 {
   176  	if x <= gsink {
   177  		y = -y
   178  	}
   179  	// amd64:"CMOVQGE"
   180  	return y
   181  }
   182  func cmovinvert3(x, y int64) int64 {
   183  	if x == gsink {
   184  		y = -y
   185  	}
   186  	// amd64:"CMOVQEQ"
   187  	return y
   188  }
   189  func cmovinvert4(x, y int64) int64 {
   190  	if x != gsink {
   191  		y = -y
   192  	}
   193  	// amd64:"CMOVQNE"
   194  	return y
   195  }
   196  func cmovinvert5(x, y uint64) uint64 {
   197  	if x > gusink {
   198  		y = -y
   199  	}
   200  	// amd64:"CMOVQCS"
   201  	return y
   202  }
   203  func cmovinvert6(x, y uint64) uint64 {
   204  	if x >= gusink {
   205  		y = -y
   206  	}
   207  	// amd64:"CMOVQLS"
   208  	return y
   209  }
   210  
   211  func cmovload(a []int, i int, b bool) int {
   212  	if b {
   213  		i += 42
   214  	}
   215  	// See issue 26306
   216  	// amd64:-"CMOVQNE"
   217  	return a[i]
   218  }
   219  
   220  func cmovstore(a []int, i int, b bool) {
   221  	if b {
   222  		i += 42
   223  	}
   224  	// amd64:"CMOVQNE"
   225  	a[i] = 7
   226  }
   227  
   228  var r0, r1, r2, r3, r4, r5 int
   229  
   230  func cmovinc(cond bool, a, b, c int) {
   231  	var x0, x1 int
   232  
   233  	if cond {
   234  		x0 = a
   235  	} else {
   236  		x0 = b + 1
   237  	}
   238  	// arm64:"CSINC NE" -"CSEL"
   239  	r0 = x0
   240  
   241  	if cond {
   242  		x1 = b + 1
   243  	} else {
   244  		x1 = a
   245  	}
   246  	// arm64:"CSINC EQ" -"CSEL"
   247  	r1 = x1
   248  
   249  	if cond {
   250  		c++
   251  	}
   252  	// arm64:"CSINC EQ" -"CSEL"
   253  	r2 = c
   254  }
   255  
   256  func cmovinv(cond bool, a, b int) {
   257  	var x0, x1 int
   258  
   259  	if cond {
   260  		x0 = a
   261  	} else {
   262  		x0 = ^b
   263  	}
   264  	// arm64:"CSINV NE" -"CSEL"
   265  	r0 = x0
   266  
   267  	if cond {
   268  		x1 = ^b
   269  	} else {
   270  		x1 = a
   271  	}
   272  	// arm64:"CSINV EQ" -"CSEL"
   273  	r1 = x1
   274  }
   275  
   276  func cmovneg(cond bool, a, b, c int) {
   277  	var x0, x1 int
   278  
   279  	if cond {
   280  		x0 = a
   281  	} else {
   282  		x0 = -b
   283  	}
   284  	// arm64:"CSNEG NE" -"CSEL"
   285  	r0 = x0
   286  
   287  	if cond {
   288  		x1 = -b
   289  	} else {
   290  		x1 = a
   291  	}
   292  	// arm64:"CSNEG EQ" -"CSEL"
   293  	r1 = x1
   294  }
   295  
   296  func cmovsetm(cond bool, x int) {
   297  	var x0, x1 int
   298  
   299  	if cond {
   300  		x0 = -1
   301  	} else {
   302  		x0 = 0
   303  	}
   304  	// arm64:"CSETM NE" -"CSEL"
   305  	r0 = x0
   306  
   307  	if cond {
   308  		x1 = 0
   309  	} else {
   310  		x1 = -1
   311  	}
   312  	// arm64:"CSETM EQ" -"CSEL"
   313  	r1 = x1
   314  }
   315  
   316  func cmovFcmp0(s, t float64, a, b int) {
   317  	var x0, x1, x2, x3, x4, x5 int
   318  
   319  	if s < t {
   320  		x0 = a
   321  	} else {
   322  		x0 = b + 1
   323  	}
   324  	// arm64:"CSINC MI" -"CSEL"
   325  	r0 = x0
   326  
   327  	if s <= t {
   328  		x1 = a
   329  	} else {
   330  		x1 = ^b
   331  	}
   332  	// arm64:"CSINV LS" -"CSEL"
   333  	r1 = x1
   334  
   335  	if s > t {
   336  		x2 = a
   337  	} else {
   338  		x2 = -b
   339  	}
   340  	// arm64:"CSNEG MI" -"CSEL"
   341  	r2 = x2
   342  
   343  	if s >= t {
   344  		x3 = -1
   345  	} else {
   346  		x3 = 0
   347  	}
   348  	// arm64:"CSETM LS" -"CSEL"
   349  	r3 = x3
   350  
   351  	if s == t {
   352  		x4 = a
   353  	} else {
   354  		x4 = b + 1
   355  	}
   356  	// arm64:"CSINC EQ" -"CSEL"
   357  	r4 = x4
   358  
   359  	if s != t {
   360  		x5 = a
   361  	} else {
   362  		x5 = b + 1
   363  	}
   364  	// arm64:"CSINC NE" -"CSEL"
   365  	r5 = x5
   366  }
   367  
   368  func cmovFcmp1(s, t float64, a, b int) {
   369  	var x0, x1, x2, x3, x4, x5 int
   370  
   371  	if s < t {
   372  		x0 = b + 1
   373  	} else {
   374  		x0 = a
   375  	}
   376  	// arm64:"CSINC PL" -"CSEL"
   377  	r0 = x0
   378  
   379  	if s <= t {
   380  		x1 = ^b
   381  	} else {
   382  		x1 = a
   383  	}
   384  	// arm64:"CSINV HI" -"CSEL"
   385  	r1 = x1
   386  
   387  	if s > t {
   388  		x2 = -b
   389  	} else {
   390  		x2 = a
   391  	}
   392  	// arm64:"CSNEG PL" -"CSEL"
   393  	r2 = x2
   394  
   395  	if s >= t {
   396  		x3 = 0
   397  	} else {
   398  		x3 = -1
   399  	}
   400  	// arm64:"CSETM HI" -"CSEL"
   401  	r3 = x3
   402  
   403  	if s == t {
   404  		x4 = b + 1
   405  	} else {
   406  		x4 = a
   407  	}
   408  	// arm64:"CSINC NE" -"CSEL"
   409  	r4 = x4
   410  
   411  	if s != t {
   412  		x5 = b + 1
   413  	} else {
   414  		x5 = a
   415  	}
   416  	// arm64:"CSINC EQ" -"CSEL"
   417  	r5 = x5
   418  }
   419  
   420  func cmovzero1(c bool) int {
   421  	var x int
   422  	if c {
   423  		x = 182
   424  	}
   425  	// loong64:"MASKEQZ" -"MASKNEZ"
   426  	return x
   427  }
   428  
   429  func cmovzero2(c bool) int {
   430  	var x int
   431  	if !c {
   432  		x = 182
   433  	}
   434  	// loong64:"MASKNEZ" -"MASKEQZ"
   435  	return x
   436  }
   437  
   438  // Conditionally selecting between a value or 0 can be done without
   439  // an extra load of 0 to a register on PPC64 by using R0 (which always
   440  // holds the value $0) instead. Verify both cases where either arg1
   441  // or arg2 is zero.
   442  func cmovzeroreg0(a, b int) int {
   443  	x := 0
   444  	if a == b {
   445  		x = a
   446  	}
   447  	// ppc64x:"ISEL [$]2, R[0-9]+, R0, R[0-9]+"
   448  	return x
   449  }
   450  
   451  func cmovzeroreg1(a, b int) int {
   452  	x := a
   453  	if a == b {
   454  		x = 0
   455  	}
   456  	// ppc64x:"ISEL [$]2, R0, R[0-9]+, R[0-9]+"
   457  	return x
   458  }
   459  
   460  func cmovmathadd(a uint, b bool) uint {
   461  	if b {
   462  		a++
   463  	}
   464  	// amd64:"ADDQ" -"CMOV"
   465  	// arm64:"CSINC" -"CSEL"
   466  	// ppc64x:"ADD" -"ISEL"
   467  	// wasm:"I64Add" -"Select"
   468  	return a
   469  }
   470  func cmovmathaddelse(a uint, b bool) uint {
   471  	if !b {
   472  		a++
   473  	}
   474  	// amd64:"ADDQ" -"CMOV"
   475  	// arm64:"CSINC" -"CSEL"
   476  	// ppc64x:"ADD" -"ISEL"
   477  	// wasm:"I64Add" -"Select"
   478  	return a
   479  }
   480  
   481  func cmovmathadd2(a uint, b bool) uint {
   482  	if b {
   483  		a += 2
   484  	}
   485  	// amd64:"LEAQ" -"CMOV" -"MUL"
   486  	// arm64:"ADD R[0-9]+<<1" -"CSEL" -"MUL"
   487  	// ppc64x: "ISEL" -"MUL"
   488  	return a
   489  }
   490  func cmovmathadd2else(a uint, b bool) uint {
   491  	if !b {
   492  		a += 2
   493  	}
   494  	// amd64:"LEAQ" -"CMOV" -"MUL"
   495  	// arm64:"ADD R[0-9]+<<1" -"CSEL" -"MUL"
   496  	// ppc64x: "ISEL" -"MUL"
   497  	return a
   498  }
   499  
   500  func cmovmathadd4(a uint, b bool) uint {
   501  	if b {
   502  		a += 4
   503  	}
   504  	// amd64:"LEAQ" -"CMOV" -"MUL"
   505  	// arm64:"ADD R[0-9]+<<2" -"CSEL" -"MUL"
   506  	// ppc64x: "ISEL" -"MUL"
   507  	return a
   508  }
   509  func cmovmathadd4else(a uint, b bool) uint {
   510  	if !b {
   511  		a += 4
   512  	}
   513  	// amd64:"LEAQ" -"CMOV" -"MUL"
   514  	// arm64:"ADD R[0-9]+<<2" -"CSEL" -"MUL"
   515  	// ppc64x: "ISEL" -"MUL"
   516  	return a
   517  }
   518  
   519  func cmovmathadd8(a uint, b bool) uint {
   520  	if b {
   521  		a += 8
   522  	}
   523  	// amd64:"LEAQ" -"CMOV" -"MUL"
   524  	// arm64:"ADD R[0-9]+<<3" -"CSEL" -"MUL"
   525  	// ppc64x: "ISEL" -"MUL"
   526  	return a
   527  }
   528  func cmovmathadd8else(a uint, b bool) uint {
   529  	if !b {
   530  		a += 8
   531  	}
   532  	// amd64:"LEAQ" -"CMOV" -"MUL"
   533  	// arm64:"ADD R[0-9]+<<3" -"CSEL" -"MUL"
   534  	// ppc64x: "ISEL" -"MUL"
   535  	return a
   536  }
   537  
   538  func cmovmathadd9223372036854775808(a uint, b bool) uint {
   539  	if b {
   540  		a += 1 << 63
   541  	}
   542  	// arm64:"ADD R[0-9]+<<63" -"CSEL" -"MUL"
   543  	// ppc64x: "ISEL" -"MUL"
   544  	return a
   545  }
   546  func cmovmathadd9223372036854775808else(a uint, b bool) uint {
   547  	if !b {
   548  		a += 1 << 63
   549  	}
   550  	// arm64:"ADD R[0-9]+<<63" -"CSEL" -"MUL"
   551  	// ppc64x: "ISEL" -"MUL"
   552  	return a
   553  }
   554  
   555  func cmovmathsub(a uint, b bool) uint {
   556  	if b {
   557  		a--
   558  	}
   559  	// amd64:"SUBQ" -"CMOV"
   560  	// arm64:"SUB" -"CSEL"
   561  	// ppc64x:"SUB" -"ISEL"
   562  	// wasm:"I64Sub" -"Select"
   563  	return a
   564  }
   565  func cmovmathsubelse(a uint, b bool) uint {
   566  	if !b {
   567  		a--
   568  	}
   569  	// amd64:"SUBQ" -"CMOV"
   570  	// arm64:"SUB" -"CSEL"
   571  	// ppc64x:"SUB" -"ISEL"
   572  	// wasm:"I64Sub" -"Select"
   573  	return a
   574  }
   575  
   576  func cmovmathsub2(a uint, b bool) uint {
   577  	if b {
   578  		a -= 2
   579  	}
   580  	// arm64 :"SUB R[0-9]+<<1" -"CSEL" -"MUL"
   581  	// ppc64x: "ISEL" -"MUL"
   582  	return a
   583  }
   584  func cmovmathsub2else(a uint, b bool) uint {
   585  	if !b {
   586  		a -= 2
   587  	}
   588  	// arm64 :"SUB R[0-9]+<<1" -"CSEL" -"MUL"
   589  	// ppc64x: "ISEL" -"MUL"
   590  	return a
   591  }
   592  
   593  // Theses two are special because in fixed width two's complement -(1<<(size-1)) == 1<<(size-1).
   594  // It doesn't matter if they are implemented with SUB or ADD.
   595  func cmovmathsub9223372036854775808(a uint, b bool) uint {
   596  	if b {
   597  		a -= 1 << 63
   598  	}
   599  	// arm64:"(SUB|ADD) R[0-9]+<<63" -"CSEL" -"MUL"
   600  	// ppc64x: "ISEL" -"MUL"
   601  	return a
   602  }
   603  func cmovmathsub9223372036854775808else(a uint, b bool) uint {
   604  	if !b {
   605  		a -= 1 << 63
   606  	}
   607  	// arm64:"(SUB|ADD) R[0-9]+<<63" -"CSEL" -"MUL"
   608  	// ppc64x: "ISEL" -"MUL"
   609  	return a
   610  }
   611  
   612  func cmovmathdouble(a uint, b bool) uint {
   613  	if b {
   614  		a *= 2
   615  	}
   616  	// amd64:"SHL" -"CMOV"
   617  	// amd64/v3:"SHL" -"CMOV" -"MOV"
   618  	// arm64:"LSL" -"CSEL"
   619  	// wasm:"I64Shl" -"Select"
   620  	return a
   621  }
   622  func cmovmathdoubleelse(a uint, b bool) uint {
   623  	if !b {
   624  		a *= 2
   625  	}
   626  	// amd64:"SHL" -"CMOV"
   627  	// amd64/v3:"SHL" -"CMOV" -"MOV"
   628  	// arm64:"LSL" -"CSEL"
   629  	// wasm:"I64Shl" -"Select"
   630  	return a
   631  }
   632  
   633  func cmovmathhalvei(a int, b bool) int {
   634  	if b {
   635  		// For some reason the compiler attributes the shift to inside this block rather than where the Phi node is.
   636  		// arm64:"ASR" -"CSEL"
   637  		// wasm:"I64ShrS" -"Select"
   638  		a /= 2
   639  	}
   640  	// arm64:-"CSEL"
   641  	// wasm:-"Select"
   642  	return a
   643  }
   644  func cmovmathhalveielse(a int, b bool) int {
   645  	if !b {
   646  		// For some reason the compiler attributes the shift to inside this block rather than where the Phi node is.
   647  		// arm64:"ASR" -"CSEL"
   648  		// wasm:"I64ShrS" -"Select"
   649  		a /= 2
   650  	}
   651  	// arm64:-"CSEL"
   652  	// wasm:-"Select"
   653  	return a
   654  }
   655  
   656  func cmovmathhalveu(a uint, b bool) uint {
   657  	if b {
   658  		a /= 2
   659  	}
   660  	// amd64:"SHR" -"CMOV"
   661  	// amd64/v3:"SHR" -"CMOV" -"MOV"
   662  	// arm64:"LSR" -"CSEL"
   663  	// wasm:"I64ShrU" -"Select"
   664  	return a
   665  }
   666  func cmovmathhalveuelse(a uint, b bool) uint {
   667  	if !b {
   668  		a /= 2
   669  	}
   670  	// amd64:"SHR" -"CMOV"
   671  	// amd64/v3:"SHR" -"CMOV" -"MOV"
   672  	// arm64:"LSR" -"CSEL"
   673  	// wasm:"I64ShrU" -"Select"
   674  	return a
   675  }
   676  
   677  func cmovmathor(a uint, b bool) uint {
   678  	if b {
   679  		a |= 1
   680  	}
   681  	// amd64:"ORQ" -"CMOV"
   682  	// arm64:"ORR" -"CSEL"
   683  	// ppc64x:"OR" -"ISEL"
   684  	// wasm:"I64Or" -"Select"
   685  	return a
   686  }
   687  func cmovmathorelse(a uint, b bool) uint {
   688  	if !b {
   689  		a |= 1
   690  	}
   691  	// amd64:"ORQ" -"CMOV"
   692  	// arm64:"ORR" -"CSEL"
   693  	// ppc64x:"OR" -"ISEL"
   694  	// wasm:"I64Or" -"Select"
   695  	return a
   696  }
   697  
   698  func cmovmathor2(a uint, b bool) uint {
   699  	if b {
   700  		a |= 2
   701  	}
   702  	// arm64:"ORR R[0-9]+<<1" -"CSEL" -"MUL"
   703  	// ppc64x:"ISEL" -"MUL"
   704  	return a
   705  }
   706  func cmovmathor2else(a uint, b bool) uint {
   707  	if !b {
   708  		a |= 2
   709  	}
   710  	// arm64:"ORR R[0-9]+<<1" -"CSEL" -"MUL"
   711  	// ppc64x:"ISEL" -"MUL"
   712  	return a
   713  }
   714  
   715  func cmovmathor9223372036854775808(a uint, b bool) uint {
   716  	if b {
   717  		a |= 1 << 63
   718  	}
   719  	// arm64:"ORR R[0-9]+<<63" -"CSEL" -"MUL"
   720  	// ppc64x:"ISEL" -"MUL"
   721  	return a
   722  }
   723  func cmovmathor9223372036854775808else(a uint, b bool) uint {
   724  	if !b {
   725  		a |= 1 << 63
   726  	}
   727  	// arm64:"ORR R[0-9]+<<63" -"CSEL" -"MUL"
   728  	// ppc64x:"ISEL" -"MUL"
   729  	return a
   730  }
   731  
   732  func cmovmathxor(a uint, b bool) uint {
   733  	if b {
   734  		a ^= 1
   735  	}
   736  	// amd64:"XORQ" -"CMOV"
   737  	// arm64:"EOR" -"CSEL"
   738  	// ppc64x:"XOR" -"ISEL"
   739  	// wasm:"I64Xor" -"Select"
   740  	return a
   741  }
   742  func cmovmathxorelse(a uint, b bool) uint {
   743  	if !b {
   744  		a ^= 1
   745  	}
   746  	// amd64:"XORQ" -"CMOV"
   747  	// arm64:"EOR" -"CSEL"
   748  	// ppc64x:"XOR" -"ISEL"
   749  	// wasm:"I64Xor" -"Select"
   750  	return a
   751  }
   752  
   753  func cmovmathxor2(a uint, b bool) uint {
   754  	if b {
   755  		a ^= 2
   756  	}
   757  	// arm64:"EOR R[0-9]+<<1" -"CSEL" -"MUL"
   758  	// ppc64x: "ISEL" -"MUL"
   759  	return a
   760  }
   761  func cmovmathxor2else(a uint, b bool) uint {
   762  	if !b {
   763  		a ^= 2
   764  	}
   765  	// arm64:"EOR R[0-9]+<<1" -"CSEL" -"MUL"
   766  	// ppc64x: "ISEL" -"MUL"
   767  	return a
   768  }
   769  
   770  func cmovmathxor9223372036854775808(a uint, b bool) uint {
   771  	if b {
   772  		a ^= 1 << 63
   773  	}
   774  	// arm64:"EOR R[0-9]+<<63" -"CSEL" -"MUL"
   775  	// ppc64x: "ISEL" -"MUL"
   776  	return a
   777  }
   778  func cmovmathxor9223372036854775808else(a uint, b bool) uint {
   779  	if !b {
   780  		a ^= 1 << 63
   781  	}
   782  	// arm64:"EOR R[0-9]+<<63" -"CSEL" -"MUL"
   783  	// ppc64x: "ISEL" -"MUL"
   784  	return a
   785  }
   786  
   787  func branchlessBoolToUint8(b bool) (r uint8) {
   788  	if b {
   789  		r = 1
   790  	}
   791  	return
   792  }
   793  
   794  func cmovFromMulFromFlags64(x uint64, b bool) uint64 {
   795  	// amd64:-"MOVB.ZX"
   796  	r := uint64(branchlessBoolToUint8(b))
   797  	// amd64:"CMOV" -"MOVB.ZX" -"MUL"
   798  	return x * r
   799  }
   800  func cmovFromMulFromFlags64sext(x int64, b bool) int64 {
   801  	// amd64:-"MOVB.ZX"
   802  	r := int64(int8(branchlessBoolToUint8(b)))
   803  	// amd64:"CMOV" -"MOVB.ZX" -"MUL"
   804  	return x * r
   805  }
   806  
   807  func constantTimeSelect(v, x, y int) int {
   808  	// amd64:"CMOVQ"
   809  	// arm64:"CSEL"
   810  	// riscv64/rva20u64,riscv64/rva22u64:"SNEZ" "NEG" "AND" "OR"
   811  	// riscv64/rva23u64:"CZERONEZ" "CZEROEQZ" "OR" -"SNEZ" -"NEG" -"AND"
   812  	return subtle.ConstantTimeSelect(v, x, y)
   813  }
   814  
   815  func issue76056fieldReduceOnceSub32(a uint32) uint32 {
   816  	const q = 8380417 // 2²³ - 2¹³ + 1
   817  	// FIXME: the compiler struggles with Sub32 since it's not intriscified.
   818  	x, b := bits.Sub32(a, q, 0)
   819  	// FIXME: prove doesn't rewrite this multiply to a condselect because it doesn't know that b is always 0 or 1.
   820  	return x + b*q
   821  }
   822  
   823  func issue76056fieldReduceOnce2Sub32(a uint32) uint32 {
   824  	const q = 8380417 // 2²³ - 2¹³ + 1
   825  	// FIXME: the compiler struggles with Sub32 since it's not intriscified.
   826  	x, b := bits.Sub32(a, q, 0)
   827  	return uint32(subtle.ConstantTimeSelect(int(b), int(a), int(x)))
   828  }
   829  
   830  func issue76056fieldReduceOnceSub64(a uint32) uint32 {
   831  	const q = 8380417 // 2²³ - 2¹³ + 1
   832  	x, b := bits.Sub64(uint64(a), q, 0)
   833  	// FIXME: prove doesn't rewrite this multiply to a condselect because it doesn't know that b is always 0 or 1.
   834  	return uint32(x) + uint32(b)*q
   835  }
   836  
   837  func issue76056fieldReduceOnce2Sub64(a uint32) uint32 {
   838  	const q = 8380417 // 2²³ - 2¹³ + 1
   839  	// amd64:"SUB" -"TEST" -"SBB"
   840  	x, b := bits.Sub64(uint64(a), q, 0)
   841  	// amd64:"CMOV" -"TEST" -"SBB"
   842  	return uint32(subtle.ConstantTimeSelect(int(b), int(a), int(x)))
   843  }
   844  

View as plain text