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 7package codegen 8 9func 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 21func 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 32func 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 43func 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 54func 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. 67func 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 79func 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 92func frexp(f float64) (frac float64, exp int) { 93 return 1.0, 4 94} 95 96//go:noinline 97func ldexp(frac float64, exp int) float64 { 98 return 1.0 99} 100 101// Generate a CMOV with a floating comparison and integer move. 102func 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 120func 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 133func 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 146func 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 160var gsink int64 161var gusink uint64 162 163func cmovinvert1(x, y int64) int64 { 164 if x < gsink { 165 y = -y 166 } 167 // amd64:"CMOVQGT" 168 return y 169} 170func cmovinvert2(x, y int64) int64 { 171 if x <= gsink { 172 y = -y 173 } 174 // amd64:"CMOVQGE" 175 return y 176} 177func cmovinvert3(x, y int64) int64 { 178 if x == gsink { 179 y = -y 180 } 181 // amd64:"CMOVQEQ" 182 return y 183} 184func cmovinvert4(x, y int64) int64 { 185 if x != gsink { 186 y = -y 187 } 188 // amd64:"CMOVQNE" 189 return y 190} 191func cmovinvert5(x, y uint64) uint64 { 192 if x > gusink { 193 y = -y 194 } 195 // amd64:"CMOVQCS" 196 return y 197} 198func cmovinvert6(x, y uint64) uint64 { 199 if x >= gusink { 200 y = -y 201 } 202 // amd64:"CMOVQLS" 203 return y 204} 205 206func 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 215func cmovstore(a []int, i int, b bool) { 216 if b { 217 i++ 218 } 219 // amd64:"CMOVQNE" 220 a[i] = 7 221} 222 223var r0, r1, r2, r3, r4, r5 int 224 225func 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 251func 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 271func 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 291func 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 311func 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 363func 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 415func cmovzero1(c bool) int { 416 var x int 417 if c { 418 x = 182 419 } 420 // loong64:"MASKEQZ", -"MASKNEZ" 421 return x 422} 423 424func 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. 437func 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 446func 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