• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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