xref: /llvm-project/llvm/test/CodeGen/ARM/overflow-intrinsic-optimizations.ll (revision dbc724f764deaac6c2a3fb9f7c9cfa557797e4da)
1; RUN: llc < %s -mtriple=arm-eabi -mcpu=generic | FileCheck %s
2
3define i32 @sadd(i32 %a, i32 %b) local_unnamed_addr #0 {
4; CHECK-LABEL: sadd:
5; CHECK:    adds r0, r0, r1
6; CHECK-NEXT:    movvc pc, lr
7entry:
8  %0 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %a, i32 %b)
9  %1 = extractvalue { i32, i1 } %0, 1
10  br i1 %1, label %trap, label %cont
11
12trap:
13  tail call void @llvm.trap() #2
14  unreachable
15
16cont:
17  %2 = extractvalue { i32, i1 } %0, 0
18  ret i32 %2
19
20}
21
22define i32 @uadd(i32 %a, i32 %b) local_unnamed_addr #0 {
23; CHECK-LABEL: uadd:
24; CHECK:    adds r0, r0, r1
25; CHECK-NEXT:    movlo pc, lr
26entry:
27  %0 = tail call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 %a, i32 %b)
28  %1 = extractvalue { i32, i1 } %0, 1
29  br i1 %1, label %trap, label %cont
30
31trap:
32  tail call void @llvm.trap() #2
33  unreachable
34
35cont:
36  %2 = extractvalue { i32, i1 } %0, 0
37  ret i32 %2
38
39}
40
41define i32 @ssub(i32 %a, i32 %b) local_unnamed_addr #0 {
42; CHECK-LABEL: ssub:
43; CHECK:    subs r0, r0, r1
44; CHECK-NEXT:    movvc pc, lr
45entry:
46  %0 = tail call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 %a, i32 %b)
47  %1 = extractvalue { i32, i1 } %0, 1
48  br i1 %1, label %trap, label %cont
49
50trap:
51  tail call void @llvm.trap() #2
52  unreachable
53
54cont:
55  %2 = extractvalue { i32, i1 } %0, 0
56  ret i32 %2
57
58}
59
60define i32 @usub(i32 %a, i32 %b) local_unnamed_addr #0 {
61; CHECK-LABEL: usub:
62; CHECK:    subs r0, r0, r1
63; CHECK-NEXT:    movhs pc, lr
64entry:
65  %0 = tail call { i32, i1 } @llvm.usub.with.overflow.i32(i32 %a, i32 %b)
66  %1 = extractvalue { i32, i1 } %0, 1
67  br i1 %1, label %trap, label %cont
68
69trap:
70  tail call void @llvm.trap() #2
71  unreachable
72
73cont:
74  %2 = extractvalue { i32, i1 } %0, 0
75  ret i32 %2
76
77}
78
79define i32 @smul(i32 %a, i32 %b) local_unnamed_addr #0 {
80; CHECK-LABEL: smul:
81; CHECK: smull r0, r[[RHI:[0-9]+]], {{r[0-9]+}}, {{r[0-9]+}}
82; CHECK-NEXT: cmp r[[RHI]], r0, asr #31
83; CHECK-NEXT: moveq pc, lr
84entry:
85  %0 = tail call { i32, i1 } @llvm.smul.with.overflow.i32(i32 %a, i32 %b)
86  %1 = extractvalue { i32, i1 } %0, 1
87  br i1 %1, label %trap, label %cont
88
89trap:
90  tail call void @llvm.trap() #2
91  unreachable
92
93cont:
94  %2 = extractvalue { i32, i1 } %0, 0
95  ret i32 %2
96}
97
98define i32 @umul(i32 %a, i32 %b) local_unnamed_addr #0 {
99; CHECK-LABEL: umul:
100; CHECK: umull r0, r[[RHI:[0-9]+]], {{r[0-9]+}}, {{r[0-9]+}}
101; CHECK-NEXT: cmp r[[RHI]], #0
102; CHECK-NEXT: moveq pc, lr
103entry:
104  %0 = tail call { i32, i1 } @llvm.umul.with.overflow.i32(i32 %a, i32 %b)
105  %1 = extractvalue { i32, i1 } %0, 1
106  br i1 %1, label %trap, label %cont
107
108trap:
109  tail call void @llvm.trap() #2
110  unreachable
111
112cont:
113  %2 = extractvalue { i32, i1 } %0, 0
114  ret i32 %2
115}
116
117define void @sum(i32* %a, i32* %b, i32 %n) local_unnamed_addr #0 {
118; CHECK-LABEL: sum:
119; CHECK:    ldr [[R0:r[0-9]+]],
120; CHECK-NEXT:    ldr [[R1:r[0-9]+|lr]],
121; CHECK-NEXT:    adds [[R2:r[0-9]+]], [[R1]], [[R0]]
122; CHECK-NEXT:    strvc [[R2]],
123; CHECK-NEXT:    addsvc
124; CHECK-NEXT:    bvs
125entry:
126  %cmp7 = icmp eq i32 %n, 0
127  br i1 %cmp7, label %for.cond.cleanup, label %for.body
128
129for.cond.cleanup:
130  ret void
131
132for.body:
133  %i.08 = phi i32 [ %7, %cont2 ], [ 0, %entry ]
134  %arrayidx = getelementptr inbounds i32, i32* %b, i32 %i.08
135  %0 = load i32, i32* %arrayidx, align 4
136  %arrayidx1 = getelementptr inbounds i32, i32* %a, i32 %i.08
137  %1 = load i32, i32* %arrayidx1, align 4
138  %2 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %1, i32 %0)
139  %3 = extractvalue { i32, i1 } %2, 1
140  br i1 %3, label %trap, label %cont
141
142trap:
143  tail call void @llvm.trap() #2
144  unreachable
145
146cont:
147  %4 = extractvalue { i32, i1 } %2, 0
148  store i32 %4, i32* %arrayidx1, align 4
149  %5 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %i.08, i32 1)
150  %6 = extractvalue { i32, i1 } %5, 1
151  br i1 %6, label %trap, label %cont2
152
153cont2:
154  %7 = extractvalue { i32, i1 } %5, 0
155  %cmp = icmp eq i32 %7, %n
156  br i1 %cmp, label %for.cond.cleanup, label %for.body
157
158}
159
160define void @extern_loop(i32 %n) local_unnamed_addr #0 {
161; Do not replace the compare around the clobbering call.
162; CHECK: add {{r[0-9]+}}, {{r[0-9]+}}, #1
163; CHECK-NEXT: bl external_fn
164; CHECK: cmp
165entry:
166  %0 = tail call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 %n, i32 1)
167  %1 = extractvalue { i32, i1 } %0, 1
168  br i1 %1, label %trap, label %cont.lr.ph
169
170cont.lr.ph:
171  %2 = extractvalue { i32, i1 } %0, 0
172  %cmp5 = icmp sgt i32 %2, 0
173  br i1 %cmp5, label %for.body.preheader, label %for.cond.cleanup
174
175for.body.preheader:
176  br label %for.body
177
178trap:
179  tail call void @llvm.trap() #2
180  unreachable
181
182for.cond.cleanup:
183  ret void
184
185for.body:
186  %i.046 = phi i32 [ %5, %cont1 ], [ 0, %for.body.preheader ]
187  tail call void bitcast (void (...)* @external_fn to void ()*)() #4
188  %3 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %i.046, i32 1)
189  %4 = extractvalue { i32, i1 } %3, 1
190  br i1 %4, label %trap, label %cont1
191
192cont1:
193  %5 = extractvalue { i32, i1 } %3, 0
194  %cmp = icmp slt i32 %5, %2
195  br i1 %cmp, label %for.body, label %for.cond.cleanup
196}
197
198declare void @external_fn(...) local_unnamed_addr #0
199
200define i32 @are_equal(i32* nocapture readonly %a1, i32* nocapture readonly %a2, i32 %n) local_unnamed_addr #0 {
201; CHECK-LABEL: are_equal
202; CHECK: subs r{{[0-9]+}}, r{{[0-9]+}}, #1
203; CHECK-NEXT: bne
204entry:
205  %tobool7 = icmp eq i32 %n, 0
206  br i1 %tobool7, label %while.end, label %land.rhs.preheader
207
208land.rhs.preheader:
209  br label %land.rhs
210
211while.cond:
212  %tobool = icmp eq i32 %dec9, 0
213  br i1 %tobool, label %while.end, label %land.rhs
214
215land.rhs:
216  %dec9.in = phi i32 [ %dec9, %while.cond ], [ %n, %land.rhs.preheader ]
217  %dec9 = add nsw i32 %dec9.in, -1
218  %arrayidx = getelementptr inbounds i32, i32* %a1, i32 %dec9
219  %0 = load i32, i32* %arrayidx, align 4
220  %arrayidx1 = getelementptr inbounds i32, i32* %a2, i32 %dec9
221  %1 = load i32, i32* %arrayidx1, align 4
222  %cmp = icmp eq i32 %0, %1
223  br i1 %cmp, label %while.cond, label %while.end
224
225while.end:
226  %n.addr.0.lcssa = phi i32 [ 0, %entry ], [ 0, %while.cond ], [ %dec9.in, %land.rhs ]
227  %cmp2 = icmp slt i32 %n.addr.0.lcssa, 1
228  %conv = zext i1 %cmp2 to i32
229  ret i32 %conv
230}
231
232declare void @llvm.trap() #2
233declare { i32, i1 } @llvm.sadd.with.overflow.i32(i32, i32) #1
234declare { i32, i1 } @llvm.uadd.with.overflow.i32(i32, i32) #1
235declare { i32, i1 } @llvm.ssub.with.overflow.i32(i32, i32) #1
236declare { i32, i1 } @llvm.usub.with.overflow.i32(i32, i32) #1
237declare { i32, i1 } @llvm.smul.with.overflow.i32(i32, i32) #1
238declare { i32, i1 } @llvm.umul.with.overflow.i32(i32, i32) #1
239