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  func cmovint(c int) int {
    10  	x := c + 4
    11  	if x < 0 {
    12  		x = 182
    13  	}
    14  	// amd64:"CMOVQLT"
    15  	// arm64:"CSEL\tLT"
    16  	// ppc64x:"ISEL\t[$]0"
    17  	// wasm:"Select"
    18  	return x
    19  }
    20  
    21  func cmovchan(x, y chan int) chan int {
    22  	if x != y {
    23  		x = y
    24  	}
    25  	// amd64:"CMOVQNE"
    26  	// arm64:"CSEL\tNE"
    27  	// ppc64x:"ISEL\t[$]2"
    28  	// wasm:"Select"
    29  	return x
    30  }
    31  
    32  func cmovuintptr(x, y uintptr) uintptr {
    33  	if x < y {
    34  		x = -y
    35  	}
    36  	// amd64:"CMOVQ(HI|CS)"
    37  	// arm64:"CSNEG\tLS"
    38  	// ppc64x:"ISEL\t[$]1"
    39  	// wasm:"Select"
    40  	return x
    41  }
    42  
    43  func cmov32bit(x, y uint32) uint32 {
    44  	if x < y {
    45  		x = -y
    46  	}
    47  	// amd64:"CMOVL(HI|CS)"
    48  	// arm64:"CSNEG\t(LS|HS)"
    49  	// ppc64x:"ISEL\t[$]1"
    50  	// wasm:"Select"
    51  	return x
    52  }
    53  
    54  func cmov16bit(x, y uint16) uint16 {
    55  	if x < y {
    56  		x = -y
    57  	}
    58  	// amd64:"CMOVW(HI|CS)"
    59  	// arm64:"CSNEG\t(LS|HS)"
    60  	// ppc64x:"ISEL\t[$][01]"
    61  	// wasm:"Select"
    62  	return x
    63  }
    64  
    65  // Floating point comparison. For EQ/NE, we must
    66  // generate special code to handle NaNs.
    67  func cmovfloateq(x, y float64) int {
    68  	a := 128
    69  	if x == y {
    70  		a = 256
    71  	}
    72  	// amd64:"CMOVQNE","CMOVQPC"
    73  	// arm64:"CSEL\tEQ"
    74  	// ppc64x:"ISEL\t[$]2"
    75  	// wasm:"Select"
    76  	return a
    77  }
    78  
    79  func cmovfloatne(x, y float64) int {
    80  	a := 128
    81  	if x != y {
    82  		a = 256
    83  	}
    84  	// amd64:"CMOVQNE","CMOVQPS"
    85  	// arm64:"CSEL\tNE"
    86  	// ppc64x:"ISEL\t[$]2"
    87  	// wasm:"Select"
    88  	return a
    89  }
    90  
    91  //go:noinline
    92  func frexp(f float64) (frac float64, exp int) {
    93  	return 1.0, 4
    94  }
    95  
    96  //go:noinline
    97  func ldexp(frac float64, exp int) float64 {
    98  	return 1.0
    99  }
   100  
   101  // Generate a CMOV with a floating comparison and integer move.
   102  func cmovfloatint2(x, y float64) float64 {
   103  	yfr, yexp := 4.0, 5
   104  
   105  	r := x
   106  	for r >= y {
   107  		rfr, rexp := frexp(r)
   108  		if rfr < yfr {
   109  			rexp = rexp - 1
   110  		}
   111  		// amd64:"CMOVQHI"
   112  		// arm64:"CSEL\tMI"
   113  		// ppc64x:"ISEL\t[$]0"
   114  		// wasm:"Select"
   115  		r = r - ldexp(y, rexp-yexp)
   116  	}
   117  	return r
   118  }
   119  
   120  func cmovloaded(x [4]int, y int) int {
   121  	if x[2] != 0 {
   122  		y = x[2]
   123  	} else {
   124  		y = y >> 2
   125  	}
   126  	// amd64:"CMOVQNE"
   127  	// arm64:"CSEL\tNE"
   128  	// ppc64x:"ISEL\t[$]2"
   129  	// wasm:"Select"
   130  	return y
   131  }
   132  
   133  func cmovuintptr2(x, y uintptr) uintptr {
   134  	a := x * 2
   135  	if a == 0 {
   136  		a = 256
   137  	}
   138  	// amd64:"CMOVQEQ"
   139  	// arm64:"CSEL\tEQ"
   140  	// ppc64x:"ISEL\t[$]2"
   141  	// wasm:"Select"
   142  	return a
   143  }
   144  
   145  // Floating point CMOVs are not supported by amd64/arm64/ppc64x
   146  func cmovfloatmove(x, y int) float64 {
   147  	a := 1.0
   148  	if x <= y {
   149  		a = 2.0
   150  	}
   151  	// amd64:-"CMOV"
   152  	// arm64:-"CSEL"
   153  	// ppc64x:-"ISEL"
   154  	// wasm:-"Select"
   155  	return a
   156  }
   157  
   158  // On amd64, the following patterns trigger comparison inversion.
   159  // Test that we correctly invert the CMOV condition
   160  var gsink int64
   161  var gusink uint64
   162  
   163  func cmovinvert1(x, y int64) int64 {
   164  	if x < gsink {
   165  		y = -y
   166  	}
   167  	// amd64:"CMOVQGT"
   168  	return y
   169  }
   170  func cmovinvert2(x, y int64) int64 {
   171  	if x <= gsink {
   172  		y = -y
   173  	}
   174  	// amd64:"CMOVQGE"
   175  	return y
   176  }
   177  func cmovinvert3(x, y int64) int64 {
   178  	if x == gsink {
   179  		y = -y
   180  	}
   181  	// amd64:"CMOVQEQ"
   182  	return y
   183  }
   184  func cmovinvert4(x, y int64) int64 {
   185  	if x != gsink {
   186  		y = -y
   187  	}
   188  	// amd64:"CMOVQNE"
   189  	return y
   190  }
   191  func cmovinvert5(x, y uint64) uint64 {
   192  	if x > gusink {
   193  		y = -y
   194  	}
   195  	// amd64:"CMOVQCS"
   196  	return y
   197  }
   198  func cmovinvert6(x, y uint64) uint64 {
   199  	if x >= gusink {
   200  		y = -y
   201  	}
   202  	// amd64:"CMOVQLS"
   203  	return y
   204  }
   205  
   206  func cmovload(a []int, i int, b bool) int {
   207  	if b {
   208  		i++
   209  	}
   210  	// See issue 26306
   211  	// amd64:-"CMOVQNE"
   212  	return a[i]
   213  }
   214  
   215  func cmovstore(a []int, i int, b bool) {
   216  	if b {
   217  		i++
   218  	}
   219  	// amd64:"CMOVQNE"
   220  	a[i] = 7
   221  }
   222  
   223  var r0, r1, r2, r3, r4, r5 int
   224  
   225  func cmovinc(cond bool, a, b, c int) {
   226  	var x0, x1 int
   227  
   228  	if cond {
   229  		x0 = a
   230  	} else {
   231  		x0 = b + 1
   232  	}
   233  	// arm64:"CSINC\tNE", -"CSEL"
   234  	r0 = x0
   235  
   236  	if cond {
   237  		x1 = b + 1
   238  	} else {
   239  		x1 = a
   240  	}
   241  	// arm64:"CSINC\tEQ", -"CSEL"
   242  	r1 = x1
   243  
   244  	if cond {
   245  		c++
   246  	}
   247  	// arm64:"CSINC\tEQ", -"CSEL"
   248  	r2 = c
   249  }
   250  
   251  func cmovinv(cond bool, a, b int) {
   252  	var x0, x1 int
   253  
   254  	if cond {
   255  		x0 = a
   256  	} else {
   257  		x0 = ^b
   258  	}
   259  	// arm64:"CSINV\tNE", -"CSEL"
   260  	r0 = x0
   261  
   262  	if cond {
   263  		x1 = ^b
   264  	} else {
   265  		x1 = a
   266  	}
   267  	// arm64:"CSINV\tEQ", -"CSEL"
   268  	r1 = x1
   269  }
   270  
   271  func cmovneg(cond bool, a, b, c int) {
   272  	var x0, x1 int
   273  
   274  	if cond {
   275  		x0 = a
   276  	} else {
   277  		x0 = -b
   278  	}
   279  	// arm64:"CSNEG\tNE", -"CSEL"
   280  	r0 = x0
   281  
   282  	if cond {
   283  		x1 = -b
   284  	} else {
   285  		x1 = a
   286  	}
   287  	// arm64:"CSNEG\tEQ", -"CSEL"
   288  	r1 = x1
   289  }
   290  
   291  func cmovsetm(cond bool, x int) {
   292  	var x0, x1 int
   293  
   294  	if cond {
   295  		x0 = -1
   296  	} else {
   297  		x0 = 0
   298  	}
   299  	// arm64:"CSETM\tNE", -"CSEL"
   300  	r0 = x0
   301  
   302  	if cond {
   303  		x1 = 0
   304  	} else {
   305  		x1 = -1
   306  	}
   307  	// arm64:"CSETM\tEQ", -"CSEL"
   308  	r1 = x1
   309  }
   310  
   311  func cmovFcmp0(s, t float64, a, b int) {
   312  	var x0, x1, x2, x3, x4, x5 int
   313  
   314  	if s < t {
   315  		x0 = a
   316  	} else {
   317  		x0 = b + 1
   318  	}
   319  	// arm64:"CSINC\tMI", -"CSEL"
   320  	r0 = x0
   321  
   322  	if s <= t {
   323  		x1 = a
   324  	} else {
   325  		x1 = ^b
   326  	}
   327  	// arm64:"CSINV\tLS", -"CSEL"
   328  	r1 = x1
   329  
   330  	if s > t {
   331  		x2 = a
   332  	} else {
   333  		x2 = -b
   334  	}
   335  	// arm64:"CSNEG\tMI", -"CSEL"
   336  	r2 = x2
   337  
   338  	if s >= t {
   339  		x3 = -1
   340  	} else {
   341  		x3 = 0
   342  	}
   343  	// arm64:"CSETM\tLS", -"CSEL"
   344  	r3 = x3
   345  
   346  	if s == t {
   347  		x4 = a
   348  	} else {
   349  		x4 = b + 1
   350  	}
   351  	// arm64:"CSINC\tEQ", -"CSEL"
   352  	r4 = x4
   353  
   354  	if s != t {
   355  		x5 = a
   356  	} else {
   357  		x5 = b + 1
   358  	}
   359  	// arm64:"CSINC\tNE", -"CSEL"
   360  	r5 = x5
   361  }
   362  
   363  func cmovFcmp1(s, t float64, a, b int) {
   364  	var x0, x1, x2, x3, x4, x5 int
   365  
   366  	if s < t {
   367  		x0 = b + 1
   368  	} else {
   369  		x0 = a
   370  	}
   371  	// arm64:"CSINC\tPL", -"CSEL"
   372  	r0 = x0
   373  
   374  	if s <= t {
   375  		x1 = ^b
   376  	} else {
   377  		x1 = a
   378  	}
   379  	// arm64:"CSINV\tHI", -"CSEL"
   380  	r1 = x1
   381  
   382  	if s > t {
   383  		x2 = -b
   384  	} else {
   385  		x2 = a
   386  	}
   387  	// arm64:"CSNEG\tPL", -"CSEL"
   388  	r2 = x2
   389  
   390  	if s >= t {
   391  		x3 = 0
   392  	} else {
   393  		x3 = -1
   394  	}
   395  	// arm64:"CSETM\tHI", -"CSEL"
   396  	r3 = x3
   397  
   398  	if s == t {
   399  		x4 = b + 1
   400  	} else {
   401  		x4 = a
   402  	}
   403  	// arm64:"CSINC\tNE", -"CSEL"
   404  	r4 = x4
   405  
   406  	if s != t {
   407  		x5 = b + 1
   408  	} else {
   409  		x5 = a
   410  	}
   411  	// arm64:"CSINC\tEQ", -"CSEL"
   412  	r5 = x5
   413  }
   414  
   415  func cmovzero1(c bool) int {
   416  	var x int
   417  	if c {
   418  		x = 182
   419  	}
   420  	// loong64:"MASKEQZ", -"MASKNEZ"
   421  	return x
   422  }
   423  
   424  func cmovzero2(c bool) int {
   425  	var x int
   426  	if !c {
   427  		x = 182
   428  	}
   429  	// loong64:"MASKNEZ", -"MASKEQZ"
   430  	return x
   431  }
   432  
   433  // Conditionally selecting between a value or 0 can be done without
   434  // an extra load of 0 to a register on PPC64 by using R0 (which always
   435  // holds the value $0) instead. Verify both cases where either arg1
   436  // or arg2 is zero.
   437  func cmovzeroreg0(a, b int) int {
   438  	x := 0
   439  	if a == b {
   440  		x = a
   441  	}
   442  	// ppc64x:"ISEL\t[$]2, R[0-9]+, R0, R[0-9]+"
   443  	return x
   444  }
   445  
   446  func cmovzeroreg1(a, b int) int {
   447  	x := a
   448  	if a == b {
   449  		x = 0
   450  	}
   451  	// ppc64x:"ISEL\t[$]2, R0, R[0-9]+, R[0-9]+"
   452  	return x
   453  }
   454  

View as plain text