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