OLD | NEW |
1 ; This tests the optimization of atomic cmpxchg w/ following cmp + branches. | 1 ; This tests the optimization of atomic cmpxchg w/ following cmp + branches. |
2 | 2 |
3 ; RUN: %llvm2ice -O2 --verbose none %s | FileCheck %s --check-prefix=O2 | |
4 ; RUN: %llvm2ice -Om1 --verbose none %s | FileCheck %s --check-prefix=OM1 | |
5 ; RUN: %llvm2ice -O2 --verbose none %s \ | 3 ; RUN: %llvm2ice -O2 --verbose none %s \ |
6 ; RUN: | llvm-mc -triple=i686-none-nacl -x86-asm-syntax=intel -filetype=obj | 4 ; RUN: | llvm-mc -triple=i686-none-nacl -x86-asm-syntax=intel -filetype=obj \ |
| 5 ; RUN: | llvm-objdump -d -symbolize -x86-asm-syntax=intel - \ |
| 6 ; RUN: | FileCheck --check-prefix=O2 %s |
7 ; RUN: %llvm2ice -Om1 --verbose none %s \ | 7 ; RUN: %llvm2ice -Om1 --verbose none %s \ |
8 ; RUN: | llvm-mc -triple=i686-none-nacl -x86-asm-syntax=intel -filetype=obj | 8 ; RUN: | llvm-mc -triple=i686-none-nacl -x86-asm-syntax=intel -filetype=obj \ |
| 9 ; RUN: | llvm-objdump -d -symbolize -x86-asm-syntax=intel - \ |
| 10 ; RUN: | FileCheck --check-prefix=OM1 %s |
9 ; RUN: %llvm2ice --verbose none %s | FileCheck --check-prefix=ERRORS %s | 11 ; RUN: %llvm2ice --verbose none %s | FileCheck --check-prefix=ERRORS %s |
10 ; RUN: %llvm2iceinsts %s | %szdiff %s | FileCheck --check-prefix=DUMP %s | 12 ; RUN: %llvm2iceinsts %s | %szdiff %s | FileCheck --check-prefix=DUMP %s |
11 ; RUN: %llvm2iceinsts --pnacl %s | %szdiff %s \ | 13 ; RUN: %llvm2iceinsts --pnacl %s | %szdiff %s \ |
12 ; RUN: | FileCheck --check-prefix=DUMP %s | 14 ; RUN: | FileCheck --check-prefix=DUMP %s |
13 | 15 |
14 declare i32 @llvm.nacl.atomic.cmpxchg.i32(i32*, i32, i32, i32, i32) | 16 declare i32 @llvm.nacl.atomic.cmpxchg.i32(i32*, i32, i32, i32, i32) |
15 | 17 |
16 | 18 |
17 ; Test that a cmpxchg followed by icmp eq and branch can be optimized to | 19 ; Test that a cmpxchg followed by icmp eq and branch can be optimized to |
18 ; reuse the flags set by the cmpxchg instruction itself. | 20 ; reuse the flags set by the cmpxchg instruction itself. |
(...skipping 11 matching lines...) Expand all Loading... |
30 %ptr = inttoptr i32 %iptr to i32* | 32 %ptr = inttoptr i32 %iptr to i32* |
31 %old = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* %ptr, i32 %expected_loop, | 33 %old = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* %ptr, i32 %expected_loop, |
32 i32 %desired, i32 6, i32 6) | 34 i32 %desired, i32 6, i32 6) |
33 %success = icmp eq i32 %expected_loop, %old | 35 %success = icmp eq i32 %expected_loop, %old |
34 br i1 %success, label %done, label %loop | 36 br i1 %success, label %done, label %loop |
35 | 37 |
36 done: | 38 done: |
37 call void @use_value(i32 %old) | 39 call void @use_value(i32 %old) |
38 ret i32 %succeeded_first_try | 40 ret i32 %succeeded_first_try |
39 } | 41 } |
40 ; O2-LABEL: .Ltest_atomic_cmpxchg_loop{{.*}}loop | 42 ; O2-LABEL: test_atomic_cmpxchg_loop |
41 ; O2: lock cmpxchg dword ptr [e{{[^a].}}], e{{[^a]}} | 43 ; O2: lock |
| 44 ; O2-NEXT: cmpxchg dword ptr [e{{[^a].}}], e{{[^a]}} |
42 ; O2-NOT: cmp | 45 ; O2-NOT: cmp |
43 ; Make sure the phi assignment for succeeded_first_try is still there. | 46 ; Make sure the phi assignment for succeeded_first_try is still there. |
44 ; O2: mov {{.*}}, 2 | 47 ; O2: mov {{.*}}, 2 |
45 ; O2-NOT: cmp | 48 ; O2-NOT: cmp |
46 ; O2: je | 49 ; O2: je |
47 ; O2-LABEL: .Ltest_atomic_cmpxchg_loop{{.*}}done | |
48 ; Make sure the call isn't accidentally deleted. | 50 ; Make sure the call isn't accidentally deleted. |
49 ; O2: call | 51 ; O2: call |
50 ; | 52 ; |
51 ; Check that the unopt version does have a cmp | 53 ; Check that the unopt version does have a cmp |
52 ; OM1-LABEL: .Ltest_atomic_cmpxchg_loop{{.*}}loop | 54 ; OM1-LABEL: test_atomic_cmpxchg_loop |
53 ; OM1: lock cmpxchg dword ptr [e{{[^a].}}], e{{[^a]}} | 55 ; OM1: lock |
| 56 ; OM1-NEXT: cmpxchg dword ptr [e{{[^a].}}], e{{[^a]}} |
54 ; OM1: cmp | 57 ; OM1: cmp |
55 ; OM1: je | 58 ; OM1: je |
56 ; OM1-LABEL: .Ltest_atomic_cmpxchg_loop{{.*}}done | |
57 ; OM1: call | 59 ; OM1: call |
58 | 60 |
59 ; Still works if the compare operands are flipped. | 61 ; Still works if the compare operands are flipped. |
60 define i32 @test_atomic_cmpxchg_loop2(i32 %iptr, i32 %expected, i32 %desired) { | 62 define i32 @test_atomic_cmpxchg_loop2(i32 %iptr, i32 %expected, i32 %desired) { |
61 entry: | 63 entry: |
62 br label %loop | 64 br label %loop |
63 | 65 |
64 loop: | 66 loop: |
65 %expected_loop = phi i32 [ %expected, %entry ], [ %old, %loop ] | 67 %expected_loop = phi i32 [ %expected, %entry ], [ %old, %loop ] |
66 %ptr = inttoptr i32 %iptr to i32* | 68 %ptr = inttoptr i32 %iptr to i32* |
67 %old = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* %ptr, i32 %expected_loop, | 69 %old = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* %ptr, i32 %expected_loop, |
68 i32 %desired, i32 6, i32 6) | 70 i32 %desired, i32 6, i32 6) |
69 %success = icmp eq i32 %old, %expected_loop | 71 %success = icmp eq i32 %old, %expected_loop |
70 br i1 %success, label %done, label %loop | 72 br i1 %success, label %done, label %loop |
71 | 73 |
72 done: | 74 done: |
73 ret i32 %old | 75 ret i32 %old |
74 } | 76 } |
75 ; O2-LABEL: .Ltest_atomic_cmpxchg_loop2{{.*}}loop | 77 ; O2-LABEL: test_atomic_cmpxchg_loop2 |
76 ; O2: lock cmpxchg dword ptr [e{{[^a].}}], e{{[^a]}} | 78 ; O2: lock |
| 79 ; O2-NEXT: cmpxchg dword ptr [e{{[^a].}}], e{{[^a]}} |
77 ; O2-NOT: cmp | 80 ; O2-NOT: cmp |
78 ; O2: je | 81 ; O2: je |
79 | 82 |
80 | 83 |
81 ; Still works if the compare operands are constants. | 84 ; Still works if the compare operands are constants. |
82 define i32 @test_atomic_cmpxchg_loop_const(i32 %iptr, i32 %desired) { | 85 define i32 @test_atomic_cmpxchg_loop_const(i32 %iptr, i32 %desired) { |
83 entry: | 86 entry: |
84 br label %loop | 87 br label %loop |
85 | 88 |
86 loop: | 89 loop: |
87 %succeeded_first_try = phi i32 [ 1, %entry ], [ 0, %loop ] | 90 %succeeded_first_try = phi i32 [ 1, %entry ], [ 0, %loop ] |
88 %ptr = inttoptr i32 %iptr to i32* | 91 %ptr = inttoptr i32 %iptr to i32* |
89 %old = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* %ptr, i32 0, | 92 %old = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* %ptr, i32 0, |
90 i32 %desired, i32 6, i32 6) | 93 i32 %desired, i32 6, i32 6) |
91 %success = icmp eq i32 %old, 0 | 94 %success = icmp eq i32 %old, 0 |
92 br i1 %success, label %done, label %loop | 95 br i1 %success, label %done, label %loop |
93 | 96 |
94 done: | 97 done: |
95 ret i32 %succeeded_first_try | 98 ret i32 %succeeded_first_try |
96 } | 99 } |
97 ; O2-LABEL: .Ltest_atomic_cmpxchg_loop_const{{.*}}loop | 100 ; O2-LABEL: test_atomic_cmpxchg_loop_const |
98 ; O2: lock cmpxchg dword ptr [e{{[^a].}}], e{{[^a]}} | 101 ; O2: lock |
| 102 ; Should be using NEXT: see issue 3929 |
| 103 ; O2: cmpxchg dword ptr [e{{[^a].}}], e{{[^a]}} |
99 ; O2-NOT: cmp | 104 ; O2-NOT: cmp |
100 ; O2: je | 105 ; O2: je |
101 | 106 |
102 ; This is a case where the flags cannot be reused (compare is for some | 107 ; This is a case where the flags cannot be reused (compare is for some |
103 ; other condition). | 108 ; other condition). |
104 define i32 @test_atomic_cmpxchg_no_opt(i32 %iptr, i32 %expected, i32 %desired) { | 109 define i32 @test_atomic_cmpxchg_no_opt(i32 %iptr, i32 %expected, i32 %desired) { |
105 entry: | 110 entry: |
106 br label %loop | 111 br label %loop |
107 | 112 |
108 loop: | 113 loop: |
109 %expected_loop = phi i32 [ %expected, %entry ], [ %old, %loop ] | 114 %expected_loop = phi i32 [ %expected, %entry ], [ %old, %loop ] |
110 %ptr = inttoptr i32 %iptr to i32* | 115 %ptr = inttoptr i32 %iptr to i32* |
111 %old = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* %ptr, i32 %expected_loop, | 116 %old = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* %ptr, i32 %expected_loop, |
112 i32 %desired, i32 6, i32 6) | 117 i32 %desired, i32 6, i32 6) |
113 %success = icmp sgt i32 %old, %expected | 118 %success = icmp sgt i32 %old, %expected |
114 br i1 %success, label %done, label %loop | 119 br i1 %success, label %done, label %loop |
115 | 120 |
116 done: | 121 done: |
117 ret i32 %old | 122 ret i32 %old |
118 } | 123 } |
119 ; O2-LABEL: .Ltest_atomic_cmpxchg_no_opt{{.*}}loop | 124 ; O2-LABEL: test_atomic_cmpxchg_no_opt |
120 ; O2: lock cmpxchg dword ptr [e{{[^a].}}], e{{[^a]}} | 125 ; O2: lock |
| 126 ; O2-NEXT: cmpxchg dword ptr [e{{[^a].}}], e{{[^a]}} |
121 ; O2: mov {{.*}} | 127 ; O2: mov {{.*}} |
122 ; O2: cmp | 128 ; O2: cmp |
123 ; O2: jg | 129 ; O2: jg |
124 | 130 |
125 ; Another case where the flags cannot be reused (the comparison result | 131 ; Another case where the flags cannot be reused (the comparison result |
126 ; is used somewhere else). | 132 ; is used somewhere else). |
127 define i32 @test_atomic_cmpxchg_no_opt2(i32 %iptr, i32 %expected, i32 %desired)
{ | 133 define i32 @test_atomic_cmpxchg_no_opt2(i32 %iptr, i32 %expected, i32 %desired)
{ |
128 entry: | 134 entry: |
129 br label %loop | 135 br label %loop |
130 | 136 |
131 loop: | 137 loop: |
132 %expected_loop = phi i32 [ %expected, %entry ], [ %old, %loop ] | 138 %expected_loop = phi i32 [ %expected, %entry ], [ %old, %loop ] |
133 %ptr = inttoptr i32 %iptr to i32* | 139 %ptr = inttoptr i32 %iptr to i32* |
134 %old = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* %ptr, i32 %expected_loop, | 140 %old = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* %ptr, i32 %expected_loop, |
135 i32 %desired, i32 6, i32 6) | 141 i32 %desired, i32 6, i32 6) |
136 %success = icmp eq i32 %old, %expected | 142 %success = icmp eq i32 %old, %expected |
137 br i1 %success, label %done, label %loop | 143 br i1 %success, label %done, label %loop |
138 | 144 |
139 done: | 145 done: |
140 %r = zext i1 %success to i32 | 146 %r = zext i1 %success to i32 |
141 ret i32 %r | 147 ret i32 %r |
142 } | 148 } |
143 ; O2-LABEL: .Ltest_atomic_cmpxchg_no_opt2{{.*}}loop | 149 ; O2-LABEL: test_atomic_cmpxchg_no_opt2 |
144 ; O2: lock cmpxchg dword ptr [e{{[^a].}}], e{{[^a]}} | 150 ; O2: lock |
| 151 ; O2-NEXT: cmpxchg dword ptr [e{{[^a].}}], e{{[^a]}} |
145 ; O2: mov {{.*}} | 152 ; O2: mov {{.*}} |
146 ; O2: cmp | 153 ; O2: cmp |
147 ; O2: je | 154 ; O2: je |
148 | 155 |
149 ; ERRORS-NOT: ICE translation error | 156 ; ERRORS-NOT: ICE translation error |
150 ; DUMP-NOT: SZ | 157 ; DUMP-NOT: SZ |
OLD | NEW |