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