brintos

brintos / llvm-project-archived public Read only

0
0
Text · 60.9 KiB · 466b82e Raw
1793 lines · plain
1; RUN: not --crash llc > /dev/null < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt2; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -mattr=+atomics,+sign-ext | FileCheck %s3 4; Test that atomic loads are assembled properly.5 6target triple = "wasm32-unknown-unknown"7 8;===----------------------------------------------------------------------------9; Atomic loads: 32-bit10;===----------------------------------------------------------------------------11 12; Basic load.13 14; CHECK-LABEL: load_i32_no_offset:15; CHECK: i32.atomic.load $push0=, 0($0){{$}}16; CHECK-NEXT: return $pop0{{$}}17define i32 @load_i32_no_offset(ptr %p) {18  %v = load atomic i32, ptr %p seq_cst, align 419  ret i32 %v20}21 22; With an nuw add, we can fold an offset.23 24; CHECK-LABEL: load_i32_with_folded_offset:25; CHECK: i32.atomic.load $push0=, 24($0){{$}}26define i32 @load_i32_with_folded_offset(ptr %p) {27  %q = ptrtoint ptr %p to i3228  %r = add nuw i32 %q, 2429  %s = inttoptr i32 %r to ptr30  %t = load atomic i32, ptr %s seq_cst, align 431  ret i32 %t32}33 34; With an inbounds gep, we can fold an offset.35 36; CHECK-LABEL: load_i32_with_folded_gep_offset:37; CHECK: i32.atomic.load $push0=, 24($0){{$}}38define i32 @load_i32_with_folded_gep_offset(ptr %p) {39  %s = getelementptr inbounds i32, ptr %p, i32 640  %t = load atomic i32, ptr %s seq_cst, align 441  ret i32 %t42}43 44; We can't fold a negative offset though, even with an inbounds gep.45 46; CHECK-LABEL: load_i32_with_unfolded_gep_negative_offset:47; CHECK: i32.const $push0=, -24{{$}}48; CHECK: i32.add $push1=, $0, $pop0{{$}}49; CHECK: i32.atomic.load $push2=, 0($pop1){{$}}50define i32 @load_i32_with_unfolded_gep_negative_offset(ptr %p) {51  %s = getelementptr inbounds i32, ptr %p, i32 -652  %t = load atomic i32, ptr %s seq_cst, align 453  ret i32 %t54}55 56; Without nuw, and even with nsw, we can't fold an offset.57 58; CHECK-LABEL: load_i32_with_unfolded_offset:59; CHECK: i32.const $push0=, 24{{$}}60; CHECK: i32.add $push1=, $0, $pop0{{$}}61; CHECK: i32.atomic.load $push2=, 0($pop1){{$}}62define i32 @load_i32_with_unfolded_offset(ptr %p) {63  %q = ptrtoint ptr %p to i3264  %r = add nsw i32 %q, 2465  %s = inttoptr i32 %r to ptr66  %t = load atomic i32, ptr %s seq_cst, align 467  ret i32 %t68}69 70; Without inbounds, we can't fold a gep offset.71 72; CHECK-LABEL: load_i32_with_unfolded_gep_offset:73; CHECK: i32.const $push0=, 24{{$}}74; CHECK: i32.add $push1=, $0, $pop0{{$}}75; CHECK: i32.atomic.load $push2=, 0($pop1){{$}}76define i32 @load_i32_with_unfolded_gep_offset(ptr %p) {77  %s = getelementptr i32, ptr %p, i32 678  %t = load atomic i32, ptr %s seq_cst, align 479  ret i32 %t80}81 82; When loading from a fixed address, materialize a zero.83 84; CHECK-LABEL: load_i32_from_numeric_address85; CHECK: i32.const $push0=, 0{{$}}86; CHECK: i32.atomic.load $push1=, 42($pop0){{$}}87define i32 @load_i32_from_numeric_address() {88  %s = inttoptr i32 42 to ptr89  %t = load atomic i32, ptr %s seq_cst, align 490  ret i32 %t91}92 93; CHECK-LABEL: load_i32_from_global_address94; CHECK: i32.const $push0=, 0{{$}}95; CHECK: i32.atomic.load $push1=, gv($pop0){{$}}96@gv = global i32 097define i32 @load_i32_from_global_address() {98  %t = load atomic i32, ptr @gv seq_cst, align 499  ret i32 %t100}101 102;===----------------------------------------------------------------------------103; Atomic loads: 64-bit104;===----------------------------------------------------------------------------105 106; Basic load.107 108; CHECK-LABEL: load_i64_no_offset:109; CHECK: i64.atomic.load $push0=, 0($0){{$}}110; CHECK-NEXT: return $pop0{{$}}111define i64 @load_i64_no_offset(ptr %p) {112  %v = load atomic i64, ptr %p seq_cst, align 8113  ret i64 %v114}115 116; With an nuw add, we can fold an offset.117 118; CHECK-LABEL: load_i64_with_folded_offset:119; CHECK: i64.atomic.load $push0=, 24($0){{$}}120define i64 @load_i64_with_folded_offset(ptr %p) {121  %q = ptrtoint ptr %p to i32122  %r = add nuw i32 %q, 24123  %s = inttoptr i32 %r to ptr124  %t = load atomic i64, ptr %s seq_cst, align 8125  ret i64 %t126}127 128; With an inbounds gep, we can fold an offset.129 130; CHECK-LABEL: load_i64_with_folded_gep_offset:131; CHECK: i64.atomic.load $push0=, 24($0){{$}}132define i64 @load_i64_with_folded_gep_offset(ptr %p) {133  %s = getelementptr inbounds i64, ptr %p, i32 3134  %t = load atomic i64, ptr %s seq_cst, align 8135  ret i64 %t136}137 138; We can't fold a negative offset though, even with an inbounds gep.139 140; CHECK-LABEL: load_i64_with_unfolded_gep_negative_offset:141; CHECK: i32.const $push0=, -24{{$}}142; CHECK: i32.add $push1=, $0, $pop0{{$}}143; CHECK: i64.atomic.load $push2=, 0($pop1){{$}}144define i64 @load_i64_with_unfolded_gep_negative_offset(ptr %p) {145  %s = getelementptr inbounds i64, ptr %p, i32 -3146  %t = load atomic i64, ptr %s seq_cst, align 8147  ret i64 %t148}149 150; Without nuw, and even with nsw, we can't fold an offset.151 152; CHECK-LABEL: load_i64_with_unfolded_offset:153; CHECK: i32.const $push0=, 24{{$}}154; CHECK: i32.add $push1=, $0, $pop0{{$}}155; CHECK: i64.atomic.load $push2=, 0($pop1){{$}}156define i64 @load_i64_with_unfolded_offset(ptr %p) {157  %q = ptrtoint ptr %p to i32158  %r = add nsw i32 %q, 24159  %s = inttoptr i32 %r to ptr160  %t = load atomic i64, ptr %s seq_cst, align 8161  ret i64 %t162}163 164; Without inbounds, we can't fold a gep offset.165 166; CHECK-LABEL: load_i64_with_unfolded_gep_offset:167; CHECK: i32.const $push0=, 24{{$}}168; CHECK: i32.add $push1=, $0, $pop0{{$}}169; CHECK: i64.atomic.load $push2=, 0($pop1){{$}}170define i64 @load_i64_with_unfolded_gep_offset(ptr %p) {171  %s = getelementptr i64, ptr %p, i32 3172  %t = load atomic i64, ptr %s seq_cst, align 8173  ret i64 %t174}175 176;===----------------------------------------------------------------------------177; Atomic stores: 32-bit178;===----------------------------------------------------------------------------179 180; Basic store.181 182; CHECK-LABEL: store_i32_no_offset:183; CHECK-NEXT: .functype store_i32_no_offset (i32, i32) -> (){{$}}184; CHECK-NEXT: i32.atomic.store 0($0), $1{{$}}185; CHECK-NEXT: return{{$}}186define void @store_i32_no_offset(ptr %p, i32 %v) {187  store atomic i32 %v, ptr %p seq_cst, align 4188  ret void189}190 191; With an nuw add, we can fold an offset.192 193; CHECK-LABEL: store_i32_with_folded_offset:194; CHECK: i32.atomic.store 24($0), $pop0{{$}}195define void @store_i32_with_folded_offset(ptr %p) {196  %q = ptrtoint ptr %p to i32197  %r = add nuw i32 %q, 24198  %s = inttoptr i32 %r to ptr199  store atomic i32 0, ptr %s seq_cst, align 4200  ret void201}202 203; With an inbounds gep, we can fold an offset.204 205; CHECK-LABEL: store_i32_with_folded_gep_offset:206; CHECK: i32.atomic.store 24($0), $pop0{{$}}207define void @store_i32_with_folded_gep_offset(ptr %p) {208  %s = getelementptr inbounds i32, ptr %p, i32 6209  store atomic i32 0, ptr %s seq_cst, align 4210  ret void211}212 213; We can't fold a negative offset though, even with an inbounds gep.214 215; CHECK-LABEL: store_i32_with_unfolded_gep_negative_offset:216; CHECK: i32.const $push0=, -24{{$}}217; CHECK: i32.add $push1=, $0, $pop0{{$}}218; CHECK: i32.atomic.store 0($pop1), $pop2{{$}}219define void @store_i32_with_unfolded_gep_negative_offset(ptr %p) {220  %s = getelementptr inbounds i32, ptr %p, i32 -6221  store atomic i32 0, ptr %s seq_cst, align 4222  ret void223}224 225; Without nuw, and even with nsw, we can't fold an offset.226 227; CHECK-LABEL: store_i32_with_unfolded_offset:228; CHECK: i32.const $push0=, 24{{$}}229; CHECK: i32.add $push1=, $0, $pop0{{$}}230; CHECK: i32.atomic.store 0($pop1), $pop2{{$}}231define void @store_i32_with_unfolded_offset(ptr %p) {232  %q = ptrtoint ptr %p to i32233  %r = add nsw i32 %q, 24234  %s = inttoptr i32 %r to ptr235  store atomic i32 0, ptr %s seq_cst, align 4236  ret void237}238 239; Without inbounds, we can't fold a gep offset.240 241; CHECK-LABEL: store_i32_with_unfolded_gep_offset:242; CHECK: i32.const $push0=, 24{{$}}243; CHECK: i32.add $push1=, $0, $pop0{{$}}244; CHECK: i32.atomic.store 0($pop1), $pop2{{$}}245define void @store_i32_with_unfolded_gep_offset(ptr %p) {246  %s = getelementptr i32, ptr %p, i32 6247  store atomic i32 0, ptr %s seq_cst, align 4248  ret void249}250 251; When storing from a fixed address, materialize a zero.252 253; CHECK-LABEL: store_i32_to_numeric_address:254; CHECK:      i32.const $push0=, 0{{$}}255; CHECK-NEXT: i32.const $push1=, 0{{$}}256; CHECK-NEXT: i32.atomic.store 42($pop0), $pop1{{$}}257define void @store_i32_to_numeric_address() {258  %s = inttoptr i32 42 to ptr259  store atomic i32 0, ptr %s seq_cst, align 4260  ret void261}262 263; CHECK-LABEL: store_i32_to_global_address:264; CHECK: i32.const $push0=, 0{{$}}265; CHECK: i32.const $push1=, 0{{$}}266; CHECK: i32.atomic.store gv($pop0), $pop1{{$}}267define void @store_i32_to_global_address() {268  store atomic i32 0, ptr @gv seq_cst, align 4269  ret void270}271 272;===----------------------------------------------------------------------------273; Atomic stores: 64-bit274;===----------------------------------------------------------------------------275 276; Basic store.277 278; CHECK-LABEL: store_i64_no_offset:279; CHECK-NEXT: .functype store_i64_no_offset (i32, i64) -> (){{$}}280; CHECK-NEXT: i64.atomic.store 0($0), $1{{$}}281; CHECK-NEXT: return{{$}}282define void @store_i64_no_offset(ptr %p, i64 %v) {283  store atomic i64 %v, ptr %p seq_cst, align 8284  ret void285}286 287; With an nuw add, we can fold an offset.288 289; CHECK-LABEL: store_i64_with_folded_offset:290; CHECK: i64.atomic.store 24($0), $pop0{{$}}291define void @store_i64_with_folded_offset(ptr %p) {292  %q = ptrtoint ptr %p to i32293  %r = add nuw i32 %q, 24294  %s = inttoptr i32 %r to ptr295  store atomic i64 0, ptr %s seq_cst, align 8296  ret void297}298 299; With an inbounds gep, we can fold an offset.300 301; CHECK-LABEL: store_i64_with_folded_gep_offset:302; CHECK: i64.atomic.store 24($0), $pop0{{$}}303define void @store_i64_with_folded_gep_offset(ptr %p) {304  %s = getelementptr inbounds i64, ptr %p, i32 3305  store atomic i64 0, ptr %s seq_cst, align 8306  ret void307}308 309; We can't fold a negative offset though, even with an inbounds gep.310 311; CHECK-LABEL: store_i64_with_unfolded_gep_negative_offset:312; CHECK: i32.const $push0=, -24{{$}}313; CHECK: i32.add $push1=, $0, $pop0{{$}}314; CHECK: i64.atomic.store 0($pop1), $pop2{{$}}315define void @store_i64_with_unfolded_gep_negative_offset(ptr %p) {316  %s = getelementptr inbounds i64, ptr %p, i32 -3317  store atomic i64 0, ptr %s seq_cst, align 8318  ret void319}320 321; Without nuw, and even with nsw, we can't fold an offset.322 323; CHECK-LABEL: store_i64_with_unfolded_offset:324; CHECK: i32.const $push0=, 24{{$}}325; CHECK: i32.add $push1=, $0, $pop0{{$}}326; CHECK: i64.atomic.store 0($pop1), $pop2{{$}}327define void @store_i64_with_unfolded_offset(ptr %p) {328  %q = ptrtoint ptr %p to i32329  %r = add nsw i32 %q, 24330  %s = inttoptr i32 %r to ptr331  store atomic i64 0, ptr %s seq_cst, align 8332  ret void333}334 335; Without inbounds, we can't fold a gep offset.336 337; CHECK-LABEL: store_i64_with_unfolded_gep_offset:338; CHECK: i32.const $push0=, 24{{$}}339; CHECK: i32.add $push1=, $0, $pop0{{$}}340; CHECK: i64.atomic.store 0($pop1), $pop2{{$}}341define void @store_i64_with_unfolded_gep_offset(ptr %p) {342  %s = getelementptr i64, ptr %p, i32 3343  store atomic i64 0, ptr %s seq_cst, align 8344  ret void345}346 347;===----------------------------------------------------------------------------348; Atomic sign-extending loads349;===----------------------------------------------------------------------------350 351; Fold an offset into a sign-extending load.352 353; CHECK-LABEL: load_i8_i32_s_with_folded_offset:354; CHECK: i32.atomic.load8_u $push0=, 24($0){{$}}355; CHECK-NEXT: i32.extend8_s $push1=, $pop0356define i32 @load_i8_i32_s_with_folded_offset(ptr %p) {357  %q = ptrtoint ptr %p to i32358  %r = add nuw i32 %q, 24359  %s = inttoptr i32 %r to ptr360  %t = load atomic i8, ptr %s seq_cst, align 1361  %u = sext i8 %t to i32362  ret i32 %u363}364 365; 32->64 sext load gets selected as i32.atomic.load, i64.extend_i32_s366; CHECK-LABEL: load_i32_i64_s_with_folded_offset:367; CHECK: i32.atomic.load $push0=, 24($0){{$}}368; CHECK-NEXT: i64.extend_i32_s $push1=, $pop0{{$}}369define i64 @load_i32_i64_s_with_folded_offset(ptr %p) {370  %q = ptrtoint ptr %p to i32371  %r = add nuw i32 %q, 24372  %s = inttoptr i32 %r to ptr373  %t = load atomic i32, ptr %s seq_cst, align 4374  %u = sext i32 %t to i64375  ret i64 %u376}377 378; Fold a gep offset into a sign-extending load.379 380; CHECK-LABEL: load_i8_i32_s_with_folded_gep_offset:381; CHECK: i32.atomic.load8_u $push0=, 24($0){{$}}382; CHECK-NEXT: i32.extend8_s $push1=, $pop0383define i32 @load_i8_i32_s_with_folded_gep_offset(ptr %p) {384  %s = getelementptr inbounds i8, ptr %p, i32 24385  %t = load atomic i8, ptr %s seq_cst, align 1386  %u = sext i8 %t to i32387  ret i32 %u388}389 390; CHECK-LABEL: load_i16_i32_s_with_folded_gep_offset:391; CHECK: i32.atomic.load16_u $push0=, 48($0){{$}}392; CHECK-NEXT: i32.extend16_s $push1=, $pop0393define i32 @load_i16_i32_s_with_folded_gep_offset(ptr %p) {394  %s = getelementptr inbounds i16, ptr %p, i32 24395  %t = load atomic i16, ptr %s seq_cst, align 2396  %u = sext i16 %t to i32397  ret i32 %u398}399 400; CHECK-LABEL: load_i16_i64_s_with_folded_gep_offset:401; CHECK: i64.atomic.load16_u $push0=, 48($0){{$}}402; CHECK-NEXT: i64.extend16_s $push1=, $pop0403define i64 @load_i16_i64_s_with_folded_gep_offset(ptr %p) {404  %s = getelementptr inbounds i16, ptr %p, i32 24405  %t = load atomic i16, ptr %s seq_cst, align 2406  %u = sext i16 %t to i64407  ret i64 %u408}409 410; 'add' in this code becomes 'or' after DAG optimization. Treat an 'or' node as411; an 'add' if the or'ed bits are known to be zero.412 413; CHECK-LABEL: load_i8_i32_s_with_folded_or_offset:414; CHECK: i32.atomic.load8_u $push[[R1:[0-9]+]]=, 2($pop{{[0-9]+}}){{$}}415; CHECK-NEXT: i32.extend8_s $push{{[0-9]+}}=, $pop[[R1]]{{$}}416define i32 @load_i8_i32_s_with_folded_or_offset(i32 %x) {417  %and = and i32 %x, -4418  %t0 = inttoptr i32 %and to ptr419  %arrayidx = getelementptr inbounds i8, ptr %t0, i32 2420  %t1 = load atomic i8, ptr %arrayidx seq_cst, align 1421  %conv = sext i8 %t1 to i32422  ret i32 %conv423}424 425; CHECK-LABEL: load_i8_i64_s_with_folded_or_offset:426; CHECK: i64.atomic.load8_u $push[[R1:[0-9]+]]=, 2($pop{{[0-9]+}}){{$}}427; CHECK-NEXT: i64.extend8_s $push{{[0-9]+}}=, $pop[[R1]]{{$}}428define i64 @load_i8_i64_s_with_folded_or_offset(i32 %x) {429  %and = and i32 %x, -4430  %t0 = inttoptr i32 %and to ptr431  %arrayidx = getelementptr inbounds i8, ptr %t0, i32 2432  %t1 = load atomic i8, ptr %arrayidx seq_cst, align 1433  %conv = sext i8 %t1 to i64434  ret i64 %conv435}436 437; When loading from a fixed address, materialize a zero.438 439; CHECK-LABEL: load_i16_i32_s_from_numeric_address440; CHECK: i32.const $push0=, 0{{$}}441; CHECK: i32.atomic.load16_u $push1=, 42($pop0){{$}}442; CHECK-NEXT: i32.extend16_s $push2=, $pop1443define i32 @load_i16_i32_s_from_numeric_address() {444  %s = inttoptr i32 42 to ptr445  %t = load atomic i16, ptr %s seq_cst, align 2446  %u = sext i16 %t to i32447  ret i32 %u448}449 450; CHECK-LABEL: load_i8_i32_s_from_global_address451; CHECK: i32.const $push0=, 0{{$}}452; CHECK: i32.atomic.load8_u $push1=, gv8($pop0){{$}}453; CHECK-NEXT: i32.extend8_s $push2=, $pop1{{$}}454@gv8 = global i8 0455define i32 @load_i8_i32_s_from_global_address() {456  %t = load atomic i8, ptr @gv8 seq_cst, align 1457  %u = sext i8 %t to i32458  ret i32 %u459}460 461;===----------------------------------------------------------------------------462; Atomic zero-extending loads463;===----------------------------------------------------------------------------464 465; Fold an offset into a zero-extending load.466 467; CHECK-LABEL: load_i8_i32_z_with_folded_offset:468; CHECK: i32.atomic.load8_u $push0=, 24($0){{$}}469define i32 @load_i8_i32_z_with_folded_offset(ptr %p) {470  %q = ptrtoint ptr %p to i32471  %r = add nuw i32 %q, 24472  %s = inttoptr i32 %r to ptr473  %t = load atomic i8, ptr %s seq_cst, align 1474  %u = zext i8 %t to i32475  ret i32 %u476}477 478; CHECK-LABEL: load_i32_i64_z_with_folded_offset:479; CHECK: i64.atomic.load32_u $push0=, 24($0){{$}}480define i64 @load_i32_i64_z_with_folded_offset(ptr %p) {481  %q = ptrtoint ptr %p to i32482  %r = add nuw i32 %q, 24483  %s = inttoptr i32 %r to ptr484  %t = load atomic i32, ptr %s seq_cst, align 4485  %u = zext i32 %t to i64486  ret i64 %u487}488 489; Fold a gep offset into a zero-extending load.490 491; CHECK-LABEL: load_i8_i32_z_with_folded_gep_offset:492; CHECK: i32.atomic.load8_u $push0=, 24($0){{$}}493define i32 @load_i8_i32_z_with_folded_gep_offset(ptr %p) {494  %s = getelementptr inbounds i8, ptr %p, i32 24495  %t = load atomic i8, ptr %s seq_cst, align 1496  %u = zext i8 %t to i32497  ret i32 %u498}499 500; CHECK-LABEL: load_i16_i32_z_with_folded_gep_offset:501; CHECK: i32.atomic.load16_u $push0=, 48($0){{$}}502define i32 @load_i16_i32_z_with_folded_gep_offset(ptr %p) {503  %s = getelementptr inbounds i16, ptr %p, i32 24504  %t = load atomic i16, ptr %s seq_cst, align 2505  %u = zext i16 %t to i32506  ret i32 %u507}508 509; CHECK-LABEL: load_i16_i64_z_with_folded_gep_offset:510; CHECK: i64.atomic.load16_u $push0=, 48($0){{$}}511define i64 @load_i16_i64_z_with_folded_gep_offset(ptr %p) {512  %s = getelementptr inbounds i16, ptr %p, i64 24513  %t = load atomic i16, ptr %s seq_cst, align 2514  %u = zext i16 %t to i64515  ret i64 %u516}517 518; 'add' in this code becomes 'or' after DAG optimization. Treat an 'or' node as519; an 'add' if the or'ed bits are known to be zero.520 521; CHECK-LABEL: load_i8_i32_z_with_folded_or_offset:522; CHECK: i32.atomic.load8_u $push[[R1:[0-9]+]]=, 2($pop{{[0-9]+}}){{$}}523define i32 @load_i8_i32_z_with_folded_or_offset(i32 %x) {524  %and = and i32 %x, -4525  %t0 = inttoptr i32 %and to ptr526  %arrayidx = getelementptr inbounds i8, ptr %t0, i32 2527  %t1 = load atomic i8, ptr %arrayidx seq_cst, align 1528  %conv = zext i8 %t1 to i32529  ret i32 %conv530}531 532; CHECK-LABEL: load_i8_i64_z_with_folded_or_offset:533; CHECK: i64.atomic.load8_u $push[[R1:[0-9]+]]=, 2($pop{{[0-9]+}}){{$}}534define i64 @load_i8_i64_z_with_folded_or_offset(i32 %x) {535  %and = and i32 %x, -4536  %t0 = inttoptr i32 %and to ptr537  %arrayidx = getelementptr inbounds i8, ptr %t0, i32 2538  %t1 = load atomic i8, ptr %arrayidx seq_cst, align 1539  %conv = zext i8 %t1 to i64540  ret i64 %conv541}542 543; When loading from a fixed address, materialize a zero.544 545; CHECK-LABEL: load_i16_i32_z_from_numeric_address546; CHECK: i32.const $push0=, 0{{$}}547; CHECK: i32.atomic.load16_u $push1=, 42($pop0){{$}}548define i32 @load_i16_i32_z_from_numeric_address() {549  %s = inttoptr i32 42 to ptr550  %t = load atomic i16, ptr %s seq_cst, align 2551  %u = zext i16 %t to i32552  ret i32 %u553}554 555; CHECK-LABEL: load_i8_i32_z_from_global_address556; CHECK: i32.const $push0=, 0{{$}}557; CHECK: i32.atomic.load8_u $push1=, gv8($pop0){{$}}558define i32 @load_i8_i32_z_from_global_address() {559  %t = load atomic i8, ptr @gv8 seq_cst, align 1560  %u = zext i8 %t to i32561  ret i32 %u562}563 564; i8 return value should test anyext loads565 566; CHECK-LABEL: load_i8_i32_retvalue:567; CHECK: i32.atomic.load8_u $push0=, 0($0){{$}}568; CHECK-NEXT: return $pop0{{$}}569define i8 @load_i8_i32_retvalue(ptr %p) {570  %v = load atomic i8, ptr %p seq_cst, align 1571  ret i8 %v572}573 574;===----------------------------------------------------------------------------575; Atomic truncating stores576;===----------------------------------------------------------------------------577 578; Fold an offset into a truncating store.579 580; CHECK-LABEL: store_i8_i32_with_folded_offset:581; CHECK: i32.atomic.store8 24($0), $1{{$}}582define void @store_i8_i32_with_folded_offset(ptr %p, i32 %v) {583  %q = ptrtoint ptr %p to i32584  %r = add nuw i32 %q, 24585  %s = inttoptr i32 %r to ptr586  %t = trunc i32 %v to i8587  store atomic i8 %t, ptr %s seq_cst, align 1588  ret void589}590 591; CHECK-LABEL: store_i32_i64_with_folded_offset:592; CHECK: i64.atomic.store32 24($0), $1{{$}}593define void @store_i32_i64_with_folded_offset(ptr %p, i64 %v) {594  %q = ptrtoint ptr %p to i32595  %r = add nuw i32 %q, 24596  %s = inttoptr i32 %r to ptr597  %t = trunc i64 %v to i32598  store atomic i32 %t, ptr %s seq_cst, align 4599  ret void600}601 602; Fold a gep offset into a truncating store.603 604; CHECK-LABEL: store_i8_i32_with_folded_gep_offset:605; CHECK: i32.atomic.store8 24($0), $1{{$}}606define void @store_i8_i32_with_folded_gep_offset(ptr %p, i32 %v) {607  %s = getelementptr inbounds i8, ptr %p, i32 24608  %t = trunc i32 %v to i8609  store atomic i8 %t, ptr %s seq_cst, align 1610  ret void611}612 613; CHECK-LABEL: store_i16_i32_with_folded_gep_offset:614; CHECK: i32.atomic.store16 48($0), $1{{$}}615define void @store_i16_i32_with_folded_gep_offset(ptr %p, i32 %v) {616  %s = getelementptr inbounds i16, ptr %p, i32 24617  %t = trunc i32 %v to i16618  store atomic i16 %t, ptr %s seq_cst, align 2619  ret void620}621 622; CHECK-LABEL: store_i16_i64_with_folded_gep_offset:623; CHECK: i64.atomic.store16 48($0), $1{{$}}624define void @store_i16_i64_with_folded_gep_offset(ptr %p, i64 %v) {625  %s = getelementptr inbounds i16, ptr %p, i32 24626  %t = trunc i64 %v to i16627  store atomic i16 %t, ptr %s seq_cst, align 2628  ret void629}630 631; 'add' in this code becomes 'or' after DAG optimization. Treat an 'or' node as632; an 'add' if the or'ed bits are known to be zero.633 634; CHECK-LABEL: store_i8_i32_with_folded_or_offset:635; CHECK: i32.atomic.store8 2($pop{{[0-9]+}}), $1{{$}}636define void @store_i8_i32_with_folded_or_offset(i32 %x, i32 %v) {637  %and = and i32 %x, -4638  %p = inttoptr i32 %and to ptr639  %arrayidx = getelementptr inbounds i8, ptr %p, i32 2640  %t = trunc i32 %v to i8641  store atomic i8 %t, ptr %arrayidx seq_cst, align 1642  ret void643}644 645; CHECK-LABEL: store_i8_i64_with_folded_or_offset:646; CHECK: i64.atomic.store8 2($pop{{[0-9]+}}), $1{{$}}647define void @store_i8_i64_with_folded_or_offset(i32 %x, i64 %v) {648  %and = and i32 %x, -4649  %p = inttoptr i32 %and to ptr650  %arrayidx = getelementptr inbounds i8, ptr %p, i32 2651  %t = trunc i64 %v to i8652  store atomic i8 %t, ptr %arrayidx seq_cst, align 1653  ret void654}655 656;===----------------------------------------------------------------------------657; Atomic binary read-modify-writes: 32-bit658;===----------------------------------------------------------------------------659 660; There are several RMW instructions, but here we only test 'add' as an example.661 662; Basic RMW.663 664; CHECK-LABEL: rmw_add_i32_no_offset:665; CHECK-NEXT: .functype rmw_add_i32_no_offset (i32, i32) -> (i32){{$}}666; CHECK: i32.atomic.rmw.add $push0=, 0($0), $1{{$}}667; CHECK-NEXT: return $pop0{{$}}668define i32 @rmw_add_i32_no_offset(ptr %p, i32 %v) {669  %old = atomicrmw add ptr %p, i32 %v seq_cst670  ret i32 %old671}672 673; With an nuw add, we can fold an offset.674 675; CHECK-LABEL: rmw_add_i32_with_folded_offset:676; CHECK: i32.atomic.rmw.add $push0=, 24($0), $1{{$}}677define i32 @rmw_add_i32_with_folded_offset(ptr %p, i32 %v) {678  %q = ptrtoint ptr %p to i32679  %r = add nuw i32 %q, 24680  %s = inttoptr i32 %r to ptr681  %old = atomicrmw add ptr %s, i32 %v seq_cst682  ret i32 %old683}684 685; With an inbounds gep, we can fold an offset.686 687; CHECK-LABEL: rmw_add_i32_with_folded_gep_offset:688; CHECK: i32.atomic.rmw.add $push0=, 24($0), $1{{$}}689define i32 @rmw_add_i32_with_folded_gep_offset(ptr %p, i32 %v) {690  %s = getelementptr inbounds i32, ptr %p, i32 6691  %old = atomicrmw add ptr %s, i32 %v seq_cst692  ret i32 %old693}694 695; We can't fold a negative offset though, even with an inbounds gep.696 697; CHECK-LABEL: rmw_add_i32_with_unfolded_gep_negative_offset:698; CHECK: i32.const $push0=, -24{{$}}699; CHECK: i32.add $push1=, $0, $pop0{{$}}700; CHECK: i32.atomic.rmw.add $push2=, 0($pop1), $1{{$}}701define i32 @rmw_add_i32_with_unfolded_gep_negative_offset(ptr %p, i32 %v) {702  %s = getelementptr inbounds i32, ptr %p, i32 -6703  %old = atomicrmw add ptr %s, i32 %v seq_cst704  ret i32 %old705}706 707; Without nuw, and even with nsw, we can't fold an offset.708 709; CHECK-LABEL: rmw_add_i32_with_unfolded_offset:710; CHECK: i32.const $push0=, 24{{$}}711; CHECK: i32.add $push1=, $0, $pop0{{$}}712; CHECK: i32.atomic.rmw.add $push2=, 0($pop1), $1{{$}}713define i32 @rmw_add_i32_with_unfolded_offset(ptr %p, i32 %v) {714  %q = ptrtoint ptr %p to i32715  %r = add nsw i32 %q, 24716  %s = inttoptr i32 %r to ptr717  %old = atomicrmw add ptr %s, i32 %v seq_cst718  ret i32 %old719}720 721; Without inbounds, we can't fold a gep offset.722 723; CHECK-LABEL: rmw_add_i32_with_unfolded_gep_offset:724; CHECK: i32.const $push0=, 24{{$}}725; CHECK: i32.add $push1=, $0, $pop0{{$}}726; CHECK: i32.atomic.rmw.add $push2=, 0($pop1), $1{{$}}727define i32 @rmw_add_i32_with_unfolded_gep_offset(ptr %p, i32 %v) {728  %s = getelementptr i32, ptr %p, i32 6729  %old = atomicrmw add ptr %s, i32 %v seq_cst730  ret i32 %old731}732 733; When loading from a fixed address, materialize a zero.734 735; CHECK-LABEL: rmw_add_i32_from_numeric_address736; CHECK: i32.const $push0=, 0{{$}}737; CHECK: i32.atomic.rmw.add $push1=, 42($pop0), $0{{$}}738define i32 @rmw_add_i32_from_numeric_address(i32 %v) {739  %s = inttoptr i32 42 to ptr740  %old = atomicrmw add ptr %s, i32 %v seq_cst741  ret i32 %old742}743 744; CHECK-LABEL: rmw_add_i32_from_global_address745; CHECK: i32.const $push0=, 0{{$}}746; CHECK: i32.atomic.rmw.add $push1=, gv($pop0), $0{{$}}747define i32 @rmw_add_i32_from_global_address(i32 %v) {748  %old = atomicrmw add ptr @gv, i32 %v seq_cst749  ret i32 %old750}751 752;===----------------------------------------------------------------------------753; Atomic binary read-modify-writes: 64-bit754;===----------------------------------------------------------------------------755 756; Basic RMW.757 758; CHECK-LABEL: rmw_add_i64_no_offset:759; CHECK-NEXT: .functype rmw_add_i64_no_offset (i32, i64) -> (i64){{$}}760; CHECK: i64.atomic.rmw.add $push0=, 0($0), $1{{$}}761; CHECK-NEXT: return $pop0{{$}}762define i64 @rmw_add_i64_no_offset(ptr %p, i64 %v) {763  %old = atomicrmw add ptr %p, i64 %v seq_cst764  ret i64 %old765}766 767; With an nuw add, we can fold an offset.768 769; CHECK-LABEL: rmw_add_i64_with_folded_offset:770; CHECK: i64.atomic.rmw.add $push0=, 24($0), $1{{$}}771define i64 @rmw_add_i64_with_folded_offset(ptr %p, i64 %v) {772  %q = ptrtoint ptr %p to i32773  %r = add nuw i32 %q, 24774  %s = inttoptr i32 %r to ptr775  %old = atomicrmw add ptr %s, i64 %v seq_cst776  ret i64 %old777}778 779; With an inbounds gep, we can fold an offset.780 781; CHECK-LABEL: rmw_add_i64_with_folded_gep_offset:782; CHECK: i64.atomic.rmw.add $push0=, 24($0), $1{{$}}783define i64 @rmw_add_i64_with_folded_gep_offset(ptr %p, i64 %v) {784  %s = getelementptr inbounds i64, ptr %p, i32 3785  %old = atomicrmw add ptr %s, i64 %v seq_cst786  ret i64 %old787}788 789; We can't fold a negative offset though, even with an inbounds gep.790 791; CHECK-LABEL: rmw_add_i64_with_unfolded_gep_negative_offset:792; CHECK: i32.const $push0=, -24{{$}}793; CHECK: i32.add $push1=, $0, $pop0{{$}}794; CHECK: i64.atomic.rmw.add $push2=, 0($pop1), $1{{$}}795define i64 @rmw_add_i64_with_unfolded_gep_negative_offset(ptr %p, i64 %v) {796  %s = getelementptr inbounds i64, ptr %p, i32 -3797  %old = atomicrmw add ptr %s, i64 %v seq_cst798  ret i64 %old799}800 801; Without nuw, and even with nsw, we can't fold an offset.802 803; CHECK-LABEL: rmw_add_i64_with_unfolded_offset:804; CHECK: i32.const $push0=, 24{{$}}805; CHECK: i32.add $push1=, $0, $pop0{{$}}806; CHECK: i64.atomic.rmw.add $push2=, 0($pop1), $1{{$}}807define i64 @rmw_add_i64_with_unfolded_offset(ptr %p, i64 %v) {808  %q = ptrtoint ptr %p to i32809  %r = add nsw i32 %q, 24810  %s = inttoptr i32 %r to ptr811  %old = atomicrmw add ptr %s, i64 %v seq_cst812  ret i64 %old813}814 815; Without inbounds, we can't fold a gep offset.816 817; CHECK-LABEL: rmw_add_i64_with_unfolded_gep_offset:818; CHECK: i32.const $push0=, 24{{$}}819; CHECK: i32.add $push1=, $0, $pop0{{$}}820; CHECK: i64.atomic.rmw.add $push2=, 0($pop1), $1{{$}}821define i64 @rmw_add_i64_with_unfolded_gep_offset(ptr %p, i64 %v) {822  %s = getelementptr i64, ptr %p, i32 3823  %old = atomicrmw add ptr %s, i64 %v seq_cst824  ret i64 %old825}826 827;===----------------------------------------------------------------------------828; Atomic truncating & sign-extending binary RMWs829;===----------------------------------------------------------------------------830 831; Fold an offset into a sign-extending rmw.832 833; CHECK-LABEL: rmw_add_i8_i32_s_with_folded_offset:834; CHECK: i32.atomic.rmw8.add_u $push0=, 24($0), $1{{$}}835; CHECK-NEXT: i32.extend8_s $push1=, $pop0836define i32 @rmw_add_i8_i32_s_with_folded_offset(ptr %p, i32 %v) {837  %q = ptrtoint ptr %p to i32838  %r = add nuw i32 %q, 24839  %s = inttoptr i32 %r to ptr840  %t = trunc i32 %v to i8841  %old = atomicrmw add ptr %s, i8 %t seq_cst842  %u = sext i8 %old to i32843  ret i32 %u844}845 846; 32->64 sext rmw gets selected as i32.atomic.rmw.add, i64.extend_i32_s847; CHECK-LABEL: rmw_add_i32_i64_s_with_folded_offset:848; CHECK: i32.wrap_i64 $push0=, $1849; CHECK-NEXT: i32.atomic.rmw.add $push1=, 24($0), $pop0{{$}}850; CHECK-NEXT: i64.extend_i32_s $push2=, $pop1{{$}}851define i64 @rmw_add_i32_i64_s_with_folded_offset(ptr %p, i64 %v) {852  %q = ptrtoint ptr %p to i32853  %r = add nuw i32 %q, 24854  %s = inttoptr i32 %r to ptr855  %t = trunc i64 %v to i32856  %old = atomicrmw add ptr %s, i32 %t seq_cst857  %u = sext i32 %old to i64858  ret i64 %u859}860 861; Fold a gep offset into a sign-extending rmw.862 863; CHECK-LABEL: rmw_add_i8_i32_s_with_folded_gep_offset:864; CHECK: i32.atomic.rmw8.add_u $push0=, 24($0), $1{{$}}865; CHECK-NEXT: i32.extend8_s $push1=, $pop0866define i32 @rmw_add_i8_i32_s_with_folded_gep_offset(ptr %p, i32 %v) {867  %s = getelementptr inbounds i8, ptr %p, i32 24868  %t = trunc i32 %v to i8869  %old = atomicrmw add ptr %s, i8 %t seq_cst870  %u = sext i8 %old to i32871  ret i32 %u872}873 874; CHECK-LABEL: rmw_add_i16_i32_s_with_folded_gep_offset:875; CHECK: i32.atomic.rmw16.add_u $push0=, 48($0), $1{{$}}876; CHECK-NEXT: i32.extend16_s $push1=, $pop0877define i32 @rmw_add_i16_i32_s_with_folded_gep_offset(ptr %p, i32 %v) {878  %s = getelementptr inbounds i16, ptr %p, i32 24879  %t = trunc i32 %v to i16880  %old = atomicrmw add ptr %s, i16 %t seq_cst881  %u = sext i16 %old to i32882  ret i32 %u883}884 885; CHECK-LABEL: rmw_add_i16_i64_s_with_folded_gep_offset:886; CHECK: i64.atomic.rmw16.add_u $push0=, 48($0), $1{{$}}887; CHECK-NEXT: i64.extend16_s $push1=, $pop0888define i64 @rmw_add_i16_i64_s_with_folded_gep_offset(ptr %p, i64 %v) {889  %s = getelementptr inbounds i16, ptr %p, i32 24890  %t = trunc i64 %v to i16891  %old = atomicrmw add ptr %s, i16 %t seq_cst892  %u = sext i16 %old to i64893  ret i64 %u894}895 896; 'add' in this code becomes 'or' after DAG optimization. Treat an 'or' node as897; an 'add' if the or'ed bits are known to be zero.898 899; CHECK-LABEL: rmw_add_i8_i32_s_with_folded_or_offset:900; CHECK: i32.atomic.rmw8.add_u $push[[R1:[0-9]+]]=, 2($pop{{[0-9]+}}), $1{{$}}901; CHECK-NEXT: i32.extend8_s $push{{[0-9]+}}=, $pop[[R1]]{{$}}902define i32 @rmw_add_i8_i32_s_with_folded_or_offset(i32 %x, i32 %v) {903  %and = and i32 %x, -4904  %t0 = inttoptr i32 %and to ptr905  %arrayidx = getelementptr inbounds i8, ptr %t0, i32 2906  %t = trunc i32 %v to i8907  %old = atomicrmw add ptr %arrayidx, i8 %t seq_cst908  %conv = sext i8 %old to i32909  ret i32 %conv910}911 912; CHECK-LABEL: rmw_add_i8_i64_s_with_folded_or_offset:913; CHECK: i64.atomic.rmw8.add_u $push[[R1:[0-9]+]]=, 2($pop{{[0-9]+}}), $1{{$}}914; CHECK-NEXT: i64.extend8_s $push{{[0-9]+}}=, $pop[[R1]]{{$}}915define i64 @rmw_add_i8_i64_s_with_folded_or_offset(i32 %x, i64 %v) {916  %and = and i32 %x, -4917  %t0 = inttoptr i32 %and to ptr918  %arrayidx = getelementptr inbounds i8, ptr %t0, i32 2919  %t = trunc i64 %v to i8920  %old = atomicrmw add ptr %arrayidx, i8 %t seq_cst921  %conv = sext i8 %old to i64922  ret i64 %conv923}924 925; When loading from a fixed address, materialize a zero.926 927; CHECK-LABEL: rmw_add_i16_i32_s_from_numeric_address928; CHECK: i32.const $push0=, 0{{$}}929; CHECK: i32.atomic.rmw16.add_u $push1=, 42($pop0), $0{{$}}930; CHECK-NEXT: i32.extend16_s $push2=, $pop1931define i32 @rmw_add_i16_i32_s_from_numeric_address(i32 %v) {932  %s = inttoptr i32 42 to ptr933  %t = trunc i32 %v to i16934  %old = atomicrmw add ptr %s, i16 %t seq_cst935  %u = sext i16 %old to i32936  ret i32 %u937}938 939; CHECK-LABEL: rmw_add_i8_i32_s_from_global_address940; CHECK: i32.const $push0=, 0{{$}}941; CHECK: i32.atomic.rmw8.add_u $push1=, gv8($pop0), $0{{$}}942; CHECK-NEXT: i32.extend8_s $push2=, $pop1{{$}}943define i32 @rmw_add_i8_i32_s_from_global_address(i32 %v) {944  %t = trunc i32 %v to i8945  %old = atomicrmw add ptr @gv8, i8 %t seq_cst946  %u = sext i8 %old to i32947  ret i32 %u948}949 950;===----------------------------------------------------------------------------951; Atomic truncating & zero-extending binary RMWs952;===----------------------------------------------------------------------------953 954; Fold an offset into a zero-extending rmw.955 956; CHECK-LABEL: rmw_add_i8_i32_z_with_folded_offset:957; CHECK: i32.atomic.rmw8.add_u $push0=, 24($0), $1{{$}}958define i32 @rmw_add_i8_i32_z_with_folded_offset(ptr %p, i32 %v) {959  %q = ptrtoint ptr %p to i32960  %r = add nuw i32 %q, 24961  %s = inttoptr i32 %r to ptr962  %t = trunc i32 %v to i8963  %old = atomicrmw add ptr %s, i8 %t seq_cst964  %u = zext i8 %old to i32965  ret i32 %u966}967 968; CHECK-LABEL: rmw_add_i32_i64_z_with_folded_offset:969; CHECK: i64.atomic.rmw32.add_u $push0=, 24($0), $1{{$}}970define i64 @rmw_add_i32_i64_z_with_folded_offset(ptr %p, i64 %v) {971  %q = ptrtoint ptr %p to i32972  %r = add nuw i32 %q, 24973  %s = inttoptr i32 %r to ptr974  %t = trunc i64 %v to i32975  %old = atomicrmw add ptr %s, i32 %t seq_cst976  %u = zext i32 %old to i64977  ret i64 %u978}979 980; Fold a gep offset into a zero-extending rmw.981 982; CHECK-LABEL: rmw_add_i8_i32_z_with_folded_gep_offset:983; CHECK: i32.atomic.rmw8.add_u $push0=, 24($0), $1{{$}}984define i32 @rmw_add_i8_i32_z_with_folded_gep_offset(ptr %p, i32 %v) {985  %s = getelementptr inbounds i8, ptr %p, i32 24986  %t = trunc i32 %v to i8987  %old = atomicrmw add ptr %s, i8 %t seq_cst988  %u = zext i8 %old to i32989  ret i32 %u990}991 992; CHECK-LABEL: rmw_add_i16_i32_z_with_folded_gep_offset:993; CHECK: i32.atomic.rmw16.add_u $push0=, 48($0), $1{{$}}994define i32 @rmw_add_i16_i32_z_with_folded_gep_offset(ptr %p, i32 %v) {995  %s = getelementptr inbounds i16, ptr %p, i32 24996  %t = trunc i32 %v to i16997  %old = atomicrmw add ptr %s, i16 %t seq_cst998  %u = zext i16 %old to i32999  ret i32 %u1000}1001 1002; CHECK-LABEL: rmw_add_i16_i64_z_with_folded_gep_offset:1003; CHECK: i64.atomic.rmw16.add_u $push0=, 48($0), $1{{$}}1004define i64 @rmw_add_i16_i64_z_with_folded_gep_offset(ptr %p, i64 %v) {1005  %s = getelementptr inbounds i16, ptr %p, i32 241006  %t = trunc i64 %v to i161007  %old = atomicrmw add ptr %s, i16 %t seq_cst1008  %u = zext i16 %old to i641009  ret i64 %u1010}1011 1012; 'add' in this code becomes 'or' after DAG optimization. Treat an 'or' node as1013; an 'add' if the or'ed bits are known to be zero.1014 1015; CHECK-LABEL: rmw_add_i8_i32_z_with_folded_or_offset:1016; CHECK: i32.atomic.rmw8.add_u $push[[R1:[0-9]+]]=, 2($pop{{[0-9]+}}), $1{{$}}1017define i32 @rmw_add_i8_i32_z_with_folded_or_offset(i32 %x, i32 %v) {1018  %and = and i32 %x, -41019  %t0 = inttoptr i32 %and to ptr1020  %arrayidx = getelementptr inbounds i8, ptr %t0, i32 21021  %t = trunc i32 %v to i81022  %old = atomicrmw add ptr %arrayidx, i8 %t seq_cst1023  %conv = zext i8 %old to i321024  ret i32 %conv1025}1026 1027; CHECK-LABEL: rmw_add_i8_i64_z_with_folded_or_offset:1028; CHECK: i64.atomic.rmw8.add_u $push[[R1:[0-9]+]]=, 2($pop{{[0-9]+}}), $1{{$}}1029define i64 @rmw_add_i8_i64_z_with_folded_or_offset(i32 %x, i64 %v) {1030  %and = and i32 %x, -41031  %t0 = inttoptr i32 %and to ptr1032  %arrayidx = getelementptr inbounds i8, ptr %t0, i32 21033  %t = trunc i64 %v to i81034  %old = atomicrmw add ptr %arrayidx, i8 %t seq_cst1035  %conv = zext i8 %old to i641036  ret i64 %conv1037}1038 1039; When loading from a fixed address, materialize a zero.1040 1041; CHECK-LABEL: rmw_add_i16_i32_z_from_numeric_address1042; CHECK: i32.const $push0=, 0{{$}}1043; CHECK: i32.atomic.rmw16.add_u $push1=, 42($pop0), $0{{$}}1044define i32 @rmw_add_i16_i32_z_from_numeric_address(i32 %v) {1045  %s = inttoptr i32 42 to ptr1046  %t = trunc i32 %v to i161047  %old = atomicrmw add ptr %s, i16 %t seq_cst1048  %u = zext i16 %old to i321049  ret i32 %u1050}1051 1052; CHECK-LABEL: rmw_add_i8_i32_z_from_global_address1053; CHECK: i32.const $push0=, 0{{$}}1054; CHECK: i32.atomic.rmw8.add_u $push1=, gv8($pop0), $0{{$}}1055define i32 @rmw_add_i8_i32_z_from_global_address(i32 %v) {1056  %t = trunc i32 %v to i81057  %old = atomicrmw add ptr @gv8, i8 %t seq_cst1058  %u = zext i8 %old to i321059  ret i32 %u1060}1061 1062; i8 return value should test anyext RMWs1063 1064; CHECK-LABEL: rmw_add_i8_i32_retvalue:1065; CHECK: i32.atomic.rmw8.add_u $push0=, 0($0), $1{{$}}1066; CHECK-NEXT: return $pop0{{$}}1067define i8 @rmw_add_i8_i32_retvalue(ptr %p, i32 %v) {1068  %t = trunc i32 %v to i81069  %old = atomicrmw add ptr %p, i8 %t seq_cst1070  ret i8 %old1071}1072 1073;===----------------------------------------------------------------------------1074; Atomic ternary read-modify-writes: 32-bit1075;===----------------------------------------------------------------------------1076 1077; Basic RMW.1078 1079; CHECK-LABEL: cmpxchg_i32_no_offset:1080; CHECK-NEXT: .functype cmpxchg_i32_no_offset (i32, i32, i32) -> (i32){{$}}1081; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}}1082; CHECK-NEXT: return $pop0{{$}}1083define i32 @cmpxchg_i32_no_offset(ptr %p, i32 %exp, i32 %new) {1084  %pair = cmpxchg ptr %p, i32 %exp, i32 %new seq_cst seq_cst1085  %old = extractvalue { i32, i1 } %pair, 01086  ret i32 %old1087}1088 1089; With an nuw add, we can fold an offset.1090 1091; CHECK-LABEL: cmpxchg_i32_with_folded_offset:1092; CHECK: i32.atomic.rmw.cmpxchg $push0=, 24($0), $1, $2{{$}}1093define i32 @cmpxchg_i32_with_folded_offset(ptr %p, i32 %exp, i32 %new) {1094  %q = ptrtoint ptr %p to i321095  %r = add nuw i32 %q, 241096  %s = inttoptr i32 %r to ptr1097  %pair = cmpxchg ptr %s, i32 %exp, i32 %new seq_cst seq_cst1098  %old = extractvalue { i32, i1 } %pair, 01099  ret i32 %old1100}1101 1102; With an inbounds gep, we can fold an offset.1103 1104; CHECK-LABEL: cmpxchg_i32_with_folded_gep_offset:1105; CHECK: i32.atomic.rmw.cmpxchg $push0=, 24($0), $1, $2{{$}}1106define i32 @cmpxchg_i32_with_folded_gep_offset(ptr %p, i32 %exp, i32 %new) {1107  %s = getelementptr inbounds i32, ptr %p, i32 61108  %pair = cmpxchg ptr %s, i32 %exp, i32 %new seq_cst seq_cst1109  %old = extractvalue { i32, i1 } %pair, 01110  ret i32 %old1111}1112 1113; We can't fold a negative offset though, even with an inbounds gep.1114 1115; CHECK-LABEL: cmpxchg_i32_with_unfolded_gep_negative_offset:1116; CHECK: i32.const $push0=, -24{{$}}1117; CHECK: i32.add $push1=, $0, $pop0{{$}}1118; CHECK: i32.atomic.rmw.cmpxchg $push2=, 0($pop1), $1, $2{{$}}1119define i32 @cmpxchg_i32_with_unfolded_gep_negative_offset(ptr %p, i32 %exp, i32 %new) {1120  %s = getelementptr inbounds i32, ptr %p, i32 -61121  %pair = cmpxchg ptr %s, i32 %exp, i32 %new seq_cst seq_cst1122  %old = extractvalue { i32, i1 } %pair, 01123  ret i32 %old1124}1125 1126; Without nuw, and even with nsw, we can't fold an offset.1127 1128; CHECK-LABEL: cmpxchg_i32_with_unfolded_offset:1129; CHECK: i32.const $push0=, 24{{$}}1130; CHECK: i32.add $push1=, $0, $pop0{{$}}1131; CHECK: i32.atomic.rmw.cmpxchg $push2=, 0($pop1), $1, $2{{$}}1132define i32 @cmpxchg_i32_with_unfolded_offset(ptr %p, i32 %exp, i32 %new) {1133  %q = ptrtoint ptr %p to i321134  %r = add nsw i32 %q, 241135  %s = inttoptr i32 %r to ptr1136  %pair = cmpxchg ptr %s, i32 %exp, i32 %new seq_cst seq_cst1137  %old = extractvalue { i32, i1 } %pair, 01138  ret i32 %old1139}1140 1141; Without inbounds, we can't fold a gep offset.1142 1143; CHECK-LABEL: cmpxchg_i32_with_unfolded_gep_offset:1144; CHECK: i32.const $push0=, 24{{$}}1145; CHECK: i32.add $push1=, $0, $pop0{{$}}1146; CHECK: i32.atomic.rmw.cmpxchg $push2=, 0($pop1), $1, $2{{$}}1147define i32 @cmpxchg_i32_with_unfolded_gep_offset(ptr %p, i32 %exp, i32 %new) {1148  %s = getelementptr i32, ptr %p, i32 61149  %pair = cmpxchg ptr %s, i32 %exp, i32 %new seq_cst seq_cst1150  %old = extractvalue { i32, i1 } %pair, 01151  ret i32 %old1152}1153 1154; When loading from a fixed address, materialize a zero.1155 1156; CHECK-LABEL: cmpxchg_i32_from_numeric_address1157; CHECK: i32.const $push0=, 0{{$}}1158; CHECK: i32.atomic.rmw.cmpxchg $push1=, 42($pop0), $0, $1{{$}}1159define i32 @cmpxchg_i32_from_numeric_address(i32 %exp, i32 %new) {1160  %s = inttoptr i32 42 to ptr1161  %pair = cmpxchg ptr %s, i32 %exp, i32 %new seq_cst seq_cst1162  %old = extractvalue { i32, i1 } %pair, 01163  ret i32 %old1164}1165 1166; CHECK-LABEL: cmpxchg_i32_from_global_address1167; CHECK: i32.const $push0=, 0{{$}}1168; CHECK: i32.atomic.rmw.cmpxchg $push1=, gv($pop0), $0, $1{{$}}1169define i32 @cmpxchg_i32_from_global_address(i32 %exp, i32 %new) {1170  %pair = cmpxchg ptr @gv, i32 %exp, i32 %new seq_cst seq_cst1171  %old = extractvalue { i32, i1 } %pair, 01172  ret i32 %old1173}1174 1175;===----------------------------------------------------------------------------1176; Atomic ternary read-modify-writes: 64-bit1177;===----------------------------------------------------------------------------1178 1179; Basic RMW.1180 1181; CHECK-LABEL: cmpxchg_i64_no_offset:1182; CHECK-NEXT: .functype cmpxchg_i64_no_offset (i32, i64, i64) -> (i64){{$}}1183; CHECK: i64.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}}1184; CHECK-NEXT: return $pop0{{$}}1185define i64 @cmpxchg_i64_no_offset(ptr %p, i64 %exp, i64 %new) {1186  %pair = cmpxchg ptr %p, i64 %exp, i64 %new seq_cst seq_cst1187  %old = extractvalue { i64, i1 } %pair, 01188  ret i64 %old1189}1190 1191; With an nuw add, we can fold an offset.1192 1193; CHECK-LABEL: cmpxchg_i64_with_folded_offset:1194; CHECK: i64.atomic.rmw.cmpxchg $push0=, 24($0), $1, $2{{$}}1195define i64 @cmpxchg_i64_with_folded_offset(ptr %p, i64 %exp, i64 %new) {1196  %q = ptrtoint ptr %p to i321197  %r = add nuw i32 %q, 241198  %s = inttoptr i32 %r to ptr1199  %pair = cmpxchg ptr %s, i64 %exp, i64 %new seq_cst seq_cst1200  %old = extractvalue { i64, i1 } %pair, 01201  ret i64 %old1202}1203 1204; With an inbounds gep, we can fold an offset.1205 1206; CHECK-LABEL: cmpxchg_i64_with_folded_gep_offset:1207; CHECK: i64.atomic.rmw.cmpxchg $push0=, 24($0), $1, $2{{$}}1208define i64 @cmpxchg_i64_with_folded_gep_offset(ptr %p, i64 %exp, i64 %new) {1209  %s = getelementptr inbounds i64, ptr %p, i32 31210  %pair = cmpxchg ptr %s, i64 %exp, i64 %new seq_cst seq_cst1211  %old = extractvalue { i64, i1 } %pair, 01212  ret i64 %old1213}1214 1215; We can't fold a negative offset though, even with an inbounds gep.1216 1217; CHECK-LABEL: cmpxchg_i64_with_unfolded_gep_negative_offset:1218; CHECK: i32.const $push0=, -24{{$}}1219; CHECK: i32.add $push1=, $0, $pop0{{$}}1220; CHECK: i64.atomic.rmw.cmpxchg $push2=, 0($pop1), $1, $2{{$}}1221define i64 @cmpxchg_i64_with_unfolded_gep_negative_offset(ptr %p, i64 %exp, i64 %new) {1222  %s = getelementptr inbounds i64, ptr %p, i32 -31223  %pair = cmpxchg ptr %s, i64 %exp, i64 %new seq_cst seq_cst1224  %old = extractvalue { i64, i1 } %pair, 01225  ret i64 %old1226}1227 1228; Without nuw, and even with nsw, we can't fold an offset.1229 1230; CHECK-LABEL: cmpxchg_i64_with_unfolded_offset:1231; CHECK: i32.const $push0=, 24{{$}}1232; CHECK: i32.add $push1=, $0, $pop0{{$}}1233; CHECK: i64.atomic.rmw.cmpxchg $push2=, 0($pop1), $1, $2{{$}}1234define i64 @cmpxchg_i64_with_unfolded_offset(ptr %p, i64 %exp, i64 %new) {1235  %q = ptrtoint ptr %p to i321236  %r = add nsw i32 %q, 241237  %s = inttoptr i32 %r to ptr1238  %pair = cmpxchg ptr %s, i64 %exp, i64 %new seq_cst seq_cst1239  %old = extractvalue { i64, i1 } %pair, 01240  ret i64 %old1241}1242 1243; Without inbounds, we can't fold a gep offset.1244 1245; CHECK-LABEL: cmpxchg_i64_with_unfolded_gep_offset:1246; CHECK: i32.const $push0=, 24{{$}}1247; CHECK: i32.add $push1=, $0, $pop0{{$}}1248; CHECK: i64.atomic.rmw.cmpxchg $push2=, 0($pop1), $1, $2{{$}}1249define i64 @cmpxchg_i64_with_unfolded_gep_offset(ptr %p, i64 %exp, i64 %new) {1250  %s = getelementptr i64, ptr %p, i32 31251  %pair = cmpxchg ptr %s, i64 %exp, i64 %new seq_cst seq_cst1252  %old = extractvalue { i64, i1 } %pair, 01253  ret i64 %old1254}1255 1256;===----------------------------------------------------------------------------1257; Atomic truncating & sign-extending ternary RMWs1258;===----------------------------------------------------------------------------1259 1260; Fold an offset into a sign-extending rmw.1261 1262; CHECK-LABEL: cmpxchg_i8_i32_s_with_folded_offset:1263; CHECK: i32.atomic.rmw8.cmpxchg_u $push0=, 24($0), $1, $2{{$}}1264; CHECK-NEXT: i32.extend8_s $push1=, $pop01265define i32 @cmpxchg_i8_i32_s_with_folded_offset(ptr %p, i32 %exp, i32 %new) {1266  %q = ptrtoint ptr %p to i321267  %r = add nuw i32 %q, 241268  %s = inttoptr i32 %r to ptr1269  %exp_t = trunc i32 %exp to i81270  %new_t = trunc i32 %new to i81271  %pair = cmpxchg ptr %s, i8 %exp_t, i8 %new_t seq_cst seq_cst1272  %old = extractvalue { i8, i1 } %pair, 01273  %u = sext i8 %old to i321274  ret i32 %u1275}1276 1277; 32->64 sext rmw gets selected as i32.atomic.rmw.cmpxchg, i64.extend_i32_s1278; CHECK-LABEL: cmpxchg_i32_i64_s_with_folded_offset:1279; CHECK: i32.wrap_i64 $push1=, $11280; CHECK-NEXT: i32.wrap_i64 $push0=, $21281; CHECK-NEXT: i32.atomic.rmw.cmpxchg $push2=, 24($0), $pop1, $pop0{{$}}1282; CHECK-NEXT: i64.extend_i32_s $push3=, $pop2{{$}}1283define i64 @cmpxchg_i32_i64_s_with_folded_offset(ptr %p, i64 %exp, i64 %new) {1284  %q = ptrtoint ptr %p to i321285  %r = add nuw i32 %q, 241286  %s = inttoptr i32 %r to ptr1287  %exp_t = trunc i64 %exp to i321288  %new_t = trunc i64 %new to i321289  %pair = cmpxchg ptr %s, i32 %exp_t, i32 %new_t seq_cst seq_cst1290  %old = extractvalue { i32, i1 } %pair, 01291  %u = sext i32 %old to i641292  ret i64 %u1293}1294 1295; Fold a gep offset into a sign-extending rmw.1296 1297; CHECK-LABEL: cmpxchg_i8_i32_s_with_folded_gep_offset:1298; CHECK: i32.atomic.rmw8.cmpxchg_u $push0=, 24($0), $1, $2{{$}}1299; CHECK-NEXT: i32.extend8_s $push1=, $pop01300define i32 @cmpxchg_i8_i32_s_with_folded_gep_offset(ptr %p, i32 %exp, i32 %new) {1301  %s = getelementptr inbounds i8, ptr %p, i32 241302  %exp_t = trunc i32 %exp to i81303  %new_t = trunc i32 %new to i81304  %pair = cmpxchg ptr %s, i8 %exp_t, i8 %new_t seq_cst seq_cst1305  %old = extractvalue { i8, i1 } %pair, 01306  %u = sext i8 %old to i321307  ret i32 %u1308}1309 1310; CHECK-LABEL: cmpxchg_i16_i32_s_with_folded_gep_offset:1311; CHECK: i32.atomic.rmw16.cmpxchg_u $push0=, 48($0), $1, $2{{$}}1312; CHECK-NEXT: i32.extend16_s $push1=, $pop01313define i32 @cmpxchg_i16_i32_s_with_folded_gep_offset(ptr %p, i32 %exp, i32 %new) {1314  %s = getelementptr inbounds i16, ptr %p, i32 241315  %exp_t = trunc i32 %exp to i161316  %new_t = trunc i32 %new to i161317  %pair = cmpxchg ptr %s, i16 %exp_t, i16 %new_t seq_cst seq_cst1318  %old = extractvalue { i16, i1 } %pair, 01319  %u = sext i16 %old to i321320  ret i32 %u1321}1322 1323; CHECK-LABEL: cmpxchg_i16_i64_s_with_folded_gep_offset:1324; CHECK: i64.atomic.rmw16.cmpxchg_u $push0=, 48($0), $1, $2{{$}}1325; CHECK-NEXT: i64.extend16_s $push1=, $pop01326define i64 @cmpxchg_i16_i64_s_with_folded_gep_offset(ptr %p, i64 %exp, i64 %new) {1327  %s = getelementptr inbounds i16, ptr %p, i32 241328  %exp_t = trunc i64 %exp to i161329  %new_t = trunc i64 %new to i161330  %pair = cmpxchg ptr %s, i16 %exp_t, i16 %new_t seq_cst seq_cst1331  %old = extractvalue { i16, i1 } %pair, 01332  %u = sext i16 %old to i641333  ret i64 %u1334}1335 1336; 'add' in this code becomes 'or' after DAG optimization. Treat an 'or' node as1337; an 'add' if the or'ed bits are known to be zero.1338 1339; CHECK-LABEL: cmpxchg_i8_i32_s_with_folded_or_offset:1340; CHECK: i32.atomic.rmw8.cmpxchg_u $push[[R1:[0-9]+]]=, 2($pop{{[0-9]+}}), $1, $2{{$}}1341; CHECK-NEXT: i32.extend8_s $push{{[0-9]+}}=, $pop[[R1]]{{$}}1342define i32 @cmpxchg_i8_i32_s_with_folded_or_offset(i32 %x, i32 %exp, i32 %new) {1343  %and = and i32 %x, -41344  %t0 = inttoptr i32 %and to ptr1345  %arrayidx = getelementptr inbounds i8, ptr %t0, i32 21346  %exp_t = trunc i32 %exp to i81347  %new_t = trunc i32 %new to i81348  %pair = cmpxchg ptr %arrayidx, i8 %exp_t, i8 %new_t seq_cst seq_cst1349  %old = extractvalue { i8, i1 } %pair, 01350  %conv = sext i8 %old to i321351  ret i32 %conv1352}1353 1354; CHECK-LABEL: cmpxchg_i8_i64_s_with_folded_or_offset:1355; CHECK: i64.atomic.rmw8.cmpxchg_u $push[[R1:[0-9]+]]=, 2($pop{{[0-9]+}}), $1, $2{{$}}1356; CHECK-NEXT: i64.extend8_s $push{{[0-9]+}}=, $pop[[R1]]{{$}}1357define i64 @cmpxchg_i8_i64_s_with_folded_or_offset(i32 %x, i64 %exp, i64 %new) {1358  %and = and i32 %x, -41359  %t0 = inttoptr i32 %and to ptr1360  %arrayidx = getelementptr inbounds i8, ptr %t0, i32 21361  %exp_t = trunc i64 %exp to i81362  %new_t = trunc i64 %new to i81363  %pair = cmpxchg ptr %arrayidx, i8 %exp_t, i8 %new_t seq_cst seq_cst1364  %old = extractvalue { i8, i1 } %pair, 01365  %conv = sext i8 %old to i641366  ret i64 %conv1367}1368 1369; When loading from a fixed address, materialize a zero.1370 1371; CHECK-LABEL: cmpxchg_i16_i32_s_from_numeric_address1372; CHECK: i32.const $push0=, 0{{$}}1373; CHECK: i32.atomic.rmw16.cmpxchg_u $push1=, 42($pop0), $0, $1{{$}}1374; CHECK-NEXT: i32.extend16_s $push2=, $pop11375define i32 @cmpxchg_i16_i32_s_from_numeric_address(i32 %exp, i32 %new) {1376  %s = inttoptr i32 42 to ptr1377  %exp_t = trunc i32 %exp to i161378  %new_t = trunc i32 %new to i161379  %pair = cmpxchg ptr %s, i16 %exp_t, i16 %new_t seq_cst seq_cst1380  %old = extractvalue { i16, i1 } %pair, 01381  %u = sext i16 %old to i321382  ret i32 %u1383}1384 1385; CHECK-LABEL: cmpxchg_i8_i32_s_from_global_address1386; CHECK: i32.const $push0=, 0{{$}}1387; CHECK: i32.atomic.rmw8.cmpxchg_u $push1=, gv8($pop0), $0, $1{{$}}1388; CHECK-NEXT: i32.extend8_s $push2=, $pop1{{$}}1389define i32 @cmpxchg_i8_i32_s_from_global_address(i32 %exp, i32 %new) {1390  %exp_t = trunc i32 %exp to i81391  %new_t = trunc i32 %new to i81392  %pair = cmpxchg ptr @gv8, i8 %exp_t, i8 %new_t seq_cst seq_cst1393  %old = extractvalue { i8, i1 } %pair, 01394  %u = sext i8 %old to i321395  ret i32 %u1396}1397 1398;===----------------------------------------------------------------------------1399; Atomic truncating & zero-extending ternary RMWs1400;===----------------------------------------------------------------------------1401 1402; Fold an offset into a sign-extending rmw.1403 1404; CHECK-LABEL: cmpxchg_i8_i32_z_with_folded_offset:1405; CHECK: i32.atomic.rmw8.cmpxchg_u $push0=, 24($0), $1, $2{{$}}1406define i32 @cmpxchg_i8_i32_z_with_folded_offset(ptr %p, i32 %exp, i32 %new) {1407  %q = ptrtoint ptr %p to i321408  %r = add nuw i32 %q, 241409  %s = inttoptr i32 %r to ptr1410  %exp_t = trunc i32 %exp to i81411  %new_t = trunc i32 %new to i81412  %pair = cmpxchg ptr %s, i8 %exp_t, i8 %new_t seq_cst seq_cst1413  %old = extractvalue { i8, i1 } %pair, 01414  %u = zext i8 %old to i321415  ret i32 %u1416}1417 1418; CHECK-LABEL: cmpxchg_i32_i64_z_with_folded_offset:1419; CHECK: i64.atomic.rmw32.cmpxchg_u $push0=, 24($0), $1, $2{{$}}1420define i64 @cmpxchg_i32_i64_z_with_folded_offset(ptr %p, i64 %exp, i64 %new) {1421  %q = ptrtoint ptr %p to i321422  %r = add nuw i32 %q, 241423  %s = inttoptr i32 %r to ptr1424  %exp_t = trunc i64 %exp to i321425  %new_t = trunc i64 %new to i321426  %pair = cmpxchg ptr %s, i32 %exp_t, i32 %new_t seq_cst seq_cst1427  %old = extractvalue { i32, i1 } %pair, 01428  %u = zext i32 %old to i641429  ret i64 %u1430}1431 1432; Fold a gep offset into a sign-extending rmw.1433 1434; CHECK-LABEL: cmpxchg_i8_i32_z_with_folded_gep_offset:1435; CHECK: i32.atomic.rmw8.cmpxchg_u $push0=, 24($0), $1, $2{{$}}1436define i32 @cmpxchg_i8_i32_z_with_folded_gep_offset(ptr %p, i32 %exp, i32 %new) {1437  %s = getelementptr inbounds i8, ptr %p, i32 241438  %exp_t = trunc i32 %exp to i81439  %new_t = trunc i32 %new to i81440  %pair = cmpxchg ptr %s, i8 %exp_t, i8 %new_t seq_cst seq_cst1441  %old = extractvalue { i8, i1 } %pair, 01442  %u = zext i8 %old to i321443  ret i32 %u1444}1445 1446; CHECK-LABEL: cmpxchg_i16_i32_z_with_folded_gep_offset:1447; CHECK: i32.atomic.rmw16.cmpxchg_u $push0=, 48($0), $1, $2{{$}}1448define i32 @cmpxchg_i16_i32_z_with_folded_gep_offset(ptr %p, i32 %exp, i32 %new) {1449  %s = getelementptr inbounds i16, ptr %p, i32 241450  %exp_t = trunc i32 %exp to i161451  %new_t = trunc i32 %new to i161452  %pair = cmpxchg ptr %s, i16 %exp_t, i16 %new_t seq_cst seq_cst1453  %old = extractvalue { i16, i1 } %pair, 01454  %u = zext i16 %old to i321455  ret i32 %u1456}1457 1458; CHECK-LABEL: cmpxchg_i16_i64_z_with_folded_gep_offset:1459; CHECK: i64.atomic.rmw16.cmpxchg_u $push0=, 48($0), $1, $2{{$}}1460define i64 @cmpxchg_i16_i64_z_with_folded_gep_offset(ptr %p, i64 %exp, i64 %new) {1461  %s = getelementptr inbounds i16, ptr %p, i32 241462  %exp_t = trunc i64 %exp to i161463  %new_t = trunc i64 %new to i161464  %pair = cmpxchg ptr %s, i16 %exp_t, i16 %new_t seq_cst seq_cst1465  %old = extractvalue { i16, i1 } %pair, 01466  %u = zext i16 %old to i641467  ret i64 %u1468}1469 1470; 'add' in this code becomes 'or' after DAG optimization. Treat an 'or' node as1471; an 'add' if the or'ed bits are known to be zero.1472 1473; CHECK-LABEL: cmpxchg_i8_i32_z_with_folded_or_offset:1474; CHECK: i32.atomic.rmw8.cmpxchg_u $push[[R1:[0-9]+]]=, 2($pop{{[0-9]+}}), $1, $2{{$}}1475define i32 @cmpxchg_i8_i32_z_with_folded_or_offset(i32 %x, i32 %exp, i32 %new) {1476  %and = and i32 %x, -41477  %t0 = inttoptr i32 %and to ptr1478  %arrayidx = getelementptr inbounds i8, ptr %t0, i32 21479  %exp_t = trunc i32 %exp to i81480  %new_t = trunc i32 %new to i81481  %pair = cmpxchg ptr %arrayidx, i8 %exp_t, i8 %new_t seq_cst seq_cst1482  %old = extractvalue { i8, i1 } %pair, 01483  %conv = zext i8 %old to i321484  ret i32 %conv1485}1486 1487; CHECK-LABEL: cmpxchg_i8_i64_z_with_folded_or_offset:1488; CHECK: i64.atomic.rmw8.cmpxchg_u $push[[R1:[0-9]+]]=, 2($pop{{[0-9]+}}), $1, $2{{$}}1489define i64 @cmpxchg_i8_i64_z_with_folded_or_offset(i32 %x, i64 %exp, i64 %new) {1490  %and = and i32 %x, -41491  %t0 = inttoptr i32 %and to ptr1492  %arrayidx = getelementptr inbounds i8, ptr %t0, i32 21493  %exp_t = trunc i64 %exp to i81494  %new_t = trunc i64 %new to i81495  %pair = cmpxchg ptr %arrayidx, i8 %exp_t, i8 %new_t seq_cst seq_cst1496  %old = extractvalue { i8, i1 } %pair, 01497  %conv = zext i8 %old to i641498  ret i64 %conv1499}1500 1501; When loading from a fixed address, materialize a zero.1502 1503; CHECK-LABEL: cmpxchg_i16_i32_z_from_numeric_address1504; CHECK: i32.const $push0=, 0{{$}}1505; CHECK: i32.atomic.rmw16.cmpxchg_u $push1=, 42($pop0), $0, $1{{$}}1506define i32 @cmpxchg_i16_i32_z_from_numeric_address(i32 %exp, i32 %new) {1507  %s = inttoptr i32 42 to ptr1508  %exp_t = trunc i32 %exp to i161509  %new_t = trunc i32 %new to i161510  %pair = cmpxchg ptr %s, i16 %exp_t, i16 %new_t seq_cst seq_cst1511  %old = extractvalue { i16, i1 } %pair, 01512  %u = zext i16 %old to i321513  ret i32 %u1514}1515 1516; CHECK-LABEL: cmpxchg_i8_i32_z_from_global_address1517; CHECK: i32.const $push0=, 0{{$}}1518; CHECK: i32.atomic.rmw8.cmpxchg_u $push1=, gv8($pop0), $0, $1{{$}}1519define i32 @cmpxchg_i8_i32_z_from_global_address(i32 %exp, i32 %new) {1520  %exp_t = trunc i32 %exp to i81521  %new_t = trunc i32 %new to i81522  %pair = cmpxchg ptr @gv8, i8 %exp_t, i8 %new_t seq_cst seq_cst1523  %old = extractvalue { i8, i1 } %pair, 01524  %u = zext i8 %old to i321525  ret i32 %u1526}1527 1528;===----------------------------------------------------------------------------1529; Waits: 32-bit1530;===----------------------------------------------------------------------------1531 1532declare i32 @llvm.wasm.memory.atomic.wait32(ptr, i32, i64)1533 1534; Basic wait.1535 1536; CHECK-LABEL: wait32_no_offset:1537; CHECK: memory.atomic.wait32 $push0=, 0($0), $1, $2{{$}}1538; CHECK-NEXT: return $pop0{{$}}1539define i32 @wait32_no_offset(ptr %p, i32 %exp, i64 %timeout) {1540  %v = call i32 @llvm.wasm.memory.atomic.wait32(ptr %p, i32 %exp, i64 %timeout)1541  ret i32 %v1542}1543 1544; With an nuw add, we can fold an offset.1545 1546; CHECK-LABEL: wait32_with_folded_offset:1547; CHECK: memory.atomic.wait32 $push0=, 24($0), $1, $2{{$}}1548define i32 @wait32_with_folded_offset(ptr %p, i32 %exp, i64 %timeout) {1549  %q = ptrtoint ptr %p to i321550  %r = add nuw i32 %q, 241551  %s = inttoptr i32 %r to ptr1552  %t = call i32 @llvm.wasm.memory.atomic.wait32(ptr %s, i32 %exp, i64 %timeout)1553  ret i32 %t1554}1555 1556; With an inbounds gep, we can fold an offset.1557 1558; CHECK-LABEL: wait32_with_folded_gep_offset:1559; CHECK: memory.atomic.wait32 $push0=, 24($0), $1, $2{{$}}1560define i32 @wait32_with_folded_gep_offset(ptr %p, i32 %exp, i64 %timeout) {1561  %s = getelementptr inbounds i32, ptr %p, i32 61562  %t = call i32 @llvm.wasm.memory.atomic.wait32(ptr %s, i32 %exp, i64 %timeout)1563  ret i32 %t1564}1565 1566; We can't fold a negative offset though, even with an inbounds gep.1567 1568; CHECK-LABEL: wait32_with_unfolded_gep_negative_offset:1569; CHECK: i32.const $push0=, -24{{$}}1570; CHECK: i32.add $push1=, $0, $pop0{{$}}1571; CHECK: memory.atomic.wait32 $push2=, 0($pop1), $1, $2{{$}}1572define i32 @wait32_with_unfolded_gep_negative_offset(ptr %p, i32 %exp, i64 %timeout) {1573  %s = getelementptr inbounds i32, ptr %p, i32 -61574  %t = call i32 @llvm.wasm.memory.atomic.wait32(ptr %s, i32 %exp, i64 %timeout)1575  ret i32 %t1576}1577 1578; Without nuw, and even with nsw, we can't fold an offset.1579 1580; CHECK-LABEL: wait32_with_unfolded_offset:1581; CHECK: i32.const $push0=, 24{{$}}1582; CHECK: i32.add $push1=, $0, $pop0{{$}}1583; CHECK: memory.atomic.wait32 $push2=, 0($pop1), $1, $2{{$}}1584define i32 @wait32_with_unfolded_offset(ptr %p, i32 %exp, i64 %timeout) {1585  %q = ptrtoint ptr %p to i321586  %r = add nsw i32 %q, 241587  %s = inttoptr i32 %r to ptr1588  %t = call i32 @llvm.wasm.memory.atomic.wait32(ptr %s, i32 %exp, i64 %timeout)1589  ret i32 %t1590}1591 1592; Without inbounds, we can't fold a gep offset.1593 1594; CHECK-LABEL: wait32_with_unfolded_gep_offset:1595; CHECK: i32.const $push0=, 24{{$}}1596; CHECK: i32.add $push1=, $0, $pop0{{$}}1597; CHECK: memory.atomic.wait32 $push2=, 0($pop1), $1, $2{{$}}1598define i32 @wait32_with_unfolded_gep_offset(ptr %p, i32 %exp, i64 %timeout) {1599  %s = getelementptr i32, ptr %p, i32 61600  %t = call i32 @llvm.wasm.memory.atomic.wait32(ptr %s, i32 %exp, i64 %timeout)1601  ret i32 %t1602}1603 1604; When waiting from a fixed address, materialize a zero.1605 1606; CHECK-LABEL: wait32_from_numeric_address1607; CHECK: i32.const $push0=, 0{{$}}1608; CHECK: memory.atomic.wait32 $push1=, 42($pop0), $0, $1{{$}}1609define i32 @wait32_from_numeric_address(i32 %exp, i64 %timeout) {1610  %s = inttoptr i32 42 to ptr1611  %t = call i32 @llvm.wasm.memory.atomic.wait32(ptr %s, i32 %exp, i64 %timeout)1612  ret i32 %t1613}1614 1615; CHECK-LABEL: wait32_from_global_address1616; CHECK: i32.const $push0=, 0{{$}}1617; CHECK: memory.atomic.wait32 $push1=, gv($pop0), $0, $1{{$}}1618define i32 @wait32_from_global_address(i32 %exp, i64 %timeout) {1619  %t = call i32 @llvm.wasm.memory.atomic.wait32(ptr @gv, i32 %exp, i64 %timeout)1620  ret i32 %t1621}1622 1623;===----------------------------------------------------------------------------1624; Waits: 64-bit1625;===----------------------------------------------------------------------------1626 1627declare i32 @llvm.wasm.memory.atomic.wait64(ptr, i64, i64)1628 1629; Basic wait.1630 1631; CHECK-LABEL: wait64_no_offset:1632; CHECK: memory.atomic.wait64 $push0=, 0($0), $1, $2{{$}}1633; CHECK-NEXT: return $pop0{{$}}1634define i32 @wait64_no_offset(ptr %p, i64 %exp, i64 %timeout) {1635  %v = call i32 @llvm.wasm.memory.atomic.wait64(ptr %p, i64 %exp, i64 %timeout)1636  ret i32 %v1637}1638 1639; With an nuw add, we can fold an offset.1640 1641; CHECK-LABEL: wait64_with_folded_offset:1642; CHECK: memory.atomic.wait64 $push0=, 24($0), $1, $2{{$}}1643define i32 @wait64_with_folded_offset(ptr %p, i64 %exp, i64 %timeout) {1644  %q = ptrtoint ptr %p to i321645  %r = add nuw i32 %q, 241646  %s = inttoptr i32 %r to ptr1647  %t = call i32 @llvm.wasm.memory.atomic.wait64(ptr %s, i64 %exp, i64 %timeout)1648  ret i32 %t1649}1650 1651; With an inbounds gep, we can fold an offset.1652 1653; CHECK-LABEL: wait64_with_folded_gep_offset:1654; CHECK: memory.atomic.wait64 $push0=, 24($0), $1, $2{{$}}1655define i32 @wait64_with_folded_gep_offset(ptr %p, i64 %exp, i64 %timeout) {1656  %s = getelementptr inbounds i64, ptr %p, i32 31657  %t = call i32 @llvm.wasm.memory.atomic.wait64(ptr %s, i64 %exp, i64 %timeout)1658  ret i32 %t1659}1660 1661; We can't fold a negative offset though, even with an inbounds gep.1662 1663; CHECK-LABEL: wait64_with_unfolded_gep_negative_offset:1664; CHECK: i32.const $push0=, -24{{$}}1665; CHECK: i32.add $push1=, $0, $pop0{{$}}1666; CHECK: memory.atomic.wait64 $push2=, 0($pop1), $1, $2{{$}}1667define i32 @wait64_with_unfolded_gep_negative_offset(ptr %p, i64 %exp, i64 %timeout) {1668  %s = getelementptr inbounds i64, ptr %p, i32 -31669  %t = call i32 @llvm.wasm.memory.atomic.wait64(ptr %s, i64 %exp, i64 %timeout)1670  ret i32 %t1671}1672 1673; Without nuw, and even with nsw, we can't fold an offset.1674 1675; CHECK-LABEL: wait64_with_unfolded_offset:1676; CHECK: i32.const $push0=, 24{{$}}1677; CHECK: i32.add $push1=, $0, $pop0{{$}}1678; CHECK: memory.atomic.wait64 $push2=, 0($pop1), $1, $2{{$}}1679define i32 @wait64_with_unfolded_offset(ptr %p, i64 %exp, i64 %timeout) {1680  %q = ptrtoint ptr %p to i321681  %r = add nsw i32 %q, 241682  %s = inttoptr i32 %r to ptr1683  %t = call i32 @llvm.wasm.memory.atomic.wait64(ptr %s, i64 %exp, i64 %timeout)1684  ret i32 %t1685}1686 1687; Without inbounds, we can't fold a gep offset.1688 1689; CHECK-LABEL: wait64_with_unfolded_gep_offset:1690; CHECK: i32.const $push0=, 24{{$}}1691; CHECK: i32.add $push1=, $0, $pop0{{$}}1692; CHECK: memory.atomic.wait64 $push2=, 0($pop1), $1, $2{{$}}1693define i32 @wait64_with_unfolded_gep_offset(ptr %p, i64 %exp, i64 %timeout) {1694  %s = getelementptr i64, ptr %p, i32 31695  %t = call i32 @llvm.wasm.memory.atomic.wait64(ptr %s, i64 %exp, i64 %timeout)1696  ret i32 %t1697}1698 1699;===----------------------------------------------------------------------------1700; Notifies1701;===----------------------------------------------------------------------------1702 1703declare i32 @llvm.wasm.memory.atomic.notify(ptr, i32)1704 1705; Basic notify.1706 1707; CHECK-LABEL: notify_no_offset:1708; CHECK: memory.atomic.notify $push0=, 0($0), $1{{$}}1709; CHECK-NEXT: return $pop0{{$}}1710define i32 @notify_no_offset(ptr %p, i32 %notify_count) {1711  %v = call i32 @llvm.wasm.memory.atomic.notify(ptr %p, i32 %notify_count)1712  ret i32 %v1713}1714 1715; With an nuw add, we can fold an offset.1716 1717; CHECK-LABEL: notify_with_folded_offset:1718; CHECK: memory.atomic.notify $push0=, 24($0), $1{{$}}1719define i32 @notify_with_folded_offset(ptr %p, i32 %notify_count) {1720  %q = ptrtoint ptr %p to i321721  %r = add nuw i32 %q, 241722  %s = inttoptr i32 %r to ptr1723  %t = call i32 @llvm.wasm.memory.atomic.notify(ptr %s, i32 %notify_count)1724  ret i32 %t1725}1726 1727; With an inbounds gep, we can fold an offset.1728 1729; CHECK-LABEL: notify_with_folded_gep_offset:1730; CHECK: memory.atomic.notify $push0=, 24($0), $1{{$}}1731define i32 @notify_with_folded_gep_offset(ptr %p, i32 %notify_count) {1732  %s = getelementptr inbounds i32, ptr %p, i32 61733  %t = call i32 @llvm.wasm.memory.atomic.notify(ptr %s, i32 %notify_count)1734  ret i32 %t1735}1736 1737; We can't fold a negative offset though, even with an inbounds gep.1738 1739; CHECK-LABEL: notify_with_unfolded_gep_negative_offset:1740; CHECK: i32.const $push0=, -24{{$}}1741; CHECK: i32.add $push1=, $0, $pop0{{$}}1742; CHECK: memory.atomic.notify $push2=, 0($pop1), $1{{$}}1743define i32 @notify_with_unfolded_gep_negative_offset(ptr %p, i32 %notify_count) {1744  %s = getelementptr inbounds i32, ptr %p, i32 -61745  %t = call i32 @llvm.wasm.memory.atomic.notify(ptr %s, i32 %notify_count)1746  ret i32 %t1747}1748 1749; Without nuw, and even with nsw, we can't fold an offset.1750 1751; CHECK-LABEL: notify_with_unfolded_offset:1752; CHECK: i32.const $push0=, 24{{$}}1753; CHECK: i32.add $push1=, $0, $pop0{{$}}1754; CHECK: memory.atomic.notify $push2=, 0($pop1), $1{{$}}1755define i32 @notify_with_unfolded_offset(ptr %p, i32 %notify_count) {1756  %q = ptrtoint ptr %p to i321757  %r = add nsw i32 %q, 241758  %s = inttoptr i32 %r to ptr1759  %t = call i32 @llvm.wasm.memory.atomic.notify(ptr %s, i32 %notify_count)1760  ret i32 %t1761}1762 1763; Without inbounds, we can't fold a gep offset.1764 1765; CHECK-LABEL: notify_with_unfolded_gep_offset:1766; CHECK: i32.const $push0=, 24{{$}}1767; CHECK: i32.add $push1=, $0, $pop0{{$}}1768; CHECK: memory.atomic.notify $push2=, 0($pop1), $1{{$}}1769define i32 @notify_with_unfolded_gep_offset(ptr %p, i32 %notify_count) {1770  %s = getelementptr i32, ptr %p, i32 61771  %t = call i32 @llvm.wasm.memory.atomic.notify(ptr %s, i32 %notify_count)1772  ret i32 %t1773}1774 1775; When notifying from a fixed address, materialize a zero.1776 1777; CHECK-LABEL: notify_from_numeric_address1778; CHECK: i32.const $push0=, 0{{$}}1779; CHECK: memory.atomic.notify $push1=, 42($pop0), $0{{$}}1780define i32 @notify_from_numeric_address(i32 %notify_count) {1781  %s = inttoptr i32 42 to ptr1782  %t = call i32 @llvm.wasm.memory.atomic.notify(ptr %s, i32 %notify_count)1783  ret i32 %t1784}1785 1786; CHECK-LABEL: notify_from_global_address1787; CHECK: i32.const $push0=, 0{{$}}1788; CHECK: memory.atomic.notify $push1=, gv($pop0), $0{{$}}1789define i32 @notify_from_global_address(i32 %notify_count) {1790  %t = call i32 @llvm.wasm.memory.atomic.notify(ptr @gv, i32 %notify_count)1791  ret i32 %t1792}1793