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