1; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers 2; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -mattr=+atomics,+sign-ext | FileCheck %s 3 4; Test atomic RMW (read-modify-write) instructions are assembled properly. 5 6target triple = "wasm32-unknown-unknown" 7 8;===---------------------------------------------------------------------------- 9; Atomic read-modify-writes: 32-bit 10;===---------------------------------------------------------------------------- 11 12; CHECK-LABEL: add_i32: 13; CHECK-NEXT: .functype add_i32 (i32, i32) -> (i32){{$}} 14; CHECK: i32.atomic.rmw.add $push0=, 0($0), $1{{$}} 15; CHECK-NEXT: return $pop0{{$}} 16define i32 @add_i32(ptr %p, i32 %v) { 17 %old = atomicrmw add ptr %p, i32 %v seq_cst 18 ret i32 %old 19} 20 21; CHECK-LABEL: sub_i32: 22; CHECK-NEXT: .functype sub_i32 (i32, i32) -> (i32){{$}} 23; CHECK: i32.atomic.rmw.sub $push0=, 0($0), $1{{$}} 24; CHECK-NEXT: return $pop0{{$}} 25define i32 @sub_i32(ptr %p, i32 %v) { 26 %old = atomicrmw sub ptr %p, i32 %v seq_cst 27 ret i32 %old 28} 29 30; CHECK-LABEL: and_i32: 31; CHECK-NEXT: .functype and_i32 (i32, i32) -> (i32){{$}} 32; CHECK: i32.atomic.rmw.and $push0=, 0($0), $1{{$}} 33; CHECK-NEXT: return $pop0{{$}} 34define i32 @and_i32(ptr %p, i32 %v) { 35 %old = atomicrmw and ptr %p, i32 %v seq_cst 36 ret i32 %old 37} 38 39; CHECK-LABEL: or_i32: 40; CHECK-NEXT: .functype or_i32 (i32, i32) -> (i32){{$}} 41; CHECK: i32.atomic.rmw.or $push0=, 0($0), $1{{$}} 42; CHECK-NEXT: return $pop0{{$}} 43define i32 @or_i32(ptr %p, i32 %v) { 44 %old = atomicrmw or ptr %p, i32 %v seq_cst 45 ret i32 %old 46} 47 48; CHECK-LABEL: xor_i32: 49; CHECK-NEXT: .functype xor_i32 (i32, i32) -> (i32){{$}} 50; CHECK: i32.atomic.rmw.xor $push0=, 0($0), $1{{$}} 51; CHECK-NEXT: return $pop0{{$}} 52define i32 @xor_i32(ptr %p, i32 %v) { 53 %old = atomicrmw xor ptr %p, i32 %v seq_cst 54 ret i32 %old 55} 56 57; CHECK-LABEL: xchg_i32: 58; CHECK-NEXT: .functype xchg_i32 (i32, i32) -> (i32){{$}} 59; CHECK: i32.atomic.rmw.xchg $push0=, 0($0), $1{{$}} 60; CHECK-NEXT: return $pop0{{$}} 61define i32 @xchg_i32(ptr %p, i32 %v) { 62 %old = atomicrmw xchg ptr %p, i32 %v seq_cst 63 ret i32 %old 64} 65 66; CHECK-LABEL: cmpxchg_i32_loaded_value: 67; CHECK-NEXT: .functype cmpxchg_i32_loaded_value (i32, i32, i32) -> (i32){{$}} 68; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}} 69; CHECK-NEXT: return $pop0{{$}} 70define i32 @cmpxchg_i32_loaded_value(ptr %p, i32 %exp, i32 %new) { 71 %pair = cmpxchg ptr %p, i32 %exp, i32 %new seq_cst seq_cst 72 %old = extractvalue { i32, i1 } %pair, 0 73 ret i32 %old 74} 75 76; CHECK-LABEL: cmpxchg_i32_success: 77; CHECK-NEXT: .functype cmpxchg_i32_success (i32, i32, i32) -> (i32){{$}} 78; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}} 79; CHECK-NEXT: i32.eq $push1=, $pop0, $1{{$}} 80; CHECK-NEXT: return $pop1{{$}} 81define i1 @cmpxchg_i32_success(ptr %p, i32 %exp, i32 %new) { 82 %pair = cmpxchg ptr %p, i32 %exp, i32 %new seq_cst seq_cst 83 %succ = extractvalue { i32, i1 } %pair, 1 84 ret i1 %succ 85} 86 87; Unsupported instructions are expanded using cmpxchg with a loop. 88 89; CHECK-LABEL: nand_i32: 90; CHECK: loop 91; CHECK: i32.atomic.rmw.cmpxchg 92; CHECK: br_if 0 93; CHECK: end_loop 94define i32 @nand_i32(ptr %p, i32 %v) { 95 %old = atomicrmw nand ptr %p, i32 %v seq_cst 96 ret i32 %old 97} 98 99; CHECK-LABEL: max_i32: 100; CHECK: loop 101; CHECK: i32.atomic.rmw.cmpxchg 102; CHECK: br_if 0 103; CHECK: end_loop 104define i32 @max_i32(ptr %p, i32 %v) { 105 %old = atomicrmw max ptr %p, i32 %v seq_cst 106 ret i32 %old 107} 108 109; CHECK-LABEL: min_i32: 110; CHECK: loop 111; CHECK: i32.atomic.rmw.cmpxchg 112; CHECK: br_if 0 113; CHECK: end_loop 114define i32 @min_i32(ptr %p, i32 %v) { 115 %old = atomicrmw min ptr %p, i32 %v seq_cst 116 ret i32 %old 117} 118 119; CHECK-LABEL: umax_i32: 120; CHECK: loop 121; CHECK: i32.atomic.rmw.cmpxchg 122; CHECK: br_if 0 123; CHECK: end_loop 124define i32 @umax_i32(ptr %p, i32 %v) { 125 %old = atomicrmw umax ptr %p, i32 %v seq_cst 126 ret i32 %old 127} 128 129; CHECK-LABEL: umin_i32: 130; CHECK: loop 131; CHECK: i32.atomic.rmw.cmpxchg 132; CHECK: br_if 0 133; CHECK: end_loop 134define i32 @umin_i32(ptr %p, i32 %v) { 135 %old = atomicrmw umin ptr %p, i32 %v seq_cst 136 ret i32 %old 137} 138 139;===---------------------------------------------------------------------------- 140; Atomic read-modify-writes: 64-bit 141;===---------------------------------------------------------------------------- 142 143; CHECK-LABEL: add_i64: 144; CHECK-NEXT: .functype add_i64 (i32, i64) -> (i64){{$}} 145; CHECK: i64.atomic.rmw.add $push0=, 0($0), $1{{$}} 146; CHECK-NEXT: return $pop0{{$}} 147define i64 @add_i64(ptr %p, i64 %v) { 148 %old = atomicrmw add ptr %p, i64 %v seq_cst 149 ret i64 %old 150} 151 152; CHECK-LABEL: sub_i64: 153; CHECK-NEXT: .functype sub_i64 (i32, i64) -> (i64){{$}} 154; CHECK: i64.atomic.rmw.sub $push0=, 0($0), $1{{$}} 155; CHECK-NEXT: return $pop0{{$}} 156define i64 @sub_i64(ptr %p, i64 %v) { 157 %old = atomicrmw sub ptr %p, i64 %v seq_cst 158 ret i64 %old 159} 160 161; CHECK-LABEL: and_i64: 162; CHECK-NEXT: .functype and_i64 (i32, i64) -> (i64){{$}} 163; CHECK: i64.atomic.rmw.and $push0=, 0($0), $1{{$}} 164; CHECK-NEXT: return $pop0{{$}} 165define i64 @and_i64(ptr %p, i64 %v) { 166 %old = atomicrmw and ptr %p, i64 %v seq_cst 167 ret i64 %old 168} 169 170; CHECK-LABEL: or_i64: 171; CHECK-NEXT: .functype or_i64 (i32, i64) -> (i64){{$}} 172; CHECK: i64.atomic.rmw.or $push0=, 0($0), $1{{$}} 173; CHECK-NEXT: return $pop0{{$}} 174define i64 @or_i64(ptr %p, i64 %v) { 175 %old = atomicrmw or ptr %p, i64 %v seq_cst 176 ret i64 %old 177} 178 179; CHECK-LABEL: xor_i64: 180; CHECK-NEXT: .functype xor_i64 (i32, i64) -> (i64){{$}} 181; CHECK: i64.atomic.rmw.xor $push0=, 0($0), $1{{$}} 182; CHECK-NEXT: return $pop0{{$}} 183define i64 @xor_i64(ptr %p, i64 %v) { 184 %old = atomicrmw xor ptr %p, i64 %v seq_cst 185 ret i64 %old 186} 187 188; CHECK-LABEL: xchg_i64: 189; CHECK-NEXT: .functype xchg_i64 (i32, i64) -> (i64){{$}} 190; CHECK: i64.atomic.rmw.xchg $push0=, 0($0), $1{{$}} 191; CHECK-NEXT: return $pop0{{$}} 192define i64 @xchg_i64(ptr %p, i64 %v) { 193 %old = atomicrmw xchg ptr %p, i64 %v seq_cst 194 ret i64 %old 195} 196 197; CHECK-LABEL: cmpxchg_i64_loaded_value: 198; CHECK-NEXT: .functype cmpxchg_i64_loaded_value (i32, i64, i64) -> (i64){{$}} 199; CHECK: i64.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}} 200; CHECK-NEXT: return $pop0{{$}} 201define i64 @cmpxchg_i64_loaded_value(ptr %p, i64 %exp, i64 %new) { 202 %pair = cmpxchg ptr %p, i64 %exp, i64 %new seq_cst seq_cst 203 %old = extractvalue { i64, i1 } %pair, 0 204 ret i64 %old 205} 206 207; CHECK-LABEL: cmpxchg_i64_success: 208; CHECK-NEXT: .functype cmpxchg_i64_success (i32, i64, i64) -> (i32){{$}} 209; CHECK: i64.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}} 210; CHECK-NEXT: i64.eq $push1=, $pop0, $1{{$}} 211; CHECK-NEXT: return $pop1{{$}} 212define i1 @cmpxchg_i64_success(ptr %p, i64 %exp, i64 %new) { 213 %pair = cmpxchg ptr %p, i64 %exp, i64 %new seq_cst seq_cst 214 %succ = extractvalue { i64, i1 } %pair, 1 215 ret i1 %succ 216} 217 218; Unsupported instructions are expanded using cmpxchg with a loop. 219 220; CHECK-LABEL: nand_i64: 221; CHECK: loop 222; CHECK: i64.atomic.rmw.cmpxchg 223; CHECK: br_if 0 224; CHECK: end_loop 225define i64 @nand_i64(ptr %p, i64 %v) { 226 %old = atomicrmw nand ptr %p, i64 %v seq_cst 227 ret i64 %old 228} 229 230; CHECK-LABEL: max_i64: 231; CHECK: loop 232; CHECK: i64.atomic.rmw.cmpxchg 233; CHECK: br_if 0 234; CHECK: end_loop 235define i64 @max_i64(ptr %p, i64 %v) { 236 %old = atomicrmw max ptr %p, i64 %v seq_cst 237 ret i64 %old 238} 239 240; CHECK-LABEL: min_i64: 241; CHECK: loop 242; CHECK: i64.atomic.rmw.cmpxchg 243; CHECK: br_if 0 244; CHECK: end_loop 245define i64 @min_i64(ptr %p, i64 %v) { 246 %old = atomicrmw min ptr %p, i64 %v seq_cst 247 ret i64 %old 248} 249 250; CHECK-LABEL: umax_i64: 251; CHECK: loop 252; CHECK: i64.atomic.rmw.cmpxchg 253; CHECK: br_if 0 254; CHECK: end_loop 255define i64 @umax_i64(ptr %p, i64 %v) { 256 %old = atomicrmw umax ptr %p, i64 %v seq_cst 257 ret i64 %old 258} 259 260; CHECK-LABEL: umin_i64: 261; CHECK: loop 262; CHECK: i64.atomic.rmw.cmpxchg 263; CHECK: br_if 0 264; CHECK: end_loop 265define i64 @umin_i64(ptr %p, i64 %v) { 266 %old = atomicrmw umin ptr %p, i64 %v seq_cst 267 ret i64 %old 268} 269 270;===---------------------------------------------------------------------------- 271; Atomic truncating & sign-extending RMWs 272;===---------------------------------------------------------------------------- 273 274; add 275 276; CHECK-LABEL: add_sext_i8_i32: 277; CHECK-NEXT: .functype add_sext_i8_i32 (i32, i32) -> (i32){{$}} 278; CHECK: i32.atomic.rmw8.add_u $push0=, 0($0), $1{{$}} 279; CHECK-NEXT: i32.extend8_s $push1=, $pop0{{$}} 280; CHECK-NEXT: return $pop1{{$}} 281define i32 @add_sext_i8_i32(ptr %p, i32 %v) { 282 %t = trunc i32 %v to i8 283 %old = atomicrmw add ptr %p, i8 %t seq_cst 284 %e = sext i8 %old to i32 285 ret i32 %e 286} 287 288; CHECK-LABEL: add_sext_i16_i32: 289; CHECK-NEXT: .functype add_sext_i16_i32 (i32, i32) -> (i32){{$}} 290; CHECK: i32.atomic.rmw16.add_u $push0=, 0($0), $1{{$}} 291; CHECK-NEXT: i32.extend16_s $push1=, $pop0{{$}} 292; CHECK-NEXT: return $pop1{{$}} 293define i32 @add_sext_i16_i32(ptr %p, i32 %v) { 294 %t = trunc i32 %v to i16 295 %old = atomicrmw add ptr %p, i16 %t seq_cst 296 %e = sext i16 %old to i32 297 ret i32 %e 298} 299 300; CHECK-LABEL: add_sext_i8_i64: 301; CHECK-NEXT: .functype add_sext_i8_i64 (i32, i64) -> (i64){{$}} 302; CHECK: i64.atomic.rmw8.add_u $push0=, 0($0), $1{{$}} 303; CHECK-NEXT: i64.extend8_s $push1=, $pop0{{$}} 304; CHECK-NEXT: return $pop1{{$}} 305define i64 @add_sext_i8_i64(ptr %p, i64 %v) { 306 %t = trunc i64 %v to i8 307 %old = atomicrmw add ptr %p, i8 %t seq_cst 308 %e = sext i8 %old to i64 309 ret i64 %e 310} 311 312; CHECK-LABEL: add_sext_i16_i64: 313; CHECK-NEXT: .functype add_sext_i16_i64 (i32, i64) -> (i64){{$}} 314; CHECK: i64.atomic.rmw16.add_u $push0=, 0($0), $1{{$}} 315; CHECK-NEXT: i64.extend16_s $push1=, $pop0{{$}} 316; CHECK-NEXT: return $pop1{{$}} 317define i64 @add_sext_i16_i64(ptr %p, i64 %v) { 318 %t = trunc i64 %v to i16 319 %old = atomicrmw add ptr %p, i16 %t seq_cst 320 %e = sext i16 %old to i64 321 ret i64 %e 322} 323 324; 32->64 sext rmw gets selected as i32.atomic.rmw.add, i64.extend_i32_s 325; CHECK-LABEL: add_sext_i32_i64: 326; CHECK-NEXT: .functype add_sext_i32_i64 (i32, i64) -> (i64){{$}} 327; CHECK: i32.wrap_i64 $push0=, $1{{$}} 328; CHECK: i32.atomic.rmw.add $push1=, 0($0), $pop0{{$}} 329; CHECK-NEXT: i64.extend_i32_s $push2=, $pop1{{$}} 330; CHECK-NEXT: return $pop2{{$}} 331define i64 @add_sext_i32_i64(ptr %p, i64 %v) { 332 %t = trunc i64 %v to i32 333 %old = atomicrmw add ptr %p, i32 %t seq_cst 334 %e = sext i32 %old to i64 335 ret i64 %e 336} 337 338; sub 339 340; CHECK-LABEL: sub_sext_i8_i32: 341; CHECK-NEXT: .functype sub_sext_i8_i32 (i32, i32) -> (i32){{$}} 342; CHECK: i32.atomic.rmw8.sub_u $push0=, 0($0), $1{{$}} 343; CHECK-NEXT: i32.extend8_s $push1=, $pop0{{$}} 344; CHECK-NEXT: return $pop1{{$}} 345define i32 @sub_sext_i8_i32(ptr %p, i32 %v) { 346 %t = trunc i32 %v to i8 347 %old = atomicrmw sub ptr %p, i8 %t seq_cst 348 %e = sext i8 %old to i32 349 ret i32 %e 350} 351 352; CHECK-LABEL: sub_sext_i16_i32: 353; CHECK-NEXT: .functype sub_sext_i16_i32 (i32, i32) -> (i32){{$}} 354; CHECK: i32.atomic.rmw16.sub_u $push0=, 0($0), $1{{$}} 355; CHECK-NEXT: i32.extend16_s $push1=, $pop0{{$}} 356; CHECK-NEXT: return $pop1{{$}} 357define i32 @sub_sext_i16_i32(ptr %p, i32 %v) { 358 %t = trunc i32 %v to i16 359 %old = atomicrmw sub ptr %p, i16 %t seq_cst 360 %e = sext i16 %old to i32 361 ret i32 %e 362} 363 364; CHECK-LABEL: sub_sext_i8_i64: 365; CHECK-NEXT: .functype sub_sext_i8_i64 (i32, i64) -> (i64){{$}} 366; CHECK: i64.atomic.rmw8.sub_u $push0=, 0($0), $1{{$}} 367; CHECK-NEXT: i64.extend8_s $push1=, $pop0{{$}} 368; CHECK-NEXT: return $pop1{{$}} 369define i64 @sub_sext_i8_i64(ptr %p, i64 %v) { 370 %t = trunc i64 %v to i8 371 %old = atomicrmw sub ptr %p, i8 %t seq_cst 372 %e = sext i8 %old to i64 373 ret i64 %e 374} 375 376; CHECK-LABEL: sub_sext_i16_i64: 377; CHECK-NEXT: .functype sub_sext_i16_i64 (i32, i64) -> (i64){{$}} 378; CHECK: i64.atomic.rmw16.sub_u $push0=, 0($0), $1{{$}} 379; CHECK-NEXT: i64.extend16_s $push1=, $pop0{{$}} 380; CHECK-NEXT: return $pop1{{$}} 381define i64 @sub_sext_i16_i64(ptr %p, i64 %v) { 382 %t = trunc i64 %v to i16 383 %old = atomicrmw sub ptr %p, i16 %t seq_cst 384 %e = sext i16 %old to i64 385 ret i64 %e 386} 387 388; 32->64 sext rmw gets selected as i32.atomic.rmw.sub, i64.extend_i32_s 389; CHECK-LABEL: sub_sext_i32_i64: 390; CHECK-NEXT: .functype sub_sext_i32_i64 (i32, i64) -> (i64){{$}} 391; CHECK: i32.wrap_i64 $push0=, $1 392; CHECK: i32.atomic.rmw.sub $push1=, 0($0), $pop0{{$}} 393; CHECK-NEXT: i64.extend_i32_s $push2=, $pop1{{$}} 394; CHECK-NEXT: return $pop2{{$}} 395define i64 @sub_sext_i32_i64(ptr %p, i64 %v) { 396 %t = trunc i64 %v to i32 397 %old = atomicrmw sub ptr %p, i32 %t seq_cst 398 %e = sext i32 %old to i64 399 ret i64 %e 400} 401 402; and 403 404; CHECK-LABEL: and_sext_i8_i32: 405; CHECK-NEXT: .functype and_sext_i8_i32 (i32, i32) -> (i32){{$}} 406; CHECK: i32.atomic.rmw8.and_u $push0=, 0($0), $1{{$}} 407; CHECK-NEXT: i32.extend8_s $push1=, $pop0{{$}} 408; CHECK-NEXT: return $pop1{{$}} 409define i32 @and_sext_i8_i32(ptr %p, i32 %v) { 410 %t = trunc i32 %v to i8 411 %old = atomicrmw and ptr %p, i8 %t seq_cst 412 %e = sext i8 %old to i32 413 ret i32 %e 414} 415 416; CHECK-LABEL: and_sext_i16_i32: 417; CHECK-NEXT: .functype and_sext_i16_i32 (i32, i32) -> (i32){{$}} 418; CHECK: i32.atomic.rmw16.and_u $push0=, 0($0), $1{{$}} 419; CHECK-NEXT: i32.extend16_s $push1=, $pop0{{$}} 420; CHECK-NEXT: return $pop1{{$}} 421define i32 @and_sext_i16_i32(ptr %p, i32 %v) { 422 %t = trunc i32 %v to i16 423 %old = atomicrmw and ptr %p, i16 %t seq_cst 424 %e = sext i16 %old to i32 425 ret i32 %e 426} 427 428; CHECK-LABEL: and_sext_i8_i64: 429; CHECK-NEXT: .functype and_sext_i8_i64 (i32, i64) -> (i64){{$}} 430; CHECK: i64.atomic.rmw8.and_u $push0=, 0($0), $1{{$}} 431; CHECK-NEXT: i64.extend8_s $push1=, $pop0{{$}} 432; CHECK-NEXT: return $pop1{{$}} 433define i64 @and_sext_i8_i64(ptr %p, i64 %v) { 434 %t = trunc i64 %v to i8 435 %old = atomicrmw and ptr %p, i8 %t seq_cst 436 %e = sext i8 %old to i64 437 ret i64 %e 438} 439 440; CHECK-LABEL: and_sext_i16_i64: 441; CHECK-NEXT: .functype and_sext_i16_i64 (i32, i64) -> (i64){{$}} 442; CHECK: i64.atomic.rmw16.and_u $push0=, 0($0), $1{{$}} 443; CHECK-NEXT: i64.extend16_s $push1=, $pop0{{$}} 444; CHECK-NEXT: return $pop1{{$}} 445define i64 @and_sext_i16_i64(ptr %p, i64 %v) { 446 %t = trunc i64 %v to i16 447 %old = atomicrmw and ptr %p, i16 %t seq_cst 448 %e = sext i16 %old to i64 449 ret i64 %e 450} 451 452; 32->64 sext rmw gets selected as i32.atomic.rmw.and, i64.extend_i32_s 453; CHECK-LABEL: and_sext_i32_i64: 454; CHECK-NEXT: .functype and_sext_i32_i64 (i32, i64) -> (i64){{$}} 455; CHECK: i32.wrap_i64 $push0=, $1{{$}} 456; CHECK: i32.atomic.rmw.and $push1=, 0($0), $pop0{{$}} 457; CHECK-NEXT: i64.extend_i32_s $push2=, $pop1{{$}} 458; CHECK-NEXT: return $pop2{{$}} 459define i64 @and_sext_i32_i64(ptr %p, i64 %v) { 460 %t = trunc i64 %v to i32 461 %old = atomicrmw and ptr %p, i32 %t seq_cst 462 %e = sext i32 %old to i64 463 ret i64 %e 464} 465 466; or 467 468; CHECK-LABEL: or_sext_i8_i32: 469; CHECK-NEXT: .functype or_sext_i8_i32 (i32, i32) -> (i32){{$}} 470; CHECK: i32.atomic.rmw8.or_u $push0=, 0($0), $1{{$}} 471; CHECK-NEXT: i32.extend8_s $push1=, $pop0{{$}} 472; CHECK-NEXT: return $pop1{{$}} 473define i32 @or_sext_i8_i32(ptr %p, i32 %v) { 474 %t = trunc i32 %v to i8 475 %old = atomicrmw or ptr %p, i8 %t seq_cst 476 %e = sext i8 %old to i32 477 ret i32 %e 478} 479 480; CHECK-LABEL: or_sext_i16_i32: 481; CHECK-NEXT: .functype or_sext_i16_i32 (i32, i32) -> (i32){{$}} 482; CHECK: i32.atomic.rmw16.or_u $push0=, 0($0), $1{{$}} 483; CHECK-NEXT: i32.extend16_s $push1=, $pop0{{$}} 484; CHECK-NEXT: return $pop1{{$}} 485define i32 @or_sext_i16_i32(ptr %p, i32 %v) { 486 %t = trunc i32 %v to i16 487 %old = atomicrmw or ptr %p, i16 %t seq_cst 488 %e = sext i16 %old to i32 489 ret i32 %e 490} 491 492; CHECK-LABEL: or_sext_i8_i64: 493; CHECK-NEXT: .functype or_sext_i8_i64 (i32, i64) -> (i64){{$}} 494; CHECK: i64.atomic.rmw8.or_u $push0=, 0($0), $1{{$}} 495; CHECK-NEXT: i64.extend8_s $push1=, $pop0{{$}} 496; CHECK-NEXT: return $pop1{{$}} 497define i64 @or_sext_i8_i64(ptr %p, i64 %v) { 498 %t = trunc i64 %v to i8 499 %old = atomicrmw or ptr %p, i8 %t seq_cst 500 %e = sext i8 %old to i64 501 ret i64 %e 502} 503 504; CHECK-LABEL: or_sext_i16_i64: 505; CHECK-NEXT: .functype or_sext_i16_i64 (i32, i64) -> (i64){{$}} 506; CHECK: i64.atomic.rmw16.or_u $push0=, 0($0), $1{{$}} 507; CHECK-NEXT: i64.extend16_s $push1=, $pop0{{$}} 508; CHECK-NEXT: return $pop1{{$}} 509define i64 @or_sext_i16_i64(ptr %p, i64 %v) { 510 %t = trunc i64 %v to i16 511 %old = atomicrmw or ptr %p, i16 %t seq_cst 512 %e = sext i16 %old to i64 513 ret i64 %e 514} 515 516; 32->64 sext rmw gets selected as i32.atomic.rmw.or, i64.extend_i32_s 517; CHECK-LABEL: or_sext_i32_i64: 518; CHECK-NEXT: .functype or_sext_i32_i64 (i32, i64) -> (i64){{$}} 519; CHECK: i32.wrap_i64 $push0=, $1{{$}} 520; CHECK: i32.atomic.rmw.or $push1=, 0($0), $pop0{{$}} 521; CHECK-NEXT: i64.extend_i32_s $push2=, $pop1{{$}} 522; CHECK-NEXT: return $pop2{{$}} 523define i64 @or_sext_i32_i64(ptr %p, i64 %v) { 524 %t = trunc i64 %v to i32 525 %old = atomicrmw or ptr %p, i32 %t seq_cst 526 %e = sext i32 %old to i64 527 ret i64 %e 528} 529 530; xor 531 532; CHECK-LABEL: xor_sext_i8_i32: 533; CHECK-NEXT: .functype xor_sext_i8_i32 (i32, i32) -> (i32){{$}} 534; CHECK: i32.atomic.rmw8.xor_u $push0=, 0($0), $1{{$}} 535; CHECK-NEXT: i32.extend8_s $push1=, $pop0{{$}} 536; CHECK-NEXT: return $pop1{{$}} 537define i32 @xor_sext_i8_i32(ptr %p, i32 %v) { 538 %t = trunc i32 %v to i8 539 %old = atomicrmw xor ptr %p, i8 %t seq_cst 540 %e = sext i8 %old to i32 541 ret i32 %e 542} 543 544; CHECK-LABEL: xor_sext_i16_i32: 545; CHECK-NEXT: .functype xor_sext_i16_i32 (i32, i32) -> (i32){{$}} 546; CHECK: i32.atomic.rmw16.xor_u $push0=, 0($0), $1{{$}} 547; CHECK-NEXT: i32.extend16_s $push1=, $pop0{{$}} 548; CHECK-NEXT: return $pop1{{$}} 549define i32 @xor_sext_i16_i32(ptr %p, i32 %v) { 550 %t = trunc i32 %v to i16 551 %old = atomicrmw xor ptr %p, i16 %t seq_cst 552 %e = sext i16 %old to i32 553 ret i32 %e 554} 555 556; CHECK-LABEL: xor_sext_i8_i64: 557; CHECK-NEXT: .functype xor_sext_i8_i64 (i32, i64) -> (i64){{$}} 558; CHECK: i64.atomic.rmw8.xor_u $push0=, 0($0), $1{{$}} 559; CHECK-NEXT: i64.extend8_s $push1=, $pop0{{$}} 560; CHECK-NEXT: return $pop1{{$}} 561define i64 @xor_sext_i8_i64(ptr %p, i64 %v) { 562 %t = trunc i64 %v to i8 563 %old = atomicrmw xor ptr %p, i8 %t seq_cst 564 %e = sext i8 %old to i64 565 ret i64 %e 566} 567 568; CHECK-LABEL: xor_sext_i16_i64: 569; CHECK-NEXT: .functype xor_sext_i16_i64 (i32, i64) -> (i64){{$}} 570; CHECK: i64.atomic.rmw16.xor_u $push0=, 0($0), $1{{$}} 571; CHECK-NEXT: i64.extend16_s $push1=, $pop0{{$}} 572; CHECK-NEXT: return $pop1{{$}} 573define i64 @xor_sext_i16_i64(ptr %p, i64 %v) { 574 %t = trunc i64 %v to i16 575 %old = atomicrmw xor ptr %p, i16 %t seq_cst 576 %e = sext i16 %old to i64 577 ret i64 %e 578} 579 580; 32->64 sext rmw gets selected as i32.atomic.rmw.xor, i64.extend_i32_s 581; CHECK-LABEL: xor_sext_i32_i64: 582; CHECK-NEXT: .functype xor_sext_i32_i64 (i32, i64) -> (i64){{$}} 583; CHECK: i32.wrap_i64 $push0=, $1{{$}} 584; CHECK: i32.atomic.rmw.xor $push1=, 0($0), $pop0{{$}} 585; CHECK-NEXT: i64.extend_i32_s $push2=, $pop1{{$}} 586; CHECK-NEXT: return $pop2{{$}} 587define i64 @xor_sext_i32_i64(ptr %p, i64 %v) { 588 %t = trunc i64 %v to i32 589 %old = atomicrmw xor ptr %p, i32 %t seq_cst 590 %e = sext i32 %old to i64 591 ret i64 %e 592} 593 594; xchg 595 596; CHECK-LABEL: xchg_sext_i8_i32: 597; CHECK-NEXT: .functype xchg_sext_i8_i32 (i32, i32) -> (i32){{$}} 598; CHECK: i32.atomic.rmw8.xchg_u $push0=, 0($0), $1{{$}} 599; CHECK-NEXT: i32.extend8_s $push1=, $pop0{{$}} 600; CHECK-NEXT: return $pop1{{$}} 601define i32 @xchg_sext_i8_i32(ptr %p, i32 %v) { 602 %t = trunc i32 %v to i8 603 %old = atomicrmw xchg ptr %p, i8 %t seq_cst 604 %e = sext i8 %old to i32 605 ret i32 %e 606} 607 608; CHECK-LABEL: xchg_sext_i16_i32: 609; CHECK-NEXT: .functype xchg_sext_i16_i32 (i32, i32) -> (i32){{$}} 610; CHECK: i32.atomic.rmw16.xchg_u $push0=, 0($0), $1{{$}} 611; CHECK-NEXT: i32.extend16_s $push1=, $pop0{{$}} 612; CHECK-NEXT: return $pop1{{$}} 613define i32 @xchg_sext_i16_i32(ptr %p, i32 %v) { 614 %t = trunc i32 %v to i16 615 %old = atomicrmw xchg ptr %p, i16 %t seq_cst 616 %e = sext i16 %old to i32 617 ret i32 %e 618} 619 620; CHECK-LABEL: xchg_sext_i8_i64: 621; CHECK-NEXT: .functype xchg_sext_i8_i64 (i32, i64) -> (i64){{$}} 622; CHECK: i64.atomic.rmw8.xchg_u $push0=, 0($0), $1{{$}} 623; CHECK-NEXT: i64.extend8_s $push1=, $pop0{{$}} 624; CHECK-NEXT: return $pop1{{$}} 625define i64 @xchg_sext_i8_i64(ptr %p, i64 %v) { 626 %t = trunc i64 %v to i8 627 %old = atomicrmw xchg ptr %p, i8 %t seq_cst 628 %e = sext i8 %old to i64 629 ret i64 %e 630} 631 632; CHECK-LABEL: xchg_sext_i16_i64: 633; CHECK-NEXT: .functype xchg_sext_i16_i64 (i32, i64) -> (i64){{$}} 634; CHECK: i64.atomic.rmw16.xchg_u $push0=, 0($0), $1{{$}} 635; CHECK-NEXT: i64.extend16_s $push1=, $pop0{{$}} 636; CHECK-NEXT: return $pop1{{$}} 637define i64 @xchg_sext_i16_i64(ptr %p, i64 %v) { 638 %t = trunc i64 %v to i16 639 %old = atomicrmw xchg ptr %p, i16 %t seq_cst 640 %e = sext i16 %old to i64 641 ret i64 %e 642} 643 644; 32->64 sext rmw gets selected as i32.atomic.rmw.xchg, i64.extend_i32_s 645; CHECK-LABEL: xchg_sext_i32_i64: 646; CHECK-NEXT: .functype xchg_sext_i32_i64 (i32, i64) -> (i64){{$}} 647; CHECK: i32.wrap_i64 $push0=, $1{{$}} 648; CHECK: i32.atomic.rmw.xchg $push1=, 0($0), $pop0{{$}} 649; CHECK-NEXT: i64.extend_i32_s $push2=, $pop1{{$}} 650; CHECK-NEXT: return $pop2{{$}} 651define i64 @xchg_sext_i32_i64(ptr %p, i64 %v) { 652 %t = trunc i64 %v to i32 653 %old = atomicrmw xchg ptr %p, i32 %t seq_cst 654 %e = sext i32 %old to i64 655 ret i64 %e 656} 657 658; cmpxchg 659 660; CHECK-LABEL: cmpxchg_sext_i8_i32: 661; CHECK-NEXT: .functype cmpxchg_sext_i8_i32 (i32, i32, i32) -> (i32){{$}} 662; CHECK: i32.atomic.rmw8.cmpxchg_u $push0=, 0($0), $1, $2{{$}} 663; CHECK-NEXT: i32.extend8_s $push1=, $pop0{{$}} 664; CHECK-NEXT: return $pop1{{$}} 665define i32 @cmpxchg_sext_i8_i32(ptr %p, i32 %exp, i32 %new) { 666 %exp_t = trunc i32 %exp to i8 667 %new_t = trunc i32 %new to i8 668 %pair = cmpxchg ptr %p, i8 %exp_t, i8 %new_t seq_cst seq_cst 669 %old = extractvalue { i8, i1 } %pair, 0 670 %e = sext i8 %old to i32 671 ret i32 %e 672} 673 674; CHECK-LABEL: cmpxchg_sext_i16_i32: 675; CHECK-NEXT: .functype cmpxchg_sext_i16_i32 (i32, i32, i32) -> (i32){{$}} 676; CHECK: i32.atomic.rmw16.cmpxchg_u $push0=, 0($0), $1, $2{{$}} 677; CHECK-NEXT: i32.extend16_s $push1=, $pop0{{$}} 678; CHECK-NEXT: return $pop1{{$}} 679define i32 @cmpxchg_sext_i16_i32(ptr %p, i32 %exp, i32 %new) { 680 %exp_t = trunc i32 %exp to i16 681 %new_t = trunc i32 %new to i16 682 %pair = cmpxchg ptr %p, i16 %exp_t, i16 %new_t seq_cst seq_cst 683 %old = extractvalue { i16, i1 } %pair, 0 684 %e = sext i16 %old to i32 685 ret i32 %e 686} 687 688; CHECK-LABEL: cmpxchg_sext_i8_i64: 689; CHECK-NEXT: .functype cmpxchg_sext_i8_i64 (i32, i64, i64) -> (i64){{$}} 690; CHECK: i64.atomic.rmw8.cmpxchg_u $push0=, 0($0), $1, $2{{$}} 691; CHECK-NEXT: i64.extend8_s $push1=, $pop0{{$}} 692; CHECK-NEXT: return $pop1{{$}} 693define i64 @cmpxchg_sext_i8_i64(ptr %p, i64 %exp, i64 %new) { 694 %exp_t = trunc i64 %exp to i8 695 %new_t = trunc i64 %new to i8 696 %pair = cmpxchg ptr %p, i8 %exp_t, i8 %new_t seq_cst seq_cst 697 %old = extractvalue { i8, i1 } %pair, 0 698 %e = sext i8 %old to i64 699 ret i64 %e 700} 701 702; CHECK-LABEL: cmpxchg_sext_i16_i64: 703; CHECK-NEXT: .functype cmpxchg_sext_i16_i64 (i32, i64, i64) -> (i64){{$}} 704; CHECK: i64.atomic.rmw16.cmpxchg_u $push0=, 0($0), $1, $2{{$}} 705; CHECK-NEXT: i64.extend16_s $push1=, $pop0{{$}} 706; CHECK-NEXT: return $pop1{{$}} 707define i64 @cmpxchg_sext_i16_i64(ptr %p, i64 %exp, i64 %new) { 708 %exp_t = trunc i64 %exp to i16 709 %new_t = trunc i64 %new to i16 710 %pair = cmpxchg ptr %p, i16 %exp_t, i16 %new_t seq_cst seq_cst 711 %old = extractvalue { i16, i1 } %pair, 0 712 %e = sext i16 %old to i64 713 ret i64 %e 714} 715 716; 32->64 sext rmw gets selected as i32.atomic.rmw.cmpxchg, i64.extend_i32_s 717; CHECK-LABEL: cmpxchg_sext_i32_i64: 718; CHECK-NEXT: .functype cmpxchg_sext_i32_i64 (i32, i64, i64) -> (i64){{$}} 719; CHECK: i32.wrap_i64 $push1=, $1{{$}} 720; CHECK-NEXT: i32.wrap_i64 $push0=, $2{{$}} 721; CHECK-NEXT: i32.atomic.rmw.cmpxchg $push2=, 0($0), $pop1, $pop0{{$}} 722; CHECK-NEXT: i64.extend_i32_s $push3=, $pop2{{$}} 723; CHECK-NEXT: return $pop3{{$}} 724define i64 @cmpxchg_sext_i32_i64(ptr %p, i64 %exp, i64 %new) { 725 %exp_t = trunc i64 %exp to i32 726 %new_t = trunc i64 %new to i32 727 %pair = cmpxchg ptr %p, i32 %exp_t, i32 %new_t seq_cst seq_cst 728 %old = extractvalue { i32, i1 } %pair, 0 729 %e = sext i32 %old to i64 730 ret i64 %e 731} 732 733; Unsupported instructions are expanded using cmpxchg with a loop. 734; Here we take a nand as an example. 735 736; nand 737 738; CHECK-LABEL: nand_sext_i8_i32: 739; CHECK-NEXT: .functype nand_sext_i8_i32 (i32, i32) -> (i32){{$}} 740; CHECK: loop 741; CHECK: i32.atomic.rmw8.cmpxchg_u 742; CHECK: i32.extend8_s 743define i32 @nand_sext_i8_i32(ptr %p, i32 %v) { 744 %t = trunc i32 %v to i8 745 %old = atomicrmw nand ptr %p, i8 %t seq_cst 746 %e = sext i8 %old to i32 747 ret i32 %e 748} 749 750; CHECK-LABEL: nand_sext_i16_i32: 751; CHECK-NEXT: .functype nand_sext_i16_i32 (i32, i32) -> (i32){{$}} 752; CHECK: loop 753; CHECK: i32.atomic.rmw16.cmpxchg_u 754; CHECK: i32.extend16_s 755define i32 @nand_sext_i16_i32(ptr %p, i32 %v) { 756 %t = trunc i32 %v to i16 757 %old = atomicrmw nand ptr %p, i16 %t seq_cst 758 %e = sext i16 %old to i32 759 ret i32 %e 760} 761 762; FIXME Currently this cannot make use of i64.atomic.rmw8.cmpxchg_u 763; CHECK-LABEL: nand_sext_i8_i64: 764; CHECK-NEXT: .functype nand_sext_i8_i64 (i32, i64) -> (i64){{$}} 765; CHECK: loop 766; CHECK: i32.atomic.rmw8.cmpxchg_u 767; CHECK: i64.extend_i32_u 768; CHECK: i64.extend8_s 769define i64 @nand_sext_i8_i64(ptr %p, i64 %v) { 770 %t = trunc i64 %v to i8 771 %old = atomicrmw nand ptr %p, i8 %t seq_cst 772 %e = sext i8 %old to i64 773 ret i64 %e 774} 775 776; FIXME Currently this cannot make use of i64.atomic.rmw16.cmpxchg_u 777; CHECK-LABEL: nand_sext_i16_i64: 778; CHECK-NEXT: .functype nand_sext_i16_i64 (i32, i64) -> (i64){{$}} 779; CHECK: loop 780; CHECK: i32.atomic.rmw16.cmpxchg_u 781; CHECK: i64.extend_i32_u 782; CHECK: i64.extend16_s 783define i64 @nand_sext_i16_i64(ptr %p, i64 %v) { 784 %t = trunc i64 %v to i16 785 %old = atomicrmw nand ptr %p, i16 %t seq_cst 786 %e = sext i16 %old to i64 787 ret i64 %e 788} 789 790; 32->64 sext rmw gets selected as i32.atomic.rmw.nand, i64.extend_i32_s 791; CHECK-LABEL: nand_sext_i32_i64: 792; CHECK-NEXT: .functype nand_sext_i32_i64 (i32, i64) -> (i64){{$}} 793; CHECK: loop 794; CHECK: i32.atomic.rmw.cmpxchg 795; CHECK: i64.extend_i32_s 796define i64 @nand_sext_i32_i64(ptr %p, i64 %v) { 797 %t = trunc i64 %v to i32 798 %old = atomicrmw nand ptr %p, i32 %t seq_cst 799 %e = sext i32 %old to i64 800 ret i64 %e 801} 802 803;===---------------------------------------------------------------------------- 804; Atomic truncating & zero-extending RMWs 805;===---------------------------------------------------------------------------- 806 807; add 808 809; CHECK-LABEL: add_zext_i8_i32: 810; CHECK-NEXT: .functype add_zext_i8_i32 (i32, i32) -> (i32){{$}} 811; CHECK: i32.atomic.rmw8.add_u $push0=, 0($0), $1{{$}} 812; CHECK-NEXT: return $pop0{{$}} 813define i32 @add_zext_i8_i32(ptr %p, i32 %v) { 814 %t = trunc i32 %v to i8 815 %old = atomicrmw add ptr %p, i8 %t seq_cst 816 %e = zext i8 %old to i32 817 ret i32 %e 818} 819 820; CHECK-LABEL: add_zext_i16_i32: 821; CHECK-NEXT: .functype add_zext_i16_i32 (i32, i32) -> (i32){{$}} 822; CHECK: i32.atomic.rmw16.add_u $push0=, 0($0), $1{{$}} 823; CHECK-NEXT: return $pop0{{$}} 824define i32 @add_zext_i16_i32(ptr %p, i32 %v) { 825 %t = trunc i32 %v to i16 826 %old = atomicrmw add ptr %p, i16 %t seq_cst 827 %e = zext i16 %old to i32 828 ret i32 %e 829} 830 831; CHECK-LABEL: add_zext_i8_i64: 832; CHECK-NEXT: .functype add_zext_i8_i64 (i32, i64) -> (i64){{$}} 833; CHECK: i64.atomic.rmw8.add_u $push0=, 0($0), $1{{$}} 834; CHECK-NEXT: return $pop0{{$}} 835define i64 @add_zext_i8_i64(ptr %p, i64 %v) { 836 %t = trunc i64 %v to i8 837 %old = atomicrmw add ptr %p, i8 %t seq_cst 838 %e = zext i8 %old to i64 839 ret i64 %e 840} 841 842; CHECK-LABEL: add_zext_i16_i64: 843; CHECK-NEXT: .functype add_zext_i16_i64 (i32, i64) -> (i64){{$}} 844; CHECK: i64.atomic.rmw16.add_u $push0=, 0($0), $1{{$}} 845; CHECK-NEXT: return $pop0{{$}} 846define i64 @add_zext_i16_i64(ptr %p, i64 %v) { 847 %t = trunc i64 %v to i16 848 %old = atomicrmw add ptr %p, i16 %t seq_cst 849 %e = zext i16 %old to i64 850 ret i64 %e 851} 852 853; CHECK-LABEL: add_zext_i32_i64: 854; CHECK-NEXT: .functype add_zext_i32_i64 (i32, i64) -> (i64){{$}} 855; CHECK: i64.atomic.rmw32.add_u $push0=, 0($0), $1{{$}} 856; CHECK-NEXT: return $pop0{{$}} 857define i64 @add_zext_i32_i64(ptr %p, i64 %v) { 858 %t = trunc i64 %v to i32 859 %old = atomicrmw add ptr %p, i32 %t seq_cst 860 %e = zext i32 %old to i64 861 ret i64 %e 862} 863 864; sub 865 866; CHECK-LABEL: sub_zext_i8_i32: 867; CHECK-NEXT: .functype sub_zext_i8_i32 (i32, i32) -> (i32){{$}} 868; CHECK: i32.atomic.rmw8.sub_u $push0=, 0($0), $1{{$}} 869; CHECK-NEXT: return $pop0{{$}} 870define i32 @sub_zext_i8_i32(ptr %p, i32 %v) { 871 %t = trunc i32 %v to i8 872 %old = atomicrmw sub ptr %p, i8 %t seq_cst 873 %e = zext i8 %old to i32 874 ret i32 %e 875} 876 877; CHECK-LABEL: sub_zext_i16_i32: 878; CHECK-NEXT: .functype sub_zext_i16_i32 (i32, i32) -> (i32){{$}} 879; CHECK: i32.atomic.rmw16.sub_u $push0=, 0($0), $1{{$}} 880; CHECK-NEXT: return $pop0{{$}} 881define i32 @sub_zext_i16_i32(ptr %p, i32 %v) { 882 %t = trunc i32 %v to i16 883 %old = atomicrmw sub ptr %p, i16 %t seq_cst 884 %e = zext i16 %old to i32 885 ret i32 %e 886} 887 888; CHECK-LABEL: sub_zext_i8_i64: 889; CHECK-NEXT: .functype sub_zext_i8_i64 (i32, i64) -> (i64){{$}} 890; CHECK: i64.atomic.rmw8.sub_u $push0=, 0($0), $1{{$}} 891; CHECK-NEXT: return $pop0{{$}} 892define i64 @sub_zext_i8_i64(ptr %p, i64 %v) { 893 %t = trunc i64 %v to i8 894 %old = atomicrmw sub ptr %p, i8 %t seq_cst 895 %e = zext i8 %old to i64 896 ret i64 %e 897} 898 899; CHECK-LABEL: sub_zext_i16_i64: 900; CHECK-NEXT: .functype sub_zext_i16_i64 (i32, i64) -> (i64){{$}} 901; CHECK: i64.atomic.rmw16.sub_u $push0=, 0($0), $1{{$}} 902; CHECK-NEXT: return $pop0{{$}} 903define i64 @sub_zext_i16_i64(ptr %p, i64 %v) { 904 %t = trunc i64 %v to i16 905 %old = atomicrmw sub ptr %p, i16 %t seq_cst 906 %e = zext i16 %old to i64 907 ret i64 %e 908} 909 910; CHECK-LABEL: sub_zext_i32_i64: 911; CHECK-NEXT: .functype sub_zext_i32_i64 (i32, i64) -> (i64){{$}} 912; CHECK: i64.atomic.rmw32.sub_u $push0=, 0($0), $1{{$}} 913; CHECK-NEXT: return $pop0{{$}} 914define i64 @sub_zext_i32_i64(ptr %p, i64 %v) { 915 %t = trunc i64 %v to i32 916 %old = atomicrmw sub ptr %p, i32 %t seq_cst 917 %e = zext i32 %old to i64 918 ret i64 %e 919} 920 921; and 922 923; CHECK-LABEL: and_zext_i8_i32: 924; CHECK-NEXT: .functype and_zext_i8_i32 (i32, i32) -> (i32){{$}} 925; CHECK: i32.atomic.rmw8.and_u $push0=, 0($0), $1{{$}} 926; CHECK-NEXT: return $pop0{{$}} 927define i32 @and_zext_i8_i32(ptr %p, i32 %v) { 928 %t = trunc i32 %v to i8 929 %old = atomicrmw and ptr %p, i8 %t seq_cst 930 %e = zext i8 %old to i32 931 ret i32 %e 932} 933 934; CHECK-LABEL: and_zext_i16_i32: 935; CHECK-NEXT: .functype and_zext_i16_i32 (i32, i32) -> (i32){{$}} 936; CHECK: i32.atomic.rmw16.and_u $push0=, 0($0), $1{{$}} 937; CHECK-NEXT: return $pop0{{$}} 938define i32 @and_zext_i16_i32(ptr %p, i32 %v) { 939 %t = trunc i32 %v to i16 940 %old = atomicrmw and ptr %p, i16 %t seq_cst 941 %e = zext i16 %old to i32 942 ret i32 %e 943} 944 945; CHECK-LABEL: and_zext_i8_i64: 946; CHECK-NEXT: .functype and_zext_i8_i64 (i32, i64) -> (i64){{$}} 947; CHECK: i64.atomic.rmw8.and_u $push0=, 0($0), $1{{$}} 948; CHECK-NEXT: return $pop0{{$}} 949define i64 @and_zext_i8_i64(ptr %p, i64 %v) { 950 %t = trunc i64 %v to i8 951 %old = atomicrmw and ptr %p, i8 %t seq_cst 952 %e = zext i8 %old to i64 953 ret i64 %e 954} 955 956; CHECK-LABEL: and_zext_i16_i64: 957; CHECK-NEXT: .functype and_zext_i16_i64 (i32, i64) -> (i64){{$}} 958; CHECK: i64.atomic.rmw16.and_u $push0=, 0($0), $1{{$}} 959; CHECK-NEXT: return $pop0{{$}} 960define i64 @and_zext_i16_i64(ptr %p, i64 %v) { 961 %t = trunc i64 %v to i16 962 %old = atomicrmw and ptr %p, i16 %t seq_cst 963 %e = zext i16 %old to i64 964 ret i64 %e 965} 966 967; CHECK-LABEL: and_zext_i32_i64: 968; CHECK-NEXT: .functype and_zext_i32_i64 (i32, i64) -> (i64){{$}} 969; CHECK: i64.atomic.rmw32.and_u $push0=, 0($0), $1{{$}} 970; CHECK-NEXT: return $pop0{{$}} 971define i64 @and_zext_i32_i64(ptr %p, i64 %v) { 972 %t = trunc i64 %v to i32 973 %old = atomicrmw and ptr %p, i32 %t seq_cst 974 %e = zext i32 %old to i64 975 ret i64 %e 976} 977 978; or 979 980; CHECK-LABEL: or_zext_i8_i32: 981; CHECK-NEXT: .functype or_zext_i8_i32 (i32, i32) -> (i32){{$}} 982; CHECK: i32.atomic.rmw8.or_u $push0=, 0($0), $1{{$}} 983; CHECK-NEXT: return $pop0{{$}} 984define i32 @or_zext_i8_i32(ptr %p, i32 %v) { 985 %t = trunc i32 %v to i8 986 %old = atomicrmw or ptr %p, i8 %t seq_cst 987 %e = zext i8 %old to i32 988 ret i32 %e 989} 990 991; CHECK-LABEL: or_zext_i16_i32: 992; CHECK-NEXT: .functype or_zext_i16_i32 (i32, i32) -> (i32){{$}} 993; CHECK: i32.atomic.rmw16.or_u $push0=, 0($0), $1{{$}} 994; CHECK-NEXT: return $pop0{{$}} 995define i32 @or_zext_i16_i32(ptr %p, i32 %v) { 996 %t = trunc i32 %v to i16 997 %old = atomicrmw or ptr %p, i16 %t seq_cst 998 %e = zext i16 %old to i32 999 ret i32 %e 1000} 1001 1002; CHECK-LABEL: or_zext_i8_i64: 1003; CHECK-NEXT: .functype or_zext_i8_i64 (i32, i64) -> (i64){{$}} 1004; CHECK: i64.atomic.rmw8.or_u $push0=, 0($0), $1{{$}} 1005; CHECK-NEXT: return $pop0{{$}} 1006define i64 @or_zext_i8_i64(ptr %p, i64 %v) { 1007 %t = trunc i64 %v to i8 1008 %old = atomicrmw or ptr %p, i8 %t seq_cst 1009 %e = zext i8 %old to i64 1010 ret i64 %e 1011} 1012 1013; CHECK-LABEL: or_zext_i16_i64: 1014; CHECK-NEXT: .functype or_zext_i16_i64 (i32, i64) -> (i64){{$}} 1015; CHECK: i64.atomic.rmw16.or_u $push0=, 0($0), $1{{$}} 1016; CHECK-NEXT: return $pop0{{$}} 1017define i64 @or_zext_i16_i64(ptr %p, i64 %v) { 1018 %t = trunc i64 %v to i16 1019 %old = atomicrmw or ptr %p, i16 %t seq_cst 1020 %e = zext i16 %old to i64 1021 ret i64 %e 1022} 1023 1024; CHECK-LABEL: or_zext_i32_i64: 1025; CHECK-NEXT: .functype or_zext_i32_i64 (i32, i64) -> (i64){{$}} 1026; CHECK: i64.atomic.rmw32.or_u $push0=, 0($0), $1{{$}} 1027; CHECK-NEXT: return $pop0{{$}} 1028define i64 @or_zext_i32_i64(ptr %p, i64 %v) { 1029 %t = trunc i64 %v to i32 1030 %old = atomicrmw or ptr %p, i32 %t seq_cst 1031 %e = zext i32 %old to i64 1032 ret i64 %e 1033} 1034 1035; xor 1036 1037; CHECK-LABEL: xor_zext_i8_i32: 1038; CHECK-NEXT: .functype xor_zext_i8_i32 (i32, i32) -> (i32){{$}} 1039; CHECK: i32.atomic.rmw8.xor_u $push0=, 0($0), $1{{$}} 1040; CHECK-NEXT: return $pop0{{$}} 1041define i32 @xor_zext_i8_i32(ptr %p, i32 %v) { 1042 %t = trunc i32 %v to i8 1043 %old = atomicrmw xor ptr %p, i8 %t seq_cst 1044 %e = zext i8 %old to i32 1045 ret i32 %e 1046} 1047 1048; CHECK-LABEL: xor_zext_i16_i32: 1049; CHECK-NEXT: .functype xor_zext_i16_i32 (i32, i32) -> (i32){{$}} 1050; CHECK: i32.atomic.rmw16.xor_u $push0=, 0($0), $1{{$}} 1051; CHECK-NEXT: return $pop0{{$}} 1052define i32 @xor_zext_i16_i32(ptr %p, i32 %v) { 1053 %t = trunc i32 %v to i16 1054 %old = atomicrmw xor ptr %p, i16 %t seq_cst 1055 %e = zext i16 %old to i32 1056 ret i32 %e 1057} 1058 1059; CHECK-LABEL: xor_zext_i8_i64: 1060; CHECK-NEXT: .functype xor_zext_i8_i64 (i32, i64) -> (i64){{$}} 1061; CHECK: i64.atomic.rmw8.xor_u $push0=, 0($0), $1{{$}} 1062; CHECK-NEXT: return $pop0{{$}} 1063define i64 @xor_zext_i8_i64(ptr %p, i64 %v) { 1064 %t = trunc i64 %v to i8 1065 %old = atomicrmw xor ptr %p, i8 %t seq_cst 1066 %e = zext i8 %old to i64 1067 ret i64 %e 1068} 1069 1070; CHECK-LABEL: xor_zext_i16_i64: 1071; CHECK-NEXT: .functype xor_zext_i16_i64 (i32, i64) -> (i64){{$}} 1072; CHECK: i64.atomic.rmw16.xor_u $push0=, 0($0), $1{{$}} 1073; CHECK-NEXT: return $pop0{{$}} 1074define i64 @xor_zext_i16_i64(ptr %p, i64 %v) { 1075 %t = trunc i64 %v to i16 1076 %old = atomicrmw xor ptr %p, i16 %t seq_cst 1077 %e = zext i16 %old to i64 1078 ret i64 %e 1079} 1080 1081; CHECK-LABEL: xor_zext_i32_i64: 1082; CHECK-NEXT: .functype xor_zext_i32_i64 (i32, i64) -> (i64){{$}} 1083; CHECK: i64.atomic.rmw32.xor_u $push0=, 0($0), $1{{$}} 1084; CHECK-NEXT: return $pop0{{$}} 1085define i64 @xor_zext_i32_i64(ptr %p, i64 %v) { 1086 %t = trunc i64 %v to i32 1087 %old = atomicrmw xor ptr %p, i32 %t seq_cst 1088 %e = zext i32 %old to i64 1089 ret i64 %e 1090} 1091 1092; xchg 1093 1094; CHECK-LABEL: xchg_zext_i8_i32: 1095; CHECK-NEXT: .functype xchg_zext_i8_i32 (i32, i32) -> (i32){{$}} 1096; CHECK: i32.atomic.rmw8.xchg_u $push0=, 0($0), $1{{$}} 1097; CHECK-NEXT: return $pop0{{$}} 1098define i32 @xchg_zext_i8_i32(ptr %p, i32 %v) { 1099 %t = trunc i32 %v to i8 1100 %old = atomicrmw xchg ptr %p, i8 %t seq_cst 1101 %e = zext i8 %old to i32 1102 ret i32 %e 1103} 1104 1105; CHECK-LABEL: xchg_zext_i16_i32: 1106; CHECK-NEXT: .functype xchg_zext_i16_i32 (i32, i32) -> (i32){{$}} 1107; CHECK: i32.atomic.rmw16.xchg_u $push0=, 0($0), $1{{$}} 1108; CHECK-NEXT: return $pop0{{$}} 1109define i32 @xchg_zext_i16_i32(ptr %p, i32 %v) { 1110 %t = trunc i32 %v to i16 1111 %old = atomicrmw xchg ptr %p, i16 %t seq_cst 1112 %e = zext i16 %old to i32 1113 ret i32 %e 1114} 1115 1116; CHECK-LABEL: xchg_zext_i8_i64: 1117; CHECK-NEXT: .functype xchg_zext_i8_i64 (i32, i64) -> (i64){{$}} 1118; CHECK: i64.atomic.rmw8.xchg_u $push0=, 0($0), $1{{$}} 1119; CHECK-NEXT: return $pop0{{$}} 1120define i64 @xchg_zext_i8_i64(ptr %p, i64 %v) { 1121 %t = trunc i64 %v to i8 1122 %old = atomicrmw xchg ptr %p, i8 %t seq_cst 1123 %e = zext i8 %old to i64 1124 ret i64 %e 1125} 1126 1127; CHECK-LABEL: xchg_zext_i16_i64: 1128; CHECK-NEXT: .functype xchg_zext_i16_i64 (i32, i64) -> (i64){{$}} 1129; CHECK: i64.atomic.rmw16.xchg_u $push0=, 0($0), $1{{$}} 1130; CHECK-NEXT: return $pop0{{$}} 1131define i64 @xchg_zext_i16_i64(ptr %p, i64 %v) { 1132 %t = trunc i64 %v to i16 1133 %old = atomicrmw xchg ptr %p, i16 %t seq_cst 1134 %e = zext i16 %old to i64 1135 ret i64 %e 1136} 1137 1138; CHECK-LABEL: xchg_zext_i32_i64: 1139; CHECK-NEXT: .functype xchg_zext_i32_i64 (i32, i64) -> (i64){{$}} 1140; CHECK: i64.atomic.rmw32.xchg_u $push0=, 0($0), $1{{$}} 1141; CHECK-NEXT: return $pop0{{$}} 1142define i64 @xchg_zext_i32_i64(ptr %p, i64 %v) { 1143 %t = trunc i64 %v to i32 1144 %old = atomicrmw xchg ptr %p, i32 %t seq_cst 1145 %e = zext i32 %old to i64 1146 ret i64 %e 1147} 1148 1149; cmpxchg 1150 1151; CHECK-LABEL: cmpxchg_zext_i8_i32: 1152; CHECK-NEXT: .functype cmpxchg_zext_i8_i32 (i32, i32, i32) -> (i32){{$}} 1153; CHECK: i32.atomic.rmw8.cmpxchg_u $push0=, 0($0), $1, $2{{$}} 1154; CHECK-NEXT: return $pop0{{$}} 1155define i32 @cmpxchg_zext_i8_i32(ptr %p, i32 %exp, i32 %new) { 1156 %exp_t = trunc i32 %exp to i8 1157 %new_t = trunc i32 %new to i8 1158 %pair = cmpxchg ptr %p, i8 %exp_t, i8 %new_t seq_cst seq_cst 1159 %old = extractvalue { i8, i1 } %pair, 0 1160 %e = zext i8 %old to i32 1161 ret i32 %e 1162} 1163 1164; CHECK-LABEL: cmpxchg_zext_i16_i32: 1165; CHECK-NEXT: .functype cmpxchg_zext_i16_i32 (i32, i32, i32) -> (i32){{$}} 1166; CHECK: i32.atomic.rmw16.cmpxchg_u $push0=, 0($0), $1, $2{{$}} 1167; CHECK-NEXT: return $pop0{{$}} 1168define i32 @cmpxchg_zext_i16_i32(ptr %p, i32 %exp, i32 %new) { 1169 %exp_t = trunc i32 %exp to i16 1170 %new_t = trunc i32 %new to i16 1171 %pair = cmpxchg ptr %p, i16 %exp_t, i16 %new_t seq_cst seq_cst 1172 %old = extractvalue { i16, i1 } %pair, 0 1173 %e = zext i16 %old to i32 1174 ret i32 %e 1175} 1176 1177; CHECK-LABEL: cmpxchg_zext_i8_i64: 1178; CHECK-NEXT: .functype cmpxchg_zext_i8_i64 (i32, i64, i64) -> (i64){{$}} 1179; CHECK: i64.atomic.rmw8.cmpxchg_u $push0=, 0($0), $1, $2{{$}} 1180; CHECK-NEXT: return $pop0{{$}} 1181define i64 @cmpxchg_zext_i8_i64(ptr %p, i64 %exp, i64 %new) { 1182 %exp_t = trunc i64 %exp to i8 1183 %new_t = trunc i64 %new to i8 1184 %pair = cmpxchg ptr %p, i8 %exp_t, i8 %new_t seq_cst seq_cst 1185 %old = extractvalue { i8, i1 } %pair, 0 1186 %e = zext i8 %old to i64 1187 ret i64 %e 1188} 1189 1190; CHECK-LABEL: cmpxchg_zext_i16_i64: 1191; CHECK-NEXT: .functype cmpxchg_zext_i16_i64 (i32, i64, i64) -> (i64){{$}} 1192; CHECK: i64.atomic.rmw16.cmpxchg_u $push0=, 0($0), $1, $2{{$}} 1193; CHECK-NEXT: return $pop0{{$}} 1194define i64 @cmpxchg_zext_i16_i64(ptr %p, i64 %exp, i64 %new) { 1195 %exp_t = trunc i64 %exp to i16 1196 %new_t = trunc i64 %new to i16 1197 %pair = cmpxchg ptr %p, i16 %exp_t, i16 %new_t seq_cst seq_cst 1198 %old = extractvalue { i16, i1 } %pair, 0 1199 %e = zext i16 %old to i64 1200 ret i64 %e 1201} 1202 1203; CHECK-LABEL: cmpxchg_zext_i32_i64: 1204; CHECK-NEXT: .functype cmpxchg_zext_i32_i64 (i32, i64, i64) -> (i64){{$}} 1205; CHECK: i64.atomic.rmw32.cmpxchg_u $push0=, 0($0), $1, $2{{$}} 1206; CHECK-NEXT: return $pop0{{$}} 1207define i64 @cmpxchg_zext_i32_i64(ptr %p, i64 %exp, i64 %new) { 1208 %exp_t = trunc i64 %exp to i32 1209 %new_t = trunc i64 %new to i32 1210 %pair = cmpxchg ptr %p, i32 %exp_t, i32 %new_t seq_cst seq_cst 1211 %old = extractvalue { i32, i1 } %pair, 0 1212 %e = zext i32 %old to i64 1213 ret i64 %e 1214} 1215 1216; Unsupported instructions are expanded using cmpxchg with a loop. 1217; Here we take a nand as an example. 1218 1219; nand 1220 1221; CHECK-LABEL: nand_zext_i8_i32: 1222; CHECK-NEXT: .functype nand_zext_i8_i32 (i32, i32) -> (i32){{$}} 1223; CHECK: loop 1224; CHECK: i32.atomic.rmw8.cmpxchg_u 1225define i32 @nand_zext_i8_i32(ptr %p, i32 %v) { 1226 %t = trunc i32 %v to i8 1227 %old = atomicrmw nand ptr %p, i8 %t seq_cst 1228 %e = zext i8 %old to i32 1229 ret i32 %e 1230} 1231 1232; CHECK-LABEL: nand_zext_i16_i32: 1233; CHECK-NEXT: .functype nand_zext_i16_i32 (i32, i32) -> (i32){{$}} 1234; CHECK: loop 1235; CHECK: i32.atomic.rmw16.cmpxchg_u 1236define i32 @nand_zext_i16_i32(ptr %p, i32 %v) { 1237 %t = trunc i32 %v to i16 1238 %old = atomicrmw nand ptr %p, i16 %t seq_cst 1239 %e = zext i16 %old to i32 1240 ret i32 %e 1241} 1242 1243; FIXME Currently this cannot make use of i64.atomic.rmw8.cmpxchg_u 1244; CHECK-LABEL: nand_zext_i8_i64: 1245; CHECK-NEXT: .functype nand_zext_i8_i64 (i32, i64) -> (i64){{$}} 1246; CHECK: loop 1247; CHECK: i32.atomic.rmw8.cmpxchg_u 1248; CHECK: i64.extend_i32_u 1249define i64 @nand_zext_i8_i64(ptr %p, i64 %v) { 1250 %t = trunc i64 %v to i8 1251 %old = atomicrmw nand ptr %p, i8 %t seq_cst 1252 %e = zext i8 %old to i64 1253 ret i64 %e 1254} 1255 1256; FIXME Currently this cannot make use of i64.atomic.rmw16.cmpxchg_u 1257; CHECK-LABEL: nand_zext_i16_i64: 1258; CHECK-NEXT: .functype nand_zext_i16_i64 (i32, i64) -> (i64){{$}} 1259; CHECK: loop 1260; CHECK: i32.atomic.rmw16.cmpxchg_u 1261; CHECK: i64.extend_i32_u 1262define i64 @nand_zext_i16_i64(ptr %p, i64 %v) { 1263 %t = trunc i64 %v to i16 1264 %old = atomicrmw nand ptr %p, i16 %t seq_cst 1265 %e = zext i16 %old to i64 1266 ret i64 %e 1267} 1268 1269; FIXME Currently this cannot make use of i64.atomic.rmw32.cmpxchg_u 1270; CHECK-LABEL: nand_zext_i32_i64: 1271; CHECK-NEXT: .functype nand_zext_i32_i64 (i32, i64) -> (i64){{$}} 1272; CHECK: loop 1273; CHECK: i32.atomic.rmw.cmpxchg 1274; CHECK: i64.extend_i32_u 1275define i64 @nand_zext_i32_i64(ptr %p, i64 %v) { 1276 %t = trunc i64 %v to i32 1277 %old = atomicrmw nand ptr %p, i32 %t seq_cst 1278 %e = zext i32 %old to i64 1279 ret i64 %e 1280} 1281