1; This tests the optimization of atomic cmpxchg w/ following cmp + branches. 2 3; RUN: %p2i -i %s --filetype=obj --disassemble --args -O2 \ 4; RUN: -allow-externally-defined-symbols | FileCheck --check-prefix=O2 %s 5; RUN: %p2i -i %s --filetype=obj --disassemble --args -Om1 \ 6; RUN: -allow-externally-defined-symbols | FileCheck --check-prefix=OM1 %s 7 8declare i32 @llvm.nacl.atomic.cmpxchg.i32(i32*, i32, i32, i32, i32) 9 10 11; Test that a cmpxchg followed by icmp eq and branch can be optimized to 12; reuse the flags set by the cmpxchg instruction itself. 13; This is only expected to work w/ O2, based on lightweight liveness. 14; (Or if we had other means to detect the only use). 15declare void @use_value(i32) 16 17define internal i32 @test_atomic_cmpxchg_loop(i32 %iptr, i32 %expected, 18 i32 %desired) { 19entry: 20 br label %loop 21 22loop: 23 %expected_loop = phi i32 [ %expected, %entry ], [ %old, %loop ] 24 %succeeded_first_try = phi i32 [ 1, %entry ], [ 2, %loop ] 25 %ptr = inttoptr i32 %iptr to i32* 26 %old = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* %ptr, i32 %expected_loop, 27 i32 %desired, i32 6, i32 6) 28 %success = icmp eq i32 %expected_loop, %old 29 br i1 %success, label %done, label %loop 30 31done: 32 call void @use_value(i32 %old) 33 ret i32 %succeeded_first_try 34} 35; O2-LABEL: test_atomic_cmpxchg_loop 36; O2: lock cmpxchg DWORD PTR [e{{[^a].}}],e{{[^a]}} 37; O2-NEXT: j{{e|ne}} 38; Make sure the call isn't accidentally deleted. 39; O2: call 40; 41; Check that the unopt version does have a cmp 42; OM1-LABEL: test_atomic_cmpxchg_loop 43; OM1: lock cmpxchg DWORD PTR [e{{[^a].}}],e{{[^a]}} 44; OM1: cmp 45; OM1: sete 46; OM1: call 47 48; Still works if the compare operands are flipped. 49define internal i32 @test_atomic_cmpxchg_loop2(i32 %iptr, i32 %expected, 50 i32 %desired) { 51entry: 52 br label %loop 53 54loop: 55 %expected_loop = phi i32 [ %expected, %entry ], [ %old, %loop ] 56 %ptr = inttoptr i32 %iptr to i32* 57 %old = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* %ptr, i32 %expected_loop, 58 i32 %desired, i32 6, i32 6) 59 %success = icmp eq i32 %old, %expected_loop 60 br i1 %success, label %done, label %loop 61 62done: 63 ret i32 %old 64} 65; O2-LABEL: test_atomic_cmpxchg_loop2 66; O2: lock cmpxchg DWORD PTR [e{{[^a].}}],e{{[^a]}} 67; O2-NOT: cmp 68; O2: jne 69 70 71; Still works if the compare operands are constants. 72define internal i32 @test_atomic_cmpxchg_loop_const(i32 %iptr, i32 %desired) { 73entry: 74 br label %loop 75 76loop: 77 %succeeded_first_try = phi i32 [ 1, %entry ], [ 0, %loop ] 78 %ptr = inttoptr i32 %iptr to i32* 79 %old = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* %ptr, i32 0, 80 i32 %desired, i32 6, i32 6) 81 %success = icmp eq i32 %old, 0 82 br i1 %success, label %done, label %loop 83 84done: 85 ret i32 %succeeded_first_try 86} 87; O2-LABEL: test_atomic_cmpxchg_loop_const 88; O2: lock cmpxchg DWORD PTR [e{{[^a].}}],e{{[^a]}} 89; O2-NEXT: j{{e|ne}} 90 91; This is a case where the flags cannot be reused (compare is for some 92; other condition). 93define internal i32 @test_atomic_cmpxchg_no_opt(i32 %iptr, i32 %expected, 94 i32 %desired) { 95entry: 96 br label %loop 97 98loop: 99 %expected_loop = phi i32 [ %expected, %entry ], [ %old, %loop ] 100 %ptr = inttoptr i32 %iptr to i32* 101 %old = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* %ptr, i32 %expected_loop, 102 i32 %desired, i32 6, i32 6) 103 %success = icmp sgt i32 %old, %expected 104 br i1 %success, label %done, label %loop 105 106done: 107 ret i32 %old 108} 109; O2-LABEL: test_atomic_cmpxchg_no_opt 110; O2: lock cmpxchg DWORD PTR [e{{[^a].}}],e{{[^a]}} 111; O2: cmp 112; O2: jle 113 114; Another case where the flags cannot be reused (the comparison result 115; is used somewhere else). 116define internal i32 @test_atomic_cmpxchg_no_opt2(i32 %iptr, i32 %expected, 117 i32 %desired) { 118entry: 119 br label %loop 120 121loop: 122 %expected_loop = phi i32 [ %expected, %entry ], [ %old, %loop ] 123 %ptr = inttoptr i32 %iptr to i32* 124 %old = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* %ptr, i32 %expected_loop, 125 i32 %desired, i32 6, i32 6) 126 %success = icmp eq i32 %old, %expected 127 br i1 %success, label %done, label %loop 128 129done: 130 %r = zext i1 %success to i32 131 ret i32 %r 132} 133; O2-LABEL: test_atomic_cmpxchg_no_opt2 134; O2: lock cmpxchg DWORD PTR [e{{[^a].}}],e{{[^a]}} 135; O2: cmp 136; O2: sete 137