1; RUN: llc -mtriple=armv8-none-linux-gnu -verify-machineinstrs < %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-LE --check-prefix=CHECK-ARM --check-prefix=CHECK-ARM-LE 2; RUN: llc -mtriple=armebv8-none-linux-gnu -verify-machineinstrs < %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-BE --check-prefix=CHECK-ARM --check-prefix=CHECK-ARM-BE 3; RUN: llc -mtriple=thumbv8-none-linux-gnu -verify-machineinstrs < %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-LE --check-prefix=CHECK-THUMB --check-prefix=CHECK-THUMB-LE 4; RUN: llc -mtriple=thumbebv8-none-linux-gnu -verify-machineinstrs < %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-BE --check-prefix=CHECK-THUMB --check-prefix=CHECK-THUMB-BE 5 6@var8 = global i8 0 7@var16 = global i16 0 8@var32 = global i32 0 9@var64 = global i64 0 10 11define i8 @test_atomic_load_add_i8(i8 %offset) nounwind { 12; CHECK-LABEL: test_atomic_load_add_i8: 13 %old = atomicrmw add i8* @var8, i8 %offset seq_cst 14; CHECK-NOT: dmb 15; CHECK-NOT: mcr 16; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8 17; CHECK: movt r[[ADDR]], :upper16:var8 18 19; CHECK: .LBB{{[0-9]+}}_1: 20; CHECK: ldaexb r[[OLD:[0-9]+]], [r[[ADDR]]] 21 ; r0 below is a reasonable guess but could change: it certainly comes into the 22 ; function there. 23; CHECK-NEXT: add{{s?}} [[NEW:r[0-9]+]], r[[OLD]], r0 24; CHECK-NEXT: stlexb [[STATUS:r[0-9]+]], [[NEW]], [r[[ADDR]]] 25; CHECK-NEXT: cmp [[STATUS]], #0 26; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 27; CHECK-NOT: dmb 28; CHECK-NOT: mcr 29 30; CHECK: mov r0, r[[OLD]] 31 ret i8 %old 32} 33 34define i16 @test_atomic_load_add_i16(i16 %offset) nounwind { 35; CHECK-LABEL: test_atomic_load_add_i16: 36 %old = atomicrmw add i16* @var16, i16 %offset acquire 37; CHECK-NOT: dmb 38; CHECK-NOT: mcr 39; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var16 40; CHECK: movt r[[ADDR]], :upper16:var16 41 42; CHECK: .LBB{{[0-9]+}}_1: 43; CHECK: ldaexh r[[OLD:[0-9]+]], [r[[ADDR]]] 44 ; r0 below is a reasonable guess but could change: it certainly comes into the 45 ; function there. 46; CHECK-NEXT: add{{s?}} [[NEW:r[0-9]+]], r[[OLD]], r0 47; CHECK-NEXT: strexh [[STATUS:r[0-9]+]], [[NEW]], [r[[ADDR]]] 48; CHECK-NEXT: cmp [[STATUS]], #0 49; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 50; CHECK-NOT: dmb 51; CHECK-NOT: mcr 52 53; CHECK: mov r0, r[[OLD]] 54 ret i16 %old 55} 56 57define i32 @test_atomic_load_add_i32(i32 %offset) nounwind { 58; CHECK-LABEL: test_atomic_load_add_i32: 59 %old = atomicrmw add i32* @var32, i32 %offset release 60; CHECK-NOT: dmb 61; CHECK-NOT: mcr 62; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var32 63; CHECK: movt r[[ADDR]], :upper16:var32 64 65; CHECK: .LBB{{[0-9]+}}_1: 66; CHECK: ldrex r[[OLD:[0-9]+]], [r[[ADDR]]] 67 ; r0 below is a reasonable guess but could change: it certainly comes into the 68 ; function there. 69; CHECK-NEXT: add{{s?}} [[NEW:r[0-9]+]], r[[OLD]], r0 70; CHECK-NEXT: stlex [[STATUS:r[0-9]+]], [[NEW]], [r[[ADDR]]] 71; CHECK-NEXT: cmp [[STATUS]], #0 72; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 73; CHECK-NOT: dmb 74; CHECK-NOT: mcr 75 76; CHECK: mov r0, r[[OLD]] 77 ret i32 %old 78} 79 80define void @test_atomic_load_add_i64(i64 %offset) nounwind { 81; CHECK-LABEL: test_atomic_load_add_i64: 82 %old = atomicrmw add i64* @var64, i64 %offset monotonic 83; CHECK-NOT: dmb 84; CHECK-NOT: mcr 85; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64 86; CHECK: movt r[[ADDR]], :upper16:var64 87 88; CHECK: .LBB{{[0-9]+}}_1: 89; CHECK: ldrexd r[[OLD1:[0-9]+]], r[[OLD2:[0-9]+]], [r[[ADDR]]] 90 ; r0, r1 below is a reasonable guess but could change: it certainly comes into the 91 ; function there. 92; CHECK-LE-NEXT: adds{{(\.w)?}} [[NEW1:r[0-9]+|lr]], r[[OLD1]], r0 93; CHECK-LE-NEXT: adc{{(\.w)?}} [[NEW2:r[0-9]+]], r[[OLD2]], r1 94; CHECK-BE-NEXT: adds{{(\.w)?}} [[NEW2:r[0-9]+|lr]], r[[OLD2]], r1 95; CHECK-BE-NEXT: adc{{(\.w)?}} [[NEW1:r[0-9]+]], r[[OLD1]], r0 96; CHECK-NEXT: strexd [[STATUS:r[0-9]+]], [[NEW1]], [[NEW2]], [r[[ADDR]]] 97; CHECK-NEXT: cmp [[STATUS]], #0 98; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 99; CHECK-NOT: dmb 100; CHECK-NOT: mcr 101 102; CHECK: strd r[[OLD1]], r[[OLD2]], [r[[ADDR]]] 103 store i64 %old, i64* @var64 104 ret void 105} 106 107define i8 @test_atomic_load_sub_i8(i8 %offset) nounwind { 108; CHECK-LABEL: test_atomic_load_sub_i8: 109 %old = atomicrmw sub i8* @var8, i8 %offset monotonic 110; CHECK-NOT: dmb 111; CHECK-NOT: mcr 112; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8 113; CHECK: movt r[[ADDR]], :upper16:var8 114 115; CHECK: .LBB{{[0-9]+}}_1: 116; CHECK: ldrexb r[[OLD:[0-9]+]], [r[[ADDR]]] 117 ; r0 below is a reasonable guess but could change: it certainly comes into the 118 ; function there. 119; CHECK-NEXT: sub{{s?}} [[NEW:r[0-9]+]], r[[OLD]], r0 120; CHECK-NEXT: strexb [[STATUS:r[0-9]+]], [[NEW]], [r[[ADDR]]] 121; CHECK-NEXT: cmp [[STATUS]], #0 122; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 123; CHECK-NOT: dmb 124; CHECK-NOT: mcr 125 126; CHECK: mov r0, r[[OLD]] 127 ret i8 %old 128} 129 130define i16 @test_atomic_load_sub_i16(i16 %offset) nounwind { 131; CHECK-LABEL: test_atomic_load_sub_i16: 132 %old = atomicrmw sub i16* @var16, i16 %offset release 133; CHECK-NOT: dmb 134; CHECK-NOT: mcr 135; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var16 136; CHECK: movt r[[ADDR]], :upper16:var16 137 138; CHECK: .LBB{{[0-9]+}}_1: 139; CHECK: ldrexh r[[OLD:[0-9]+]], [r[[ADDR]]] 140 ; r0 below is a reasonable guess but could change: it certainly comes into the 141 ; function there. 142; CHECK-NEXT: sub{{s?}} [[NEW:r[0-9]+]], r[[OLD]], r0 143; CHECK-NEXT: stlexh [[STATUS:r[0-9]+]], [[NEW]], [r[[ADDR]]] 144; CHECK-NEXT: cmp [[STATUS]], #0 145; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 146; CHECK-NOT: dmb 147; CHECK-NOT: mcr 148 149; CHECK: mov r0, r[[OLD]] 150 ret i16 %old 151} 152 153define i32 @test_atomic_load_sub_i32(i32 %offset) nounwind { 154; CHECK-LABEL: test_atomic_load_sub_i32: 155 %old = atomicrmw sub i32* @var32, i32 %offset acquire 156; CHECK-NOT: dmb 157; CHECK-NOT: mcr 158; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var32 159; CHECK: movt r[[ADDR]], :upper16:var32 160 161; CHECK: .LBB{{[0-9]+}}_1: 162; CHECK: ldaex r[[OLD:[0-9]+]], [r[[ADDR]]] 163 ; r0 below is a reasonable guess but could change: it certainly comes into the 164 ; function there. 165; CHECK-NEXT: sub{{s?}} [[NEW:r[0-9]+]], r[[OLD]], r0 166; CHECK-NEXT: strex [[STATUS:r[0-9]+]], [[NEW]], [r[[ADDR]]] 167; CHECK-NEXT: cmp [[STATUS]], #0 168; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 169; CHECK-NOT: dmb 170; CHECK-NOT: mcr 171 172; CHECK: mov r0, r[[OLD]] 173 ret i32 %old 174} 175 176define void @test_atomic_load_sub_i64(i64 %offset) nounwind { 177; CHECK-LABEL: test_atomic_load_sub_i64: 178 %old = atomicrmw sub i64* @var64, i64 %offset seq_cst 179; CHECK-NOT: dmb 180; CHECK-NOT: mcr 181; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64 182; CHECK: movt r[[ADDR]], :upper16:var64 183 184; CHECK: .LBB{{[0-9]+}}_1: 185; CHECK: ldaexd r[[OLD1:[0-9]+]], r[[OLD2:[0-9]+]], [r[[ADDR]]] 186 ; r0, r1 below is a reasonable guess but could change: it certainly comes into the 187 ; function there. 188; CHECK-LE-NEXT: subs{{(\.w)?}} [[NEW1:r[0-9]+|lr]], r[[OLD1]], r0 189; CHECK-LE-NEXT: sbc{{(\.w)?}} [[NEW2:r[0-9]+]], r[[OLD2]], r1 190; CHECK-BE-NEXT: subs{{(\.w)?}} [[NEW2:r[0-9]+|lr]], r[[OLD2]], r1 191; CHECK-BE-NEXT: sbc{{(\.w)?}} [[NEW1:r[0-9]+]], r[[OLD1]], r0 192; CHECK-NEXT: stlexd [[STATUS:r[0-9]+]], [[NEW1]], [[NEW2]], [r[[ADDR]]] 193; CHECK-NEXT: cmp [[STATUS]], #0 194; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 195; CHECK-NOT: dmb 196; CHECK-NOT: mcr 197 198; CHECK: strd r[[OLD1]], r[[OLD2]], [r[[ADDR]]] 199 store i64 %old, i64* @var64 200 ret void 201} 202 203define i8 @test_atomic_load_and_i8(i8 %offset) nounwind { 204; CHECK-LABEL: test_atomic_load_and_i8: 205 %old = atomicrmw and i8* @var8, i8 %offset release 206; CHECK-NOT: dmb 207; CHECK-NOT: mcr 208; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8 209; CHECK: movt r[[ADDR]], :upper16:var8 210 211; CHECK: .LBB{{[0-9]+}}_1: 212; CHECK: ldrexb r[[OLD:[0-9]+]], [r[[ADDR]]] 213 ; r0 below is a reasonable guess but could change: it certainly comes into the 214 ; function there. 215; CHECK-NEXT: and{{(\.w)?}} [[NEW:r[0-9]+]], r[[OLD]], r0 216; CHECK-NEXT: stlexb [[STATUS:r[0-9]+]], [[NEW]], [r[[ADDR]]] 217; CHECK-NEXT: cmp [[STATUS]], #0 218; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 219; CHECK-NOT: dmb 220; CHECK-NOT: mcr 221 222; CHECK: mov r0, r[[OLD]] 223 ret i8 %old 224} 225 226define i16 @test_atomic_load_and_i16(i16 %offset) nounwind { 227; CHECK-LABEL: test_atomic_load_and_i16: 228 %old = atomicrmw and i16* @var16, i16 %offset monotonic 229; CHECK-NOT: dmb 230; CHECK-NOT: mcr 231; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var16 232; CHECK: movt r[[ADDR]], :upper16:var16 233 234; CHECK: .LBB{{[0-9]+}}_1: 235; CHECK: ldrexh r[[OLD:[0-9]+]], [r[[ADDR]]] 236 ; r0 below is a reasonable guess but could change: it certainly comes into the 237 ; function there. 238; CHECK-NEXT: and{{(\.w)?}} [[NEW:r[0-9]+]], r[[OLD]], r0 239; CHECK-NEXT: strexh [[STATUS:r[0-9]+]], [[NEW]], [r[[ADDR]]] 240; CHECK-NEXT: cmp [[STATUS]], #0 241; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 242; CHECK-NOT: dmb 243; CHECK-NOT: mcr 244 245; CHECK: mov r0, r[[OLD]] 246 ret i16 %old 247} 248 249define i32 @test_atomic_load_and_i32(i32 %offset) nounwind { 250; CHECK-LABEL: test_atomic_load_and_i32: 251 %old = atomicrmw and i32* @var32, i32 %offset seq_cst 252; CHECK-NOT: dmb 253; CHECK-NOT: mcr 254; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var32 255; CHECK: movt r[[ADDR]], :upper16:var32 256 257; CHECK: .LBB{{[0-9]+}}_1: 258; CHECK: ldaex r[[OLD:[0-9]+]], [r[[ADDR]]] 259 ; r0 below is a reasonable guess but could change: it certainly comes into the 260 ; function there. 261; CHECK-NEXT: and{{(\.w)?}} [[NEW:r[0-9]+]], r[[OLD]], r0 262; CHECK-NEXT: stlex [[STATUS:r[0-9]+]], [[NEW]], [r[[ADDR]]] 263; CHECK-NEXT: cmp [[STATUS]], #0 264; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 265; CHECK-NOT: dmb 266; CHECK-NOT: mcr 267 268; CHECK: mov r0, r[[OLD]] 269 ret i32 %old 270} 271 272define void @test_atomic_load_and_i64(i64 %offset) nounwind { 273; CHECK-LABEL: test_atomic_load_and_i64: 274 %old = atomicrmw and i64* @var64, i64 %offset acquire 275; CHECK-NOT: dmb 276; CHECK-NOT: mcr 277; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64 278; CHECK: movt r[[ADDR]], :upper16:var64 279 280; CHECK: .LBB{{[0-9]+}}_1: 281; CHECK: ldaexd r[[OLD1:[0-9]+]], r[[OLD2:[0-9]+]], [r[[ADDR]]] 282 ; r0, r1 below is a reasonable guess but could change: it certainly comes into the 283 ; function there. 284; CHECK-LE-DAG: and{{(\.w)?}} [[NEW1:r[0-9]+|lr]], r[[OLD1]], r0 285; CHECK-LE-DAG: and{{(\.w)?}} [[NEW2:r[0-9]+|lr]], r[[OLD2]], r1 286; CHECK-BE-DAG: and{{(\.w)?}} [[NEW2:r[0-9]+|lr]], r[[OLD2]], r1 287; CHECK-BE-DAG: and{{(\.w)?}} [[NEW1:r[0-9]+|lr]], r[[OLD1]], r0 288; CHECK: strexd [[STATUS:r[0-9]+]], [[NEW1]], [[NEW2]], [r[[ADDR]]] 289; CHECK-NEXT: cmp [[STATUS]], #0 290; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 291; CHECK-NOT: dmb 292; CHECK-NOT: mcr 293 294; CHECK: strd r[[OLD1]], r[[OLD2]], [r[[ADDR]]] 295 store i64 %old, i64* @var64 296 ret void 297} 298 299define i8 @test_atomic_load_or_i8(i8 %offset) nounwind { 300; CHECK-LABEL: test_atomic_load_or_i8: 301 %old = atomicrmw or i8* @var8, i8 %offset seq_cst 302; CHECK-NOT: dmb 303; CHECK-NOT: mcr 304; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8 305; CHECK: movt r[[ADDR]], :upper16:var8 306 307; CHECK: .LBB{{[0-9]+}}_1: 308; CHECK: ldaexb r[[OLD:[0-9]+]], [r[[ADDR]]] 309 ; r0 below is a reasonable guess but could change: it certainly comes into the 310 ; function there. 311; CHECK-NEXT: orr{{(\.w)?}} [[NEW:r[0-9]+]], r[[OLD]], r0 312; CHECK-NEXT: stlexb [[STATUS:r[0-9]+]], [[NEW]], [r[[ADDR]]] 313; CHECK-NEXT: cmp [[STATUS]], #0 314; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 315; CHECK-NOT: dmb 316; CHECK-NOT: mcr 317 318; CHECK: mov r0, r[[OLD]] 319 ret i8 %old 320} 321 322define i16 @test_atomic_load_or_i16(i16 %offset) nounwind { 323; CHECK-LABEL: test_atomic_load_or_i16: 324 %old = atomicrmw or i16* @var16, i16 %offset monotonic 325; CHECK-NOT: dmb 326; CHECK-NOT: mcr 327; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var16 328; CHECK: movt r[[ADDR]], :upper16:var16 329 330; CHECK: .LBB{{[0-9]+}}_1: 331; CHECK: ldrexh r[[OLD:[0-9]+]], [r[[ADDR]]] 332 ; r0 below is a reasonable guess but could change: it certainly comes into the 333 ; function there. 334; CHECK-NEXT: orr{{(\.w)?}} [[NEW:r[0-9]+]], r[[OLD]], r0 335; CHECK-NEXT: strexh [[STATUS:r[0-9]+]], [[NEW]], [r[[ADDR]]] 336; CHECK-NEXT: cmp [[STATUS]], #0 337; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 338; CHECK-NOT: dmb 339; CHECK-NOT: mcr 340 341; CHECK: mov r0, r[[OLD]] 342 ret i16 %old 343} 344 345define i32 @test_atomic_load_or_i32(i32 %offset) nounwind { 346; CHECK-LABEL: test_atomic_load_or_i32: 347 %old = atomicrmw or i32* @var32, i32 %offset acquire 348; CHECK-NOT: dmb 349; CHECK-NOT: mcr 350; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var32 351; CHECK: movt r[[ADDR]], :upper16:var32 352 353; CHECK: .LBB{{[0-9]+}}_1: 354; CHECK: ldaex r[[OLD:[0-9]+]], [r[[ADDR]]] 355 ; r0 below is a reasonable guess but could change: it certainly comes into the 356 ; function there. 357; CHECK-NEXT: orr{{(\.w)?}} [[NEW:r[0-9]+]], r[[OLD]], r0 358; CHECK-NEXT: strex [[STATUS:r[0-9]+]], [[NEW]], [r[[ADDR]]] 359; CHECK-NEXT: cmp [[STATUS]], #0 360; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 361; CHECK-NOT: dmb 362; CHECK-NOT: mcr 363 364; CHECK: mov r0, r[[OLD]] 365 ret i32 %old 366} 367 368define void @test_atomic_load_or_i64(i64 %offset) nounwind { 369; CHECK-LABEL: test_atomic_load_or_i64: 370 %old = atomicrmw or i64* @var64, i64 %offset release 371; CHECK-NOT: dmb 372; CHECK-NOT: mcr 373; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64 374; CHECK: movt r[[ADDR]], :upper16:var64 375 376; CHECK: .LBB{{[0-9]+}}_1: 377; CHECK: ldrexd r[[OLD1:[0-9]+]], r[[OLD2:[0-9]+]], [r[[ADDR]]] 378 ; r0, r1 below is a reasonable guess but could change: it certainly comes into the 379 ; function there. 380; CHECK-LE-DAG: orr{{(\.w)?}} [[NEW1:r[0-9]+|lr]], r[[OLD1]], r0 381; CHECK-LE-DAG: orr{{(\.w)?}} [[NEW2:r[0-9]+|lr]], r[[OLD2]], r1 382; CHECK-BE-DAG: orr{{(\.w)?}} [[NEW2:r[0-9]+|lr]], r[[OLD2]], r1 383; CHECK-BE-DAG: orr{{(\.w)?}} [[NEW1:r[0-9]+|lr]], r[[OLD1]], r0 384; CHECK: stlexd [[STATUS:r[0-9]+]], [[NEW1]], [[NEW2]], [r[[ADDR]]] 385; CHECK-NEXT: cmp [[STATUS]], #0 386; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 387; CHECK-NOT: dmb 388; CHECK-NOT: mcr 389 390; CHECK: strd r[[OLD1]], r[[OLD2]], [r[[ADDR]]] 391 store i64 %old, i64* @var64 392 ret void 393} 394 395define i8 @test_atomic_load_xor_i8(i8 %offset) nounwind { 396; CHECK-LABEL: test_atomic_load_xor_i8: 397 %old = atomicrmw xor i8* @var8, i8 %offset acquire 398; CHECK-NOT: dmb 399; CHECK-NOT: mcr 400; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8 401; CHECK: movt r[[ADDR]], :upper16:var8 402 403; CHECK: .LBB{{[0-9]+}}_1: 404; CHECK: ldaexb r[[OLD:[0-9]+]], [r[[ADDR]]] 405 ; r0 below is a reasonable guess but could change: it certainly comes into the 406 ; function there. 407; CHECK-NEXT: eor{{(\.w)?}} [[NEW:r[0-9]+]], r[[OLD]], r0 408; CHECK-NEXT: strexb [[STATUS:r[0-9]+]], [[NEW]], [r[[ADDR]]] 409; CHECK-NEXT: cmp [[STATUS]], #0 410; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 411; CHECK-NOT: dmb 412; CHECK-NOT: mcr 413 414; CHECK: mov r0, r[[OLD]] 415 ret i8 %old 416} 417 418define i16 @test_atomic_load_xor_i16(i16 %offset) nounwind { 419; CHECK-LABEL: test_atomic_load_xor_i16: 420 %old = atomicrmw xor i16* @var16, i16 %offset release 421; CHECK-NOT: dmb 422; CHECK-NOT: mcr 423; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var16 424; CHECK: movt r[[ADDR]], :upper16:var16 425 426; CHECK: .LBB{{[0-9]+}}_1: 427; CHECK: ldrexh r[[OLD:[0-9]+]], [r[[ADDR]]] 428 ; r0 below is a reasonable guess but could change: it certainly comes into the 429 ; function there. 430; CHECK-NEXT: eor{{(\.w)?}} [[NEW:r[0-9]+]], r[[OLD]], r0 431; CHECK-NEXT: stlexh [[STATUS:r[0-9]+]], [[NEW]], [r[[ADDR]]] 432; CHECK-NEXT: cmp [[STATUS]], #0 433; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 434; CHECK-NOT: dmb 435; CHECK-NOT: mcr 436 437; CHECK: mov r0, r[[OLD]] 438 ret i16 %old 439} 440 441define i32 @test_atomic_load_xor_i32(i32 %offset) nounwind { 442; CHECK-LABEL: test_atomic_load_xor_i32: 443 %old = atomicrmw xor i32* @var32, i32 %offset seq_cst 444; CHECK-NOT: dmb 445; CHECK-NOT: mcr 446; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var32 447; CHECK: movt r[[ADDR]], :upper16:var32 448 449; CHECK: .LBB{{[0-9]+}}_1: 450; CHECK: ldaex r[[OLD:[0-9]+]], [r[[ADDR]]] 451 ; r0 below is a reasonable guess but could change: it certainly comes into the 452 ; function there. 453; CHECK-NEXT: eor{{(\.w)?}} [[NEW:r[0-9]+]], r[[OLD]], r0 454; CHECK-NEXT: stlex [[STATUS:r[0-9]+]], [[NEW]], [r[[ADDR]]] 455; CHECK-NEXT: cmp [[STATUS]], #0 456; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 457; CHECK-NOT: dmb 458; CHECK-NOT: mcr 459 460; CHECK: mov r0, r[[OLD]] 461 ret i32 %old 462} 463 464define void @test_atomic_load_xor_i64(i64 %offset) nounwind { 465; CHECK-LABEL: test_atomic_load_xor_i64: 466 %old = atomicrmw xor i64* @var64, i64 %offset monotonic 467; CHECK-NOT: dmb 468; CHECK-NOT: mcr 469; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64 470; CHECK: movt r[[ADDR]], :upper16:var64 471 472; CHECK: .LBB{{[0-9]+}}_1: 473; CHECK: ldrexd r[[OLD1:[0-9]+]], r[[OLD2:[0-9]+]], [r[[ADDR]]] 474 ; r0, r1 below is a reasonable guess but could change: it certainly comes into the 475 ; function there. 476; CHECK-LE-DAG: eor{{(\.w)?}} [[NEW1:r[0-9]+|lr]], r[[OLD1]], r0 477; CHECK-LE-DAG: eor{{(\.w)?}} [[NEW2:r[0-9]+|lr]], r[[OLD2]], r1 478; CHECK-BE-DAG: eor{{(\.w)?}} [[NEW2:r[0-9]+|lr]], r[[OLD2]], r1 479; CHECK-BE-DAG: eor{{(\.w)?}} [[NEW1:r[0-9]+|lr]], r[[OLD1]], r0 480; CHECK: strexd [[STATUS:r[0-9]+]], [[NEW1]], [[NEW2]], [r[[ADDR]]] 481; CHECK-NEXT: cmp [[STATUS]], #0 482; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 483; CHECK-NOT: dmb 484; CHECK-NOT: mcr 485 486; CHECK: strd r[[OLD1]], r[[OLD2]], [r[[ADDR]]] 487 store i64 %old, i64* @var64 488 ret void 489} 490 491define i8 @test_atomic_load_xchg_i8(i8 %offset) nounwind { 492; CHECK-LABEL: test_atomic_load_xchg_i8: 493 %old = atomicrmw xchg i8* @var8, i8 %offset monotonic 494; CHECK-NOT: dmb 495; CHECK-NOT: mcr 496; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8 497; CHECK: movt r[[ADDR]], :upper16:var8 498 499; CHECK: .LBB{{[0-9]+}}_1: 500; CHECK: ldrexb r[[OLD:[0-9]+]], [r[[ADDR]]] 501 ; r0 below is a reasonable guess but could change: it certainly comes into the 502 ; function there. 503; CHECK-NEXT: strexb [[STATUS:r[0-9]+]], r0, [r[[ADDR]]] 504; CHECK-NEXT: cmp [[STATUS]], #0 505; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 506; CHECK-NOT: dmb 507; CHECK-NOT: mcr 508 509; CHECK: mov r0, r[[OLD]] 510 ret i8 %old 511} 512 513define i16 @test_atomic_load_xchg_i16(i16 %offset) nounwind { 514; CHECK-LABEL: test_atomic_load_xchg_i16: 515 %old = atomicrmw xchg i16* @var16, i16 %offset seq_cst 516; CHECK-NOT: dmb 517; CHECK-NOT: mcr 518; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var16 519; CHECK: movt r[[ADDR]], :upper16:var16 520 521; CHECK: .LBB{{[0-9]+}}_1: 522; CHECK: ldaexh r[[OLD:[0-9]+]], [r[[ADDR]]] 523 ; r0 below is a reasonable guess but could change: it certainly comes into the 524 ; function there. 525; CHECK-NEXT: stlexh [[STATUS:r[0-9]+]], r0, [r[[ADDR]]] 526; CHECK-NEXT: cmp [[STATUS]], #0 527; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 528; CHECK-NOT: dmb 529; CHECK-NOT: mcr 530 531; CHECK: mov r0, r[[OLD]] 532 ret i16 %old 533} 534 535define i32 @test_atomic_load_xchg_i32(i32 %offset) nounwind { 536; CHECK-LABEL: test_atomic_load_xchg_i32: 537 %old = atomicrmw xchg i32* @var32, i32 %offset release 538; CHECK-NOT: dmb 539; CHECK-NOT: mcr 540; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var32 541; CHECK: movt r[[ADDR]], :upper16:var32 542 543; CHECK: .LBB{{[0-9]+}}_1: 544; CHECK: ldrex r[[OLD:[0-9]+]], [r[[ADDR]]] 545 ; r0 below is a reasonable guess but could change: it certainly comes into the 546 ; function there. 547; CHECK-NEXT: stlex [[STATUS:r[0-9]+]], r0, [r[[ADDR]]] 548; CHECK-NEXT: cmp [[STATUS]], #0 549; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 550; CHECK-NOT: dmb 551; CHECK-NOT: mcr 552 553; CHECK: mov r0, r[[OLD]] 554 ret i32 %old 555} 556 557define void @test_atomic_load_xchg_i64(i64 %offset) nounwind { 558; CHECK-LABEL: test_atomic_load_xchg_i64: 559 %old = atomicrmw xchg i64* @var64, i64 %offset acquire 560; CHECK-NOT: dmb 561; CHECK-NOT: mcr 562; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64 563; CHECK: movt r[[ADDR]], :upper16:var64 564 565; CHECK: .LBB{{[0-9]+}}_1: 566; CHECK: ldaexd [[OLD1:r[0-9]+]], [[OLD2:r[0-9]+|lr]], [r[[ADDR]]] 567 ; r0, r1 below is a reasonable guess but could change: it certainly comes into the 568 ; function there. 569; CHECK-NEXT: strexd [[STATUS:r[0-9]+]], r0, r1, [r[[ADDR]]] 570; CHECK-NEXT: cmp [[STATUS]], #0 571; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 572; CHECK-NOT: dmb 573; CHECK-NOT: mcr 574 575; CHECK: strd [[OLD1]], [[OLD2]], [r[[ADDR]]] 576 store i64 %old, i64* @var64 577 ret void 578} 579 580define i8 @test_atomic_load_min_i8(i8 signext %offset) nounwind { 581; CHECK-LABEL: test_atomic_load_min_i8: 582 %old = atomicrmw min i8* @var8, i8 %offset acquire 583; CHECK-NOT: dmb 584; CHECK-NOT: mcr 585; CHECK-DAG: movw [[ADDR:r[0-9]+|lr]], :lower16:var8 586; CHECK-DAG: movt [[ADDR]], :upper16:var8 587 588; CHECK: .LBB{{[0-9]+}}_1: 589; CHECK: ldaexb r[[OLD:[0-9]+]], {{.*}}[[ADDR]] 590; CHECK-NEXT: sxtb r[[OLDX:[0-9]+]], r[[OLD]] 591 ; r0 below is a reasonable guess but could change: it certainly comes into the 592 ; function there. 593; CHECK-NEXT: cmp r[[OLDX]], r0 594; Thumb mode: it le 595; CHECK: movle r[[OLDX]], r[[OLD]] 596; CHECK-NEXT: strexb [[STATUS:r[0-9]+]], r[[OLDX]], {{.*}}[[ADDR]]] 597; CHECK-NEXT: cmp [[STATUS]], #0 598; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 599; CHECK-NOT: dmb 600; CHECK-NOT: mcr 601 602; CHECK: mov r0, r[[OLD]] 603 ret i8 %old 604} 605 606define i16 @test_atomic_load_min_i16(i16 signext %offset) nounwind { 607; CHECK-LABEL: test_atomic_load_min_i16: 608 %old = atomicrmw min i16* @var16, i16 %offset release 609; CHECK-NOT: dmb 610; CHECK-NOT: mcr 611; CHECK: movw [[ADDR:r[0-9]+|lr]], :lower16:var16 612; CHECK: movt [[ADDR]], :upper16:var16 613 614; CHECK: .LBB{{[0-9]+}}_1: 615; CHECK: ldrexh r[[OLD:[0-9]+]], {{.*}}[[ADDR]] 616; CHECK-NEXT: sxth r[[OLDX:[0-9]+]], r[[OLD]] 617 ; r0 below is a reasonable guess but could change: it certainly comes into the 618 ; function there. 619; CHECK-NEXT: cmp r[[OLDX]], r0 620; Thumb mode: it le 621; CHECK: movle r[[OLDX]], r[[OLD]] 622; CHECK-NEXT: stlexh [[STATUS:r[0-9]+]], r[[OLDX]], {{.*}}[[ADDR]] 623; CHECK-NEXT: cmp [[STATUS]], #0 624; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 625; CHECK-NOT: dmb 626; CHECK-NOT: mcr 627 628; CHECK: mov r0, r[[OLD]] 629 ret i16 %old 630} 631 632define i32 @test_atomic_load_min_i32(i32 %offset) nounwind { 633; CHECK-LABEL: test_atomic_load_min_i32: 634 %old = atomicrmw min i32* @var32, i32 %offset monotonic 635; CHECK-NOT: dmb 636; CHECK-NOT: mcr 637; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var32 638; CHECK: movt r[[ADDR]], :upper16:var32 639 640; CHECK: .LBB{{[0-9]+}}_1: 641; CHECK: ldrex r[[OLD:[0-9]+]], [r[[ADDR]]] 642 ; r0 below is a reasonable guess but could change: it certainly comes into the 643 ; function there. 644; CHECK-NEXT: mov r[[NEW:[0-9]+]], r0 645; CHECK-NEXT: cmp r[[OLD]], r0 646; Thumb mode: it le 647; CHECK: movle r[[NEW]], r[[OLD]] 648; CHECK-NEXT: strex [[STATUS:r[0-9]+]], r[[NEW]], [r[[ADDR]]] 649; CHECK-NEXT: cmp [[STATUS]], #0 650; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 651; CHECK-NOT: dmb 652; CHECK-NOT: mcr 653 654; CHECK: mov r0, r[[OLD]] 655 ret i32 %old 656} 657 658define void @test_atomic_load_min_i64(i64 %offset) nounwind { 659; CHECK-LABEL: test_atomic_load_min_i64: 660 %old = atomicrmw min i64* @var64, i64 %offset seq_cst 661; CHECK-NOT: dmb 662; CHECK-NOT: mcr 663; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64 664; CHECK: movt r[[ADDR]], :upper16:var64 665 666; CHECK: .LBB{{[0-9]+}}_1: 667; CHECK: ldaexd [[OLD1:r[0-9]+|lr]], [[OLD2:r[0-9]+|lr]], [r[[ADDR]]] 668 ; r0, r1 below is a reasonable guess but could change: it certainly comes into the 669 ; function there. 670; CHECK-ARM: mov [[MINHI:r[0-9]+]], r1 671; CHECK-ARM-LE: subs {{[^,]+}}, r0, [[OLD1]] 672; CHECK-ARM-LE: sbcs {{[^,]+}}, r1, [[OLD2]] 673; CHECK-ARM-BE: subs {{[^,]+}}, r1, [[OLD2]] 674; CHECK-ARM-BE: sbcs {{[^,]+}}, r0, [[OLD1]] 675; CHECK-ARM: mov [[CMP:r[0-9]+|lr]], #0 676; CHECK-ARM: movwge [[CMP:r[0-9]+|lr]], #1 677; CHECK-ARM: cmp [[CMP:r[0-9]+|lr]], #0 678; CHECK-ARM: movne [[MINHI]], [[OLD2]] 679; CHECK-ARM: mov [[MINLO:r[0-9]+]], r0 680; CHECK-ARM: movne [[MINLO]], [[OLD1]] 681; CHECK-ARM: stlexd [[STATUS:r[0-9]+]], [[MINLO]], [[MINHI]], [r[[ADDR]]] 682; CHECK-THUMB: stlexd [[STATUS:r[0-9]+]], {{r[0-9]+}}, {{r[0-9]+}}, [r[[ADDR]]] 683; CHECK-NEXT: cmp [[STATUS]], #0 684; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 685; CHECK-NOT: dmb 686; CHECK-NOT: mcr 687 688; CHECK-ARM: strd [[OLD1]], [[OLD2]], [r[[ADDR]]] 689 store i64 %old, i64* @var64 690 ret void 691} 692 693define i8 @test_atomic_load_max_i8(i8 signext %offset) nounwind { 694; CHECK-LABEL: test_atomic_load_max_i8: 695 %old = atomicrmw max i8* @var8, i8 %offset seq_cst 696; CHECK-NOT: dmb 697; CHECK-NOT: mcr 698; CHECK: movw [[ADDR:r[0-9]+|lr]], :lower16:var8 699; CHECK: movt [[ADDR]], :upper16:var8 700 701; CHECK: .LBB{{[0-9]+}}_1: 702; CHECK: ldaexb r[[OLD:[0-9]+]], {{.*}}[[ADDR]] 703; CHECK-NEXT: sxtb r[[OLDX:[0-9]+]], r[[OLD]] 704 ; r0 below is a reasonable guess but could change: it certainly comes into the 705 ; function there. 706; CHECK-NEXT: cmp r[[OLDX]], r0 707; Thumb mode: it gt 708; CHECK: movgt r[[OLDX]], r[[OLD]] 709; CHECK-NEXT: stlexb [[STATUS:r[0-9]+]], r[[OLDX]], {{.*}}[[ADDR]] 710; CHECK-NEXT: cmp [[STATUS]], #0 711; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 712; CHECK-NOT: dmb 713; CHECK-NOT: mcr 714 715; CHECK: mov r0, r[[OLD]] 716 ret i8 %old 717} 718 719define i16 @test_atomic_load_max_i16(i16 signext %offset) nounwind { 720; CHECK-LABEL: test_atomic_load_max_i16: 721 %old = atomicrmw max i16* @var16, i16 %offset acquire 722; CHECK-NOT: dmb 723; CHECK-NOT: mcr 724; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var16 725; CHECK: movt r[[ADDR]], :upper16:var16 726 727; CHECK: .LBB{{[0-9]+}}_1: 728; CHECK: ldaexh r[[OLD:[0-9]+]], [r[[ADDR]]] 729; CHECK-NEXT: sxth r[[OLDX:[0-9]+]], r[[OLD]] 730 ; r0 below is a reasonable guess but could change: it certainly comes into the 731 ; function there. 732; CHECK-NEXT: cmp r[[OLDX]], r0 733; Thumb mode: it gt 734; CHECK: movgt r[[OLDX]], r[[OLD]] 735; CHECK-NEXT: strexh [[STATUS:r[0-9]+]], r[[OLDX]], [r[[ADDR]]] 736; CHECK-NEXT: cmp [[STATUS]], #0 737; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 738; CHECK-NOT: dmb 739; CHECK-NOT: mcr 740 741; CHECK: mov r0, r[[OLD]] 742 ret i16 %old 743} 744 745define i32 @test_atomic_load_max_i32(i32 %offset) nounwind { 746; CHECK-LABEL: test_atomic_load_max_i32: 747 %old = atomicrmw max i32* @var32, i32 %offset release 748; CHECK-NOT: dmb 749; CHECK-NOT: mcr 750; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var32 751; CHECK: movt r[[ADDR]], :upper16:var32 752 753; CHECK: .LBB{{[0-9]+}}_1: 754; CHECK: ldrex r[[OLD:[0-9]+]], [r[[ADDR]]] 755 ; r0 below is a reasonable guess but could change: it certainly comes into the 756 ; function there. 757; CHECK-NEXT: mov r[[NEW:[0-9]+]], r0 758; CHECK-NEXT: cmp r[[OLD]], r0 759; Thumb mode: it gt 760; CHECK: movgt r[[NEW]], r[[OLD]] 761; CHECK-NEXT: stlex [[STATUS:r[0-9]+]], r[[NEW]], [r[[ADDR]]] 762; CHECK-NEXT: cmp [[STATUS]], #0 763; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 764; CHECK-NOT: dmb 765; CHECK-NOT: mcr 766 767; CHECK: mov r0, r[[OLD]] 768 ret i32 %old 769} 770 771define void @test_atomic_load_max_i64(i64 %offset) nounwind { 772; CHECK-LABEL: test_atomic_load_max_i64: 773 %old = atomicrmw max i64* @var64, i64 %offset monotonic 774; CHECK-NOT: dmb 775; CHECK-NOT: mcr 776; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64 777; CHECK: movt r[[ADDR]], :upper16:var64 778 779; CHECK: .LBB{{[0-9]+}}_1: 780; CHECK: ldrexd [[OLD1:r[0-9]+]], [[OLD2:r[0-9]+|lr]], [r[[ADDR]]] 781 ; r0, r1 below is a reasonable guess but could change: it certainly comes into the 782 ; function there. 783; CHECK-ARM: mov [[MINHI:r[0-9]+]], r1 784; CHECK-ARM-LE: subs {{[^,]+}}, r0, [[OLD1]] 785; CHECK-ARM-LE: sbcs {{[^,]+}}, r1, [[OLD2]] 786; CHECK-ARM-BE: subs {{[^,]+}}, r1, [[OLD2]] 787; CHECK-ARM-BE: sbcs {{[^,]+}}, r0, [[OLD1]] 788; CHECK-ARM: mov [[CMP:r[0-9]+|lr]], #0 789; CHECK-ARM: movwlt [[CMP:r[0-9]+|lr]], #1 790; CHECK-ARM: cmp [[CMP:r[0-9]+|lr]], #0 791; CHECK-ARM: movne [[MINHI]], [[OLD2]] 792; CHECK-ARM: mov [[MINLO:r[0-9]+]], r0 793; CHECK-ARM: movne [[MINLO]], [[OLD1]] 794; CHECK-ARM: strexd [[STATUS:r[0-9]+]], [[MINLO]], [[MINHI]], [r[[ADDR]]] 795; CHECK-THUMB: strexd [[STATUS:r[0-9]+]], {{r[0-9]+}}, {{r[0-9]+}}, [r[[ADDR]]] 796; CHECK-NEXT: cmp [[STATUS]], #0 797; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 798; CHECK-NOT: dmb 799; CHECK-NOT: mcr 800 801; CHECK-ARM: strd [[OLD1]], [[OLD2]], [r[[ADDR]]] 802 store i64 %old, i64* @var64 803 ret void 804} 805 806define i8 @test_atomic_load_umin_i8(i8 zeroext %offset) nounwind { 807; CHECK-LABEL: test_atomic_load_umin_i8: 808 %old = atomicrmw umin i8* @var8, i8 %offset monotonic 809; CHECK-NOT: dmb 810; CHECK-NOT: mcr 811; CHECK: movw [[ADDR:r[0-9]+|lr]], :lower16:var8 812; CHECK: movt [[ADDR]], :upper16:var8 813 814; CHECK: .LBB{{[0-9]+}}_1: 815; CHECK: ldrexb r[[OLD:[0-9]+]], {{.*}}[[ADDR]] 816 ; r0 below is a reasonable guess but could change: it certainly comes into the 817 ; function there. 818; CHECK-NEXT: mov r[[NEW:[0-9]+]], r0 819; CHECK-NEXT: cmp r[[OLD]], r0 820; Thumb mode: it ls 821; CHECK: movls r[[NEW]], r[[OLD]] 822; CHECK-NEXT: strexb [[STATUS:r[0-9]+]], r[[NEW]], {{.*}}[[ADDR]] 823; CHECK-NEXT: cmp [[STATUS]], #0 824; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 825; CHECK-NOT: dmb 826; CHECK-NOT: mcr 827 828; CHECK: mov r0, r[[OLD]] 829 ret i8 %old 830} 831 832define i16 @test_atomic_load_umin_i16(i16 zeroext %offset) nounwind { 833; CHECK-LABEL: test_atomic_load_umin_i16: 834 %old = atomicrmw umin i16* @var16, i16 %offset acquire 835; CHECK-NOT: dmb 836; CHECK-NOT: mcr 837; CHECK: movw [[ADDR:r[0-9]+|lr]], :lower16:var16 838; CHECK: movt [[ADDR]], :upper16:var16 839 840; CHECK: .LBB{{[0-9]+}}_1: 841; CHECK: ldaexh r[[OLD:[0-9]+]], {{.*}}[[ADDR]] 842 ; r0 below is a reasonable guess but could change: it certainly comes into the 843 ; function there. 844; CHECK-NEXT: mov r[[NEW:[0-9]+]], r0 845; CHECK-NEXT: cmp r[[OLD]], r0 846; Thumb mode: it ls 847; CHECK: movls r[[NEW]], r[[OLD]] 848; CHECK-NEXT: strexh [[STATUS:r[0-9]+]], r[[NEW]], {{.*}}[[ADDR]] 849; CHECK-NEXT: cmp [[STATUS]], #0 850; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 851; CHECK-NOT: dmb 852; CHECK-NOT: mcr 853 854; CHECK: mov r0, r[[OLD]] 855 ret i16 %old 856} 857 858define i32 @test_atomic_load_umin_i32(i32 %offset) nounwind { 859; CHECK-LABEL: test_atomic_load_umin_i32: 860 %old = atomicrmw umin i32* @var32, i32 %offset seq_cst 861; CHECK-NOT: dmb 862; CHECK-NOT: mcr 863; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var32 864; CHECK: movt r[[ADDR]], :upper16:var32 865 866; CHECK: .LBB{{[0-9]+}}_1: 867; CHECK: ldaex r[[OLD:[0-9]+]], [r[[ADDR]]] 868 ; r0 below is a reasonable guess but could change: it certainly comes into the 869 ; function there. 870; CHECK-NEXT: mov r[[NEW:[0-9]+]], r0 871; CHECK-NEXT: cmp r[[OLD]], r0 872; Thumb mode: it ls 873; CHECK: movls r[[NEW]], r[[OLD]] 874; CHECK-NEXT: stlex [[STATUS:r[0-9]+]], r[[NEW]], [r[[ADDR]]] 875; CHECK-NEXT: cmp [[STATUS]], #0 876; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 877; CHECK-NOT: dmb 878; CHECK-NOT: mcr 879 880; CHECK: mov r0, r[[OLD]] 881 ret i32 %old 882} 883 884define void @test_atomic_load_umin_i64(i64 %offset) nounwind { 885; CHECK-LABEL: test_atomic_load_umin_i64: 886 %old = atomicrmw umin i64* @var64, i64 %offset seq_cst 887; CHECK-NOT: dmb 888; CHECK-NOT: mcr 889; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64 890; CHECK: movt r[[ADDR]], :upper16:var64 891 892; CHECK: .LBB{{[0-9]+}}_1: 893; CHECK: ldaexd [[OLD1:r[0-9]+|lr]], [[OLD2:r[0-9]+|lr]], [r[[ADDR]]] 894 ; r0, r1 below is a reasonable guess but could change: it certainly comes into the 895 ; function there. 896; CHECK-ARM: mov [[MINHI:r[0-9]+]], r1 897; CHECK-ARM-LE: subs {{[^,]+}}, r0, [[OLD1]] 898; CHECK-ARM-LE: sbcs {{[^,]+}}, r1, [[OLD2]] 899; CHECK-ARM-BE: subs {{[^,]+}}, r1, [[OLD2]] 900; CHECK-ARM-BE: sbcs {{[^,]+}}, r0, [[OLD1]] 901; CHECK-ARM: mov [[CMP:r[0-9]+|lr]], #0 902; CHECK-ARM: movwhs [[CMP:r[0-9]+|lr]], #1 903; CHECK-ARM: cmp [[CMP:r[0-9]+|lr]], #0 904; CHECK-ARM: movne [[MINHI]], [[OLD2]] 905; CHECK-ARM: mov [[MINLO:r[0-9]+]], r0 906; CHECK-ARM: movne [[MINLO]], [[OLD1]] 907; CHECK-ARM: stlexd [[STATUS:r[0-9]+]], [[MINLO]], [[MINHI]], [r[[ADDR]]] 908; CHECK-THUMB: stlexd [[STATUS:r[0-9]+]], {{r[0-9]+}}, {{r[0-9]+}}, [r[[ADDR]]] 909; CHECK-NEXT: cmp [[STATUS]], #0 910; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 911; CHECK-NOT: dmb 912; CHECK-NOT: mcr 913 914; CHECK-ARM: strd [[OLD1]], [[OLD2]], [r[[ADDR]]] 915 store i64 %old, i64* @var64 916 ret void 917} 918 919define i8 @test_atomic_load_umax_i8(i8 zeroext %offset) nounwind { 920; CHECK-LABEL: test_atomic_load_umax_i8: 921 %old = atomicrmw umax i8* @var8, i8 %offset acq_rel 922; CHECK-NOT: dmb 923; CHECK-NOT: mcr 924; CHECK: movw [[ADDR:r[0-9]+|lr]], :lower16:var8 925; CHECK: movt [[ADDR]], :upper16:var8 926 927; CHECK: .LBB{{[0-9]+}}_1: 928; CHECK: ldaexb r[[OLD:[0-9]+]], {{.*}}[[ADDR]] 929 ; r0 below is a reasonable guess but could change: it certainly comes into the 930 ; function there. 931; CHECK-NEXT: mov r[[NEW:[0-9]+]], r0 932; CHECK-NEXT: cmp r[[OLD]], r0 933; Thumb mode: it hi 934; CHECK: movhi r[[NEW]], r[[OLD]] 935; CHECK-NEXT: stlexb [[STATUS:r[0-9]+]], r[[NEW]], {{.*}}[[ADDR]] 936; CHECK-NEXT: cmp [[STATUS]], #0 937; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 938; CHECK-NOT: dmb 939; CHECK-NOT: mcr 940 941; CHECK: mov r0, r[[OLD]] 942 ret i8 %old 943} 944 945define i16 @test_atomic_load_umax_i16(i16 zeroext %offset) nounwind { 946; CHECK-LABEL: test_atomic_load_umax_i16: 947 %old = atomicrmw umax i16* @var16, i16 %offset monotonic 948; CHECK-NOT: dmb 949; CHECK-NOT: mcr 950; CHECK: movw [[ADDR:r[0-9]+|lr]], :lower16:var16 951; CHECK: movt [[ADDR]], :upper16:var16 952 953; CHECK: .LBB{{[0-9]+}}_1: 954; CHECK: ldrexh r[[OLD:[0-9]+]], {{.*}}[[ADDR]] 955 ; r0 below is a reasonable guess but could change: it certainly comes into the 956 ; function there. 957; CHECK-NEXT: mov r[[NEW:[0-9]+]], r0 958; CHECK-NEXT: cmp r[[OLD]], r0 959; Thumb mode: it hi 960; CHECK: movhi r[[NEW]], r[[OLD]] 961; CHECK-NEXT: strexh [[STATUS:r[0-9]+]], r[[NEW]], {{.*}}[[ADDR]] 962; CHECK-NEXT: cmp [[STATUS]], #0 963; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 964; CHECK-NOT: dmb 965; CHECK-NOT: mcr 966 967; CHECK: mov r0, r[[OLD]] 968 ret i16 %old 969} 970 971define i32 @test_atomic_load_umax_i32(i32 %offset) nounwind { 972; CHECK-LABEL: test_atomic_load_umax_i32: 973 %old = atomicrmw umax i32* @var32, i32 %offset seq_cst 974; CHECK-NOT: dmb 975; CHECK-NOT: mcr 976; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var32 977; CHECK: movt r[[ADDR]], :upper16:var32 978 979; CHECK: .LBB{{[0-9]+}}_1: 980; CHECK: ldaex r[[OLD:[0-9]+]], [r[[ADDR]]] 981 ; r0 below is a reasonable guess but could change: it certainly comes into the 982 ; function there. 983; CHECK-NEXT: mov r[[NEW:[0-9]+]], r0 984; CHECK-NEXT: cmp r[[OLD]], r0 985; Thumb mode: it hi 986; CHECK: movhi r[[NEW]], r[[OLD]] 987; CHECK-NEXT: stlex [[STATUS:r[0-9]+]], r[[NEW]], [r[[ADDR]]] 988; CHECK-NEXT: cmp [[STATUS]], #0 989; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 990; CHECK-NOT: dmb 991; CHECK-NOT: mcr 992 993; CHECK: mov r0, r[[OLD]] 994 ret i32 %old 995} 996 997define void @test_atomic_load_umax_i64(i64 %offset) nounwind { 998; CHECK-LABEL: test_atomic_load_umax_i64: 999 %old = atomicrmw umax i64* @var64, i64 %offset seq_cst 1000; CHECK-NOT: dmb 1001; CHECK-NOT: mcr 1002; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64 1003; CHECK: movt r[[ADDR]], :upper16:var64 1004 1005; CHECK: .LBB{{[0-9]+}}_1: 1006; CHECK: ldaexd [[OLD1:r[0-9]+|lr]], [[OLD2:r[0-9]+|lr]], [r[[ADDR]]] 1007 ; r0, r1 below is a reasonable guess but could change: it certainly comes into the 1008 ; function there. 1009; CHECK-ARM: mov [[MINHI:r[0-9]+]], r1 1010; CHECK-ARM-LE: subs {{[^,]+}}, r0, [[OLD1]] 1011; CHECK-ARM-LE: sbcs {{[^,]+}}, r1, [[OLD2]] 1012; CHECK-ARM-BE: subs {{[^,]+}}, r1, [[OLD2]] 1013; CHECK-ARM-BE: sbcs {{[^,]+}}, r0, [[OLD1]] 1014; CHECK-ARM: mov [[CMP:r[0-9]+|lr]], #0 1015; CHECK-ARM: movwlo [[CMP:r[0-9]+|lr]], #1 1016; CHECK-ARM: cmp [[CMP:r[0-9]+|lr]], #0 1017; CHECK-ARM: movne [[MINHI]], [[OLD2]] 1018; CHECK-ARM: mov [[MINLO:r[0-9]+]], r0 1019; CHECK-ARM: movne [[MINLO]], [[OLD1]] 1020; CHECK-ARM: stlexd [[STATUS:r[0-9]+]], [[MINLO]], [[MINHI]], [r[[ADDR]]] 1021; CHECK-THUMB: stlexd [[STATUS:r[0-9]+]], {{r[0-9]+}}, {{r[0-9]+}}, [r[[ADDR]]] 1022; CHECK-NEXT: cmp [[STATUS]], #0 1023; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 1024; CHECK-NOT: dmb 1025; CHECK-NOT: mcr 1026 1027; CHECK-ARM: strd [[OLD1]], [[OLD2]], [r[[ADDR]]] 1028 store i64 %old, i64* @var64 1029 ret void 1030} 1031 1032define i8 @test_atomic_cmpxchg_i8(i8 zeroext %wanted, i8 zeroext %new) nounwind { 1033; CHECK-LABEL: test_atomic_cmpxchg_i8: 1034 %pair = cmpxchg i8* @var8, i8 %wanted, i8 %new acquire acquire 1035 %old = extractvalue { i8, i1 } %pair, 0 1036; CHECK-NOT: dmb 1037; CHECK-NOT: mcr 1038; CHECK-DAG: movw r[[ADDR:[0-9]+]], :lower16:var8 1039; CHECK-DAG: movt r[[ADDR]], :upper16:var8 1040; CHECK-THUMB-DAG: mov r[[WANTED:[0-9]+]], r0 1041 1042; CHECK: .LBB{{[0-9]+}}_1: 1043; CHECK: ldaexb r[[OLD:[0-9]+]], [r[[ADDR]]] 1044 ; r0 below is a reasonable guess but could change: it certainly comes into the 1045 ; function there. 1046; CHECK-ARM-NEXT: cmp r[[OLD]], r0 1047; CHECK-THUMB-NEXT: cmp r[[OLD]], r[[WANTED]] 1048; CHECK-NEXT: bne .LBB{{[0-9]+}}_3 1049; CHECK-NEXT: BB#2: 1050 ; As above, r1 is a reasonable guess. 1051; CHECK: strexb [[STATUS:r[0-9]+]], r1, [r[[ADDR]]] 1052; CHECK-NEXT: cmp [[STATUS]], #0 1053; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 1054; CHECK-NEXT: b .LBB{{[0-9]+}}_4 1055; CHECK-NEXT: .LBB{{[0-9]+}}_3: 1056; CHECK-NEXT: clrex 1057; CHECK-NEXT: .LBB{{[0-9]+}}_4: 1058; CHECK-NOT: dmb 1059; CHECK-NOT: mcr 1060 1061; CHECK-ARM: mov r0, r[[OLD]] 1062 ret i8 %old 1063} 1064 1065define i16 @test_atomic_cmpxchg_i16(i16 zeroext %wanted, i16 zeroext %new) nounwind { 1066; CHECK-LABEL: test_atomic_cmpxchg_i16: 1067 %pair = cmpxchg i16* @var16, i16 %wanted, i16 %new seq_cst seq_cst 1068 %old = extractvalue { i16, i1 } %pair, 0 1069; CHECK-NOT: dmb 1070; CHECK-NOT: mcr 1071; CHECK-DAG: movw r[[ADDR:[0-9]+]], :lower16:var16 1072; CHECK-DAG: movt r[[ADDR]], :upper16:var16 1073; CHECK-THUMB-DAG: mov r[[WANTED:[0-9]+]], r0 1074 1075; CHECK: .LBB{{[0-9]+}}_1: 1076; CHECK: ldaexh r[[OLD:[0-9]+]], [r[[ADDR]]] 1077 ; r0 below is a reasonable guess but could change: it certainly comes into the 1078 ; function there. 1079; CHECK-ARM-NEXT: cmp r[[OLD]], r0 1080; CHECK-THUMB-NEXT: cmp r[[OLD]], r[[WANTED]] 1081; CHECK-NEXT: bne .LBB{{[0-9]+}}_3 1082; CHECK-NEXT: BB#2: 1083 ; As above, r1 is a reasonable guess. 1084; CHECK: stlexh [[STATUS:r[0-9]+]], r1, [r[[ADDR]]] 1085; CHECK-NEXT: cmp [[STATUS]], #0 1086; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 1087; CHECK-NEXT: b .LBB{{[0-9]+}}_4 1088; CHECK-NEXT: .LBB{{[0-9]+}}_3: 1089; CHECK-NEXT: clrex 1090; CHECK-NEXT: .LBB{{[0-9]+}}_4: 1091; CHECK-NOT: dmb 1092; CHECK-NOT: mcr 1093 1094; CHECK-ARM: mov r0, r[[OLD]] 1095 ret i16 %old 1096} 1097 1098define void @test_atomic_cmpxchg_i32(i32 %wanted, i32 %new) nounwind { 1099; CHECK-LABEL: test_atomic_cmpxchg_i32: 1100 %pair = cmpxchg i32* @var32, i32 %wanted, i32 %new release monotonic 1101 %old = extractvalue { i32, i1 } %pair, 0 1102 store i32 %old, i32* @var32 1103; CHECK-NOT: dmb 1104; CHECK-NOT: mcr 1105; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var32 1106; CHECK: movt r[[ADDR]], :upper16:var32 1107 1108; CHECK: .LBB{{[0-9]+}}_1: 1109; CHECK: ldrex r[[OLD:[0-9]+]], [r[[ADDR]]] 1110 ; r0 below is a reasonable guess but could change: it certainly comes into the 1111 ; function there. 1112; CHECK-NEXT: cmp r[[OLD]], r0 1113; CHECK-NEXT: bne .LBB{{[0-9]+}}_3 1114; CHECK-NEXT: BB#2: 1115 ; As above, r1 is a reasonable guess. 1116; CHECK: stlex [[STATUS:r[0-9]+]], r1, [r[[ADDR]]] 1117; CHECK-NEXT: cmp [[STATUS]], #0 1118; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 1119; CHECK-NEXT: b .LBB{{[0-9]+}}_4 1120; CHECK-NEXT: .LBB{{[0-9]+}}_3: 1121; CHECK-NEXT: clrex 1122; CHECK-NEXT: .LBB{{[0-9]+}}_4: 1123; CHECK-NOT: dmb 1124; CHECK-NOT: mcr 1125 1126; CHECK: str{{(.w)?}} r[[OLD]], 1127 ret void 1128} 1129 1130define void @test_atomic_cmpxchg_i64(i64 %wanted, i64 %new) nounwind { 1131; CHECK-LABEL: test_atomic_cmpxchg_i64: 1132 %pair = cmpxchg i64* @var64, i64 %wanted, i64 %new monotonic monotonic 1133 %old = extractvalue { i64, i1 } %pair, 0 1134; CHECK-NOT: dmb 1135; CHECK-NOT: mcr 1136; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64 1137; CHECK: movt r[[ADDR]], :upper16:var64 1138 1139; CHECK: .LBB{{[0-9]+}}_1: 1140; CHECK: ldrexd [[OLD1:r[0-9]+|lr]], [[OLD2:r[0-9]+|lr]], [r[[ADDR]]] 1141 ; r0, r1 below is a reasonable guess but could change: it certainly comes into the 1142 ; function there. 1143; CHECK-LE-DAG: eor{{(\.w)?}} [[MISMATCH_LO:r[0-9]+|lr]], [[OLD1]], r0 1144; CHECK-LE-DAG: eor{{(\.w)?}} [[MISMATCH_HI:r[0-9]+|lr]], [[OLD2]], r1 1145; CHECK-ARM-LE: orrs{{(\.w)?}} {{r[0-9]+}}, [[MISMATCH_LO]], [[MISMATCH_HI]] 1146; CHECK-THUMB-LE: orrs{{(\.w)?}} {{(r[0-9]+, )?}}[[MISMATCH_HI]], [[MISMATCH_LO]] 1147; CHECK-BE-DAG: eor{{(\.w)?}} [[MISMATCH_HI:r[0-9]+|lr]], [[OLD2]], r1 1148; CHECK-BE-DAG: eor{{(\.w)?}} [[MISMATCH_LO:r[0-9]+|lr]], [[OLD1]], r0 1149; CHECK-ARM-BE: orrs{{(\.w)?}} {{r[0-9]+}}, [[MISMATCH_HI]], [[MISMATCH_LO]] 1150; CHECK-THUMB-BE: orrs{{(\.w)?}} {{(r[0-9]+, )?}}[[MISMATCH_LO]], [[MISMATCH_HI]] 1151; CHECK-NEXT: bne .LBB{{[0-9]+}}_3 1152; CHECK-NEXT: BB#2: 1153 ; As above, r2, r3 is a reasonable guess. 1154; CHECK: strexd [[STATUS:r[0-9]+]], r2, r3, [r[[ADDR]]] 1155; CHECK-NEXT: cmp [[STATUS]], #0 1156; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 1157; CHECK-NEXT: b .LBB{{[0-9]+}}_4 1158; CHECK-NEXT: .LBB{{[0-9]+}}_3: 1159; CHECK-NEXT: clrex 1160; CHECK-NEXT: .LBB{{[0-9]+}}_4: 1161; CHECK-NOT: dmb 1162; CHECK-NOT: mcr 1163 1164; CHECK-ARM: strd [[OLD1]], [[OLD2]], [r[[ADDR]]] 1165 store i64 %old, i64* @var64 1166 ret void 1167} 1168 1169define i8 @test_atomic_load_monotonic_i8() nounwind { 1170; CHECK-LABEL: test_atomic_load_monotonic_i8: 1171 %val = load atomic i8, i8* @var8 monotonic, align 1 1172; CHECK-NOT: dmb 1173; CHECK-NOT: mcr 1174; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8 1175; CHECK: movt r[[ADDR]], :upper16:var8 1176; CHECK: ldrb r0, [r[[ADDR]]] 1177; CHECK-NOT: dmb 1178; CHECK-NOT: mcr 1179 1180 ret i8 %val 1181} 1182 1183define i8 @test_atomic_load_monotonic_regoff_i8(i64 %base, i64 %off) nounwind { 1184; CHECK-LABEL: test_atomic_load_monotonic_regoff_i8: 1185 %addr_int = add i64 %base, %off 1186 %addr = inttoptr i64 %addr_int to i8* 1187 1188 %val = load atomic i8, i8* %addr monotonic, align 1 1189; CHECK-NOT: dmb 1190; CHECK-NOT: mcr 1191; CHECK-LE: ldrb r0, [r0, r2] 1192; CHECK-BE: ldrb r0, [r1, r3] 1193; CHECK-NOT: dmb 1194; CHECK-NOT: mcr 1195 1196 ret i8 %val 1197} 1198 1199define i8 @test_atomic_load_acquire_i8() nounwind { 1200; CHECK-LABEL: test_atomic_load_acquire_i8: 1201 %val = load atomic i8, i8* @var8 acquire, align 1 1202; CHECK-NOT: dmb 1203; CHECK-NOT: mcr 1204; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8 1205; CHECK-NOT: dmb 1206; CHECK-NOT: mcr 1207; CHECK: movt r[[ADDR]], :upper16:var8 1208; CHECK-NOT: dmb 1209; CHECK-NOT: mcr 1210; CHECK: ldab r0, [r[[ADDR]]] 1211; CHECK-NOT: dmb 1212; CHECK-NOT: mcr 1213 ret i8 %val 1214} 1215 1216define i8 @test_atomic_load_seq_cst_i8() nounwind { 1217; CHECK-LABEL: test_atomic_load_seq_cst_i8: 1218 %val = load atomic i8, i8* @var8 seq_cst, align 1 1219; CHECK-NOT: dmb 1220; CHECK-NOT: mcr 1221; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8 1222; CHECK-NOT: dmb 1223; CHECK-NOT: mcr 1224; CHECK: movt r[[ADDR]], :upper16:var8 1225; CHECK-NOT: dmb 1226; CHECK-NOT: mcr 1227; CHECK: ldab r0, [r[[ADDR]]] 1228; CHECK-NOT: dmb 1229; CHECK-NOT: mcr 1230 ret i8 %val 1231} 1232 1233define i16 @test_atomic_load_monotonic_i16() nounwind { 1234; CHECK-LABEL: test_atomic_load_monotonic_i16: 1235 %val = load atomic i16, i16* @var16 monotonic, align 2 1236; CHECK-NOT: dmb 1237; CHECK-NOT: mcr 1238; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var16 1239; CHECK-NOT: dmb 1240; CHECK-NOT: mcr 1241; CHECK: movt r[[ADDR]], :upper16:var16 1242; CHECK-NOT: dmb 1243; CHECK-NOT: mcr 1244; CHECK: ldrh r0, [r[[ADDR]]] 1245; CHECK-NOT: dmb 1246; CHECK-NOT: mcr 1247 1248 ret i16 %val 1249} 1250 1251define i32 @test_atomic_load_monotonic_regoff_i32(i64 %base, i64 %off) nounwind { 1252; CHECK-LABEL: test_atomic_load_monotonic_regoff_i32: 1253 %addr_int = add i64 %base, %off 1254 %addr = inttoptr i64 %addr_int to i32* 1255 1256 %val = load atomic i32, i32* %addr monotonic, align 4 1257; CHECK-NOT: dmb 1258; CHECK-NOT: mcr 1259; CHECK-LE: ldr r0, [r0, r2] 1260; CHECK-BE: ldr r0, [r1, r3] 1261; CHECK-NOT: dmb 1262; CHECK-NOT: mcr 1263 1264 ret i32 %val 1265} 1266 1267define i64 @test_atomic_load_seq_cst_i64() nounwind { 1268; CHECK-LABEL: test_atomic_load_seq_cst_i64: 1269 %val = load atomic i64, i64* @var64 seq_cst, align 8 1270; CHECK-NOT: dmb 1271; CHECK-NOT: mcr 1272; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var64 1273; CHECK-NOT: dmb 1274; CHECK-NOT: mcr 1275; CHECK: movt r[[ADDR]], :upper16:var64 1276; CHECK-NOT: dmb 1277; CHECK-NOT: mcr 1278; CHECK: ldaexd r0, r1, [r[[ADDR]]] 1279; CHECK-NOT: dmb 1280; CHECK-NOT: mcr 1281 ret i64 %val 1282} 1283 1284define void @test_atomic_store_monotonic_i8(i8 %val) nounwind { 1285; CHECK-LABEL: test_atomic_store_monotonic_i8: 1286 store atomic i8 %val, i8* @var8 monotonic, align 1 1287; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8 1288; CHECK: movt r[[ADDR]], :upper16:var8 1289; CHECK: strb r0, [r[[ADDR]]] 1290 1291 ret void 1292} 1293 1294define void @test_atomic_store_monotonic_regoff_i8(i64 %base, i64 %off, i8 %val) nounwind { 1295; CHECK-LABEL: test_atomic_store_monotonic_regoff_i8: 1296 1297 %addr_int = add i64 %base, %off 1298 %addr = inttoptr i64 %addr_int to i8* 1299 1300 store atomic i8 %val, i8* %addr monotonic, align 1 1301; CHECK-LE: ldr{{b?(\.w)?}} [[VAL:r[0-9]+]], [sp] 1302; CHECK-LE: strb [[VAL]], [r0, r2] 1303; CHECK-BE: ldrb{{(\.w)?}} [[VAL:r[0-9]+]], [sp, #3] 1304; CHECK-BE: strb [[VAL]], [r1, r3] 1305 1306 ret void 1307} 1308 1309define void @test_atomic_store_release_i8(i8 %val) nounwind { 1310; CHECK-LABEL: test_atomic_store_release_i8: 1311 store atomic i8 %val, i8* @var8 release, align 1 1312; CHECK-NOT: dmb 1313; CHECK-NOT: mcr 1314; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8 1315; CHECK-NOT: dmb 1316; CHECK-NOT: mcr 1317; CHECK: movt r[[ADDR]], :upper16:var8 1318; CHECK-NOT: dmb 1319; CHECK-NOT: mcr 1320; CHECK: stlb r0, [r[[ADDR]]] 1321; CHECK-NOT: dmb 1322; CHECK-NOT: mcr 1323 ret void 1324} 1325 1326define void @test_atomic_store_seq_cst_i8(i8 %val) nounwind { 1327; CHECK-LABEL: test_atomic_store_seq_cst_i8: 1328 store atomic i8 %val, i8* @var8 seq_cst, align 1 1329; CHECK-NOT: dmb 1330; CHECK-NOT: mcr 1331; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var8 1332; CHECK-NOT: dmb 1333; CHECK-NOT: mcr 1334; CHECK: movt r[[ADDR]], :upper16:var8 1335; CHECK-NOT: dmb 1336; CHECK-NOT: mcr 1337; CHECK: stlb r0, [r[[ADDR]]] 1338; CHECK-NOT: dmb 1339; CHECK-NOT: mcr 1340 ret void 1341} 1342 1343define void @test_atomic_store_monotonic_i16(i16 %val) nounwind { 1344; CHECK-LABEL: test_atomic_store_monotonic_i16: 1345 store atomic i16 %val, i16* @var16 monotonic, align 2 1346; CHECK-NOT: dmb 1347; CHECK-NOT: mcr 1348; CHECK: movw r[[ADDR:[0-9]+]], :lower16:var16 1349; CHECK-NOT: dmb 1350; CHECK-NOT: mcr 1351; CHECK: movt r[[ADDR]], :upper16:var16 1352; CHECK-NOT: dmb 1353; CHECK-NOT: mcr 1354; CHECK: strh r0, [r[[ADDR]]] 1355; CHECK-NOT: dmb 1356; CHECK-NOT: mcr 1357 ret void 1358} 1359 1360define void @test_atomic_store_monotonic_regoff_i32(i64 %base, i64 %off, i32 %val) nounwind { 1361; CHECK-LABEL: test_atomic_store_monotonic_regoff_i32: 1362 1363 %addr_int = add i64 %base, %off 1364 %addr = inttoptr i64 %addr_int to i32* 1365 1366 store atomic i32 %val, i32* %addr monotonic, align 4 1367; CHECK-NOT: dmb 1368; CHECK-NOT: mcr 1369; CHECK: ldr [[VAL:r[0-9]+]], [sp] 1370; CHECK-NOT: dmb 1371; CHECK-NOT: mcr 1372; CHECK-LE: str [[VAL]], [r0, r2] 1373; CHECK-BE: str [[VAL]], [r1, r3] 1374; CHECK-NOT: dmb 1375; CHECK-NOT: mcr 1376 1377 ret void 1378} 1379 1380define void @test_atomic_store_release_i64(i64 %val) nounwind { 1381; CHECK-LABEL: test_atomic_store_release_i64: 1382 store atomic i64 %val, i64* @var64 release, align 8 1383; CHECK-NOT: dmb 1384; CHECK-NOT: mcr 1385; CHECK: movw [[ADDR:r[0-9]+|lr]], :lower16:var64 1386; CHECK: movt [[ADDR]], :upper16:var64 1387 1388; CHECK: .LBB{{[0-9]+}}_1: 1389 ; r0, r1 below is a reasonable guess but could change: it certainly comes into the 1390 ; function there. 1391; CHECK: stlexd [[STATUS:r[0-9]+]], r0, r1, {{.*}}[[ADDR]] 1392; CHECK-NEXT: cmp [[STATUS]], #0 1393; CHECK-NEXT: bne .LBB{{[0-9]+}}_1 1394; CHECK-NOT: dmb 1395; CHECK-NOT: mcr 1396 1397 ret void 1398} 1399 1400define i32 @not.barriers(i32* %var, i1 %cond) { 1401; CHECK-LABEL: not.barriers: 1402 br i1 %cond, label %atomic_ver, label %simple_ver 1403simple_ver: 1404 %oldval = load i32, i32* %var 1405 %newval = add nsw i32 %oldval, -1 1406 store i32 %newval, i32* %var 1407 br label %somewhere 1408atomic_ver: 1409 fence seq_cst 1410 %val = atomicrmw add i32* %var, i32 -1 monotonic 1411 fence seq_cst 1412 br label %somewhere 1413; CHECK: dmb 1414; CHECK: ldrex 1415; CHECK: dmb 1416 ; The key point here is that the second dmb isn't immediately followed by the 1417 ; simple_ver basic block, which LLVM attempted to do when DMB had been marked 1418 ; with isBarrier. For now, look for something that looks like "somewhere". 1419; CHECK-NEXT: {{mov|bx}} 1420somewhere: 1421 %combined = phi i32 [ %val, %atomic_ver ], [ %newval, %simple_ver] 1422 ret i32 %combined 1423} 1424