blob: ee81cce17f97ce011b03bd1357777fcdf7288de8 [file] [log] [blame]
Jan Voungc820ddf2014-07-29 14:38:51 -07001; This tests the optimization of atomic cmpxchg w/ following cmp + branches.
2
Jim Stichnoth729dbd02015-02-25 14:48:43 -08003; RUN: %p2i -i %s --filetype=obj --disassemble --args -O2 \
Jan Voungdddc3062014-08-29 12:59:02 -07004; RUN: | FileCheck --check-prefix=O2 %s
Jim Stichnoth729dbd02015-02-25 14:48:43 -08005; RUN: %p2i -i %s --filetype=obj --disassemble --args -Om1 \
Jan Voungdddc3062014-08-29 12:59:02 -07006; RUN: | FileCheck --check-prefix=OM1 %s
Jan Voungc820ddf2014-07-29 14:38:51 -07007
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).
Jim Stichnothff9c7062014-09-18 04:50:49 -070015declare void @use_value(i32)
Jan Voungc820ddf2014-07-29 14:38:51 -070016
17define i32 @test_atomic_cmpxchg_loop(i32 %iptr, i32 %expected, i32 %desired) {
18entry:
19 br label %loop
20
21loop:
22 %expected_loop = phi i32 [ %expected, %entry ], [ %old, %loop ]
23 %succeeded_first_try = phi i32 [ 1, %entry ], [ 2, %loop ]
24 %ptr = inttoptr i32 %iptr to i32*
25 %old = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* %ptr, i32 %expected_loop,
26 i32 %desired, i32 6, i32 6)
27 %success = icmp eq i32 %expected_loop, %old
28 br i1 %success, label %done, label %loop
29
30done:
31 call void @use_value(i32 %old)
32 ret i32 %succeeded_first_try
33}
Jan Voungdddc3062014-08-29 12:59:02 -070034; O2-LABEL: test_atomic_cmpxchg_loop
Jan Vounga2703ae2015-02-19 11:27:44 -080035; O2: lock cmpxchg DWORD PTR [e{{[^a].}}],e{{[^a]}}
Jim Stichnoth336f6c42014-10-30 15:01:31 -070036; O2-NEXT: j{{e|ne}}
Jan Voungc820ddf2014-07-29 14:38:51 -070037; Make sure the call isn't accidentally deleted.
38; O2: call
39;
40; Check that the unopt version does have a cmp
Jan Voungdddc3062014-08-29 12:59:02 -070041; OM1-LABEL: test_atomic_cmpxchg_loop
Jan Vounga2703ae2015-02-19 11:27:44 -080042; OM1: lock cmpxchg DWORD PTR [e{{[^a].}}],e{{[^a]}}
Jan Voungc820ddf2014-07-29 14:38:51 -070043; OM1: cmp
Jim Stichnothf48b3202015-05-04 10:22:17 -070044; OM1: sete
Jan Voungc820ddf2014-07-29 14:38:51 -070045; OM1: call
46
47; Still works if the compare operands are flipped.
48define i32 @test_atomic_cmpxchg_loop2(i32 %iptr, i32 %expected, i32 %desired) {
49entry:
50 br label %loop
51
52loop:
53 %expected_loop = phi i32 [ %expected, %entry ], [ %old, %loop ]
54 %ptr = inttoptr i32 %iptr to i32*
55 %old = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* %ptr, i32 %expected_loop,
56 i32 %desired, i32 6, i32 6)
57 %success = icmp eq i32 %old, %expected_loop
58 br i1 %success, label %done, label %loop
59
60done:
61 ret i32 %old
62}
Jan Voungdddc3062014-08-29 12:59:02 -070063; O2-LABEL: test_atomic_cmpxchg_loop2
Jan Vounga2703ae2015-02-19 11:27:44 -080064; O2: lock cmpxchg DWORD PTR [e{{[^a].}}],e{{[^a]}}
Jan Voungc820ddf2014-07-29 14:38:51 -070065; O2-NOT: cmp
Jim Stichnothff9c7062014-09-18 04:50:49 -070066; O2: jne
Jan Voungc820ddf2014-07-29 14:38:51 -070067
68
69; Still works if the compare operands are constants.
70define i32 @test_atomic_cmpxchg_loop_const(i32 %iptr, i32 %desired) {
71entry:
72 br label %loop
73
74loop:
75 %succeeded_first_try = phi i32 [ 1, %entry ], [ 0, %loop ]
76 %ptr = inttoptr i32 %iptr to i32*
77 %old = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* %ptr, i32 0,
78 i32 %desired, i32 6, i32 6)
79 %success = icmp eq i32 %old, 0
80 br i1 %success, label %done, label %loop
81
82done:
83 ret i32 %succeeded_first_try
84}
Jan Voungdddc3062014-08-29 12:59:02 -070085; O2-LABEL: test_atomic_cmpxchg_loop_const
Jan Vounga2703ae2015-02-19 11:27:44 -080086; O2: lock cmpxchg DWORD PTR [e{{[^a].}}],e{{[^a]}}
Jim Stichnoth336f6c42014-10-30 15:01:31 -070087; O2-NEXT: j{{e|ne}}
Jan Voungc820ddf2014-07-29 14:38:51 -070088
89; This is a case where the flags cannot be reused (compare is for some
90; other condition).
91define i32 @test_atomic_cmpxchg_no_opt(i32 %iptr, i32 %expected, i32 %desired) {
92entry:
93 br label %loop
94
95loop:
96 %expected_loop = phi i32 [ %expected, %entry ], [ %old, %loop ]
97 %ptr = inttoptr i32 %iptr to i32*
98 %old = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* %ptr, i32 %expected_loop,
99 i32 %desired, i32 6, i32 6)
100 %success = icmp sgt i32 %old, %expected
101 br i1 %success, label %done, label %loop
102
103done:
104 ret i32 %old
105}
Jan Voungdddc3062014-08-29 12:59:02 -0700106; O2-LABEL: test_atomic_cmpxchg_no_opt
Jan Vounga2703ae2015-02-19 11:27:44 -0800107; O2: lock cmpxchg DWORD PTR [e{{[^a].}}],e{{[^a]}}
Jan Voungc820ddf2014-07-29 14:38:51 -0700108; O2: cmp
Jim Stichnothff9c7062014-09-18 04:50:49 -0700109; O2: jle
Jan Voungc820ddf2014-07-29 14:38:51 -0700110
111; Another case where the flags cannot be reused (the comparison result
112; is used somewhere else).
113define i32 @test_atomic_cmpxchg_no_opt2(i32 %iptr, i32 %expected, i32 %desired) {
114entry:
115 br label %loop
116
117loop:
118 %expected_loop = phi i32 [ %expected, %entry ], [ %old, %loop ]
119 %ptr = inttoptr i32 %iptr to i32*
120 %old = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* %ptr, i32 %expected_loop,
121 i32 %desired, i32 6, i32 6)
122 %success = icmp eq i32 %old, %expected
123 br i1 %success, label %done, label %loop
124
125done:
126 %r = zext i1 %success to i32
127 ret i32 %r
128}
Jan Voungdddc3062014-08-29 12:59:02 -0700129; O2-LABEL: test_atomic_cmpxchg_no_opt2
Jan Vounga2703ae2015-02-19 11:27:44 -0800130; O2: lock cmpxchg DWORD PTR [e{{[^a].}}],e{{[^a]}}
Jan Voungc820ddf2014-07-29 14:38:51 -0700131; O2: mov {{.*}}
132; O2: cmp
Jim Stichnothf48b3202015-05-04 10:22:17 -0700133; O2: sete