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