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 8 declare 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). 15 declare void @use_value(i32) 16 17 define internal i32 @test_atomic_cmpxchg_loop(i32 %iptr, i32 %expected, 18 i32 %desired) { 19 entry: 20 br label %loop 21 22 loop: 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 31 done: 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. 49 define internal i32 @test_atomic_cmpxchg_loop2(i32 %iptr, i32 %expected, 50 i32 %desired) { 51 entry: 52 br label %loop 53 54 loop: 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 62 done: 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. 72 define internal i32 @test_atomic_cmpxchg_loop_const(i32 %iptr, i32 %desired) { 73 entry: 74 br label %loop 75 76 loop: 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 84 done: 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). 93 define internal i32 @test_atomic_cmpxchg_no_opt(i32 %iptr, i32 %expected, 94 i32 %desired) { 95 entry: 96 br label %loop 97 98 loop: 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 106 done: 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). 116 define internal i32 @test_atomic_cmpxchg_no_opt2(i32 %iptr, i32 %expected, 117 i32 %desired) { 118 entry: 119 br label %loop 120 121 loop: 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 129 done: 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