[InstCombine] Signed saturation patterns
[llvm-core.git] / test / CodeGen / ARM / overflow-intrinsic-optimizations.ll
blob048a1205febea05ef2f2ce1700b9346121e6990b
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
4 define 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
8 entry:
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
13 trap:
14   tail call void @llvm.trap() #2
15   unreachable
17 cont:
18   %2 = extractvalue { i32, i1 } %0, 0
19   ret i32 %2
23 define 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
27 entry:
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
32 trap:
33   tail call void @llvm.trap() #2
34   unreachable
36 cont:
37   %2 = extractvalue { i32, i1 } %0, 0
38   ret i32 %2
42 define 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
46 entry:
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
51 trap:
52   tail call void @llvm.trap() #2
53   unreachable
55 cont:
56   %2 = extractvalue { i32, i1 } %0, 0
57   ret i32 %2
61 define 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
65 entry:
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
70 trap:
71   tail call void @llvm.trap() #2
72   unreachable
74 cont:
75   %2 = extractvalue { i32, i1 } %0, 0
76   ret i32 %2
80 define 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
87 entry:
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
92 trap:
93   tail call void @llvm.trap() #2
94   unreachable
96 cont:
97   %2 = extractvalue { i32, i1 } %0, 0
98   ret i32 %2
101 define 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
108 entry:
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
113 trap:
114   tail call void @llvm.trap() #2
115   unreachable
117 cont:
118   %2 = extractvalue { i32, i1 } %0, 0
119   ret i32 %2
122 define 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
130 entry:
131   %cmp7 = icmp eq i32 %n, 0
132   br i1 %cmp7, label %for.cond.cleanup, label %for.body
134 for.cond.cleanup:
135   ret void
137 for.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
147 trap:
148   tail call void @llvm.trap() #2
149   unreachable
151 cont:
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
158 cont2:
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
165 define 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
170 entry:
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
175 cont.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
180 for.body.preheader:
181   br label %for.body
183 trap:
184   tail call void @llvm.trap() #2
185   unreachable
187 for.cond.cleanup:
188   ret void
190 for.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
197 cont1:
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
203 declare void @external_fn(...) local_unnamed_addr #0
205 define 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
209 entry:
210   %tobool7 = icmp eq i32 %n, 0
211   br i1 %tobool7, label %while.end, label %land.rhs.preheader
213 land.rhs.preheader:
214   br label %land.rhs
216 while.cond:
217   %tobool = icmp eq i32 %dec9, 0
218   br i1 %tobool, label %while.end, label %land.rhs
220 land.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
230 while.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
237 declare void @llvm.trap() #2
238 declare { i32, i1 } @llvm.sadd.with.overflow.i32(i32, i32) #1
239 declare { i32, i1 } @llvm.uadd.with.overflow.i32(i32, i32) #1
240 declare { i32, i1 } @llvm.ssub.with.overflow.i32(i32, i32) #1
241 declare { i32, i1 } @llvm.usub.with.overflow.i32(i32, i32) #1
242 declare { i32, i1 } @llvm.smul.with.overflow.i32(i32, i32) #1
243 declare { i32, i1 } @llvm.umul.with.overflow.i32(i32, i32) #1