1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt -passes=constraint-elimination -S %s | FileCheck %s 3 4declare { i8, i1 } @llvm.ssub.with.overflow.i8(i8, i8) 5 6define i8 @ssub_no_overflow_due_to_or_conds(i8 %a, i8 %b) { 7; CHECK-LABEL: @ssub_no_overflow_due_to_or_conds( 8; CHECK-NEXT: entry: 9; CHECK-NEXT: [[C_1:%.*]] = icmp sle i8 [[B:%.*]], [[A:%.*]] 10; CHECK-NEXT: [[C_2:%.*]] = icmp slt i8 [[A]], 0 11; CHECK-NEXT: [[OR_COND:%.*]] = or i1 [[C_2]], [[C_1]] 12; CHECK-NEXT: br i1 [[OR_COND]], label [[EXIT_FAIL:%.*]], label [[MATH:%.*]] 13; CHECK: math: 14; CHECK-NEXT: [[TMP0:%.*]] = sub i8 [[B]], [[A]] 15; CHECK-NEXT: br i1 false, label [[EXIT_FAIL]], label [[EXIT_OK:%.*]] 16; CHECK: exit.ok: 17; CHECK-NEXT: ret i8 [[TMP0]] 18; CHECK: exit.fail: 19; CHECK-NEXT: ret i8 0 20; 21entry: 22 %c.1 = icmp sle i8 %b, %a 23 %c.2 = icmp slt i8 %a, 0 24 %or.cond = or i1 %c.2, %c.1 25 br i1 %or.cond, label %exit.fail, label %math 26 27math: 28 %op = tail call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %b, i8 %a) 29 %status = extractvalue { i8, i1 } %op, 1 30 br i1 %status, label %exit.fail, label %exit.ok 31 32exit.ok: 33 %res = extractvalue { i8, i1 } %op, 0 34 ret i8 %res 35 36exit.fail: 37 ret i8 0 38} 39 40declare void @use_res({ i8, i1 }) 41 42define i8 @ssub_no_overflow_due_to_or_conds_result_used(i8 %a, i8 %b) { 43; CHECK-LABEL: @ssub_no_overflow_due_to_or_conds_result_used( 44; CHECK-NEXT: entry: 45; CHECK-NEXT: [[C_1:%.*]] = icmp sle i8 [[B:%.*]], [[A:%.*]] 46; CHECK-NEXT: [[C_2:%.*]] = icmp slt i8 [[A]], 0 47; CHECK-NEXT: [[OR_COND:%.*]] = or i1 [[C_2]], [[C_1]] 48; CHECK-NEXT: br i1 [[OR_COND]], label [[EXIT_FAIL:%.*]], label [[MATH:%.*]] 49; CHECK: math: 50; CHECK-NEXT: [[TMP0:%.*]] = sub i8 [[B]], [[A]] 51; CHECK-NEXT: [[OP:%.*]] = tail call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 [[B]], i8 [[A]]) 52; CHECK-NEXT: call void @use_res({ i8, i1 } [[OP]]) 53; CHECK-NEXT: br i1 false, label [[EXIT_FAIL]], label [[EXIT_OK:%.*]] 54; CHECK: exit.ok: 55; CHECK-NEXT: ret i8 [[TMP0]] 56; CHECK: exit.fail: 57; CHECK-NEXT: ret i8 0 58; 59entry: 60 %c.1 = icmp sle i8 %b, %a 61 %c.2 = icmp slt i8 %a, 0 62 %or.cond = or i1 %c.2, %c.1 63 br i1 %or.cond, label %exit.fail, label %math 64 65math: 66 %op = tail call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %b, i8 %a) 67 call void @use_res({ i8, i1 } %op) 68 %status = extractvalue { i8, i1 } %op, 1 69 br i1 %status, label %exit.fail, label %exit.ok 70 71exit.ok: 72 %res = extractvalue { i8, i1 } %op, 0 73 ret i8 %res 74 75exit.fail: 76 ret i8 0 77} 78 79define i8 @ssub_no_overflow_due_to_and_conds(i8 %a, i8 %b) { 80; CHECK-LABEL: @ssub_no_overflow_due_to_and_conds( 81; CHECK-NEXT: entry: 82; CHECK-NEXT: [[C_1:%.*]] = icmp sge i8 [[B:%.*]], [[A:%.*]] 83; CHECK-NEXT: [[C_2:%.*]] = icmp sge i8 [[A]], 0 84; CHECK-NEXT: [[AND:%.*]] = and i1 [[C_2]], [[C_1]] 85; CHECK-NEXT: br i1 [[AND]], label [[MATH:%.*]], label [[EXIT_FAIL:%.*]] 86; CHECK: math: 87; CHECK-NEXT: [[TMP0:%.*]] = sub i8 [[B]], [[A]] 88; CHECK-NEXT: br i1 false, label [[EXIT_FAIL]], label [[EXIT_OK:%.*]] 89; CHECK: exit.ok: 90; CHECK-NEXT: ret i8 [[TMP0]] 91; CHECK: exit.fail: 92; CHECK-NEXT: ret i8 0 93; 94entry: 95 %c.1 = icmp sge i8 %b, %a 96 %c.2 = icmp sge i8 %a, 0 97 %and = and i1 %c.2, %c.1 98 br i1 %and, label %math, label %exit.fail 99 100math: 101 %op = tail call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %b, i8 %a) 102 %status = extractvalue { i8, i1 } %op, 1 103 br i1 %status, label %exit.fail, label %exit.ok 104 105exit.ok: 106 %res = extractvalue { i8, i1 } %op, 0 107 ret i8 %res 108 109exit.fail: 110 ret i8 0 111} 112 113define i8 @ssub_no_overflow_due_to_and_conds_sub_result_not_used(i8 %a, i8 %b) { 114; CHECK-LABEL: @ssub_no_overflow_due_to_and_conds_sub_result_not_used( 115; CHECK-NEXT: entry: 116; CHECK-NEXT: [[C_1:%.*]] = icmp sge i8 [[B:%.*]], [[A:%.*]] 117; CHECK-NEXT: [[C_2:%.*]] = icmp sge i8 [[A]], 0 118; CHECK-NEXT: [[AND:%.*]] = and i1 [[C_2]], [[C_1]] 119; CHECK-NEXT: br i1 [[AND]], label [[MATH:%.*]], label [[EXIT_FAIL:%.*]] 120; CHECK: math: 121; CHECK-NEXT: br i1 false, label [[EXIT_FAIL]], label [[EXIT_OK:%.*]] 122; CHECK: exit.ok: 123; CHECK-NEXT: ret i8 20 124; CHECK: exit.fail: 125; CHECK-NEXT: ret i8 0 126; 127entry: 128 %c.1 = icmp sge i8 %b, %a 129 %c.2 = icmp sge i8 %a, 0 130 %and = and i1 %c.2, %c.1 131 br i1 %and, label %math, label %exit.fail 132 133math: 134 %op = tail call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %b, i8 %a) 135 %status = extractvalue { i8, i1 } %op, 1 136 br i1 %status, label %exit.fail, label %exit.ok 137 138exit.ok: 139 ret i8 20 140 141exit.fail: 142 ret i8 0 143} 144 145define i8 @ssub_may_overflow1(i8 %a, i8 %b) { 146; CHECK-LABEL: @ssub_may_overflow1( 147; CHECK-NEXT: entry: 148; CHECK-NEXT: [[C_1:%.*]] = icmp sge i8 [[B:%.*]], [[A:%.*]] 149; CHECK-NEXT: br i1 [[C_1]], label [[MATH:%.*]], label [[EXIT_FAIL:%.*]] 150; CHECK: math: 151; CHECK-NEXT: [[OP:%.*]] = tail call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 [[B]], i8 [[A]]) 152; CHECK-NEXT: [[STATUS:%.*]] = extractvalue { i8, i1 } [[OP]], 1 153; CHECK-NEXT: br i1 [[STATUS]], label [[EXIT_FAIL]], label [[EXIT_OK:%.*]] 154; CHECK: exit.ok: 155; CHECK-NEXT: [[RES:%.*]] = extractvalue { i8, i1 } [[OP]], 0 156; CHECK-NEXT: ret i8 [[RES]] 157; CHECK: exit.fail: 158; CHECK-NEXT: ret i8 0 159; 160entry: 161 %c.1 = icmp sge i8 %b, %a 162 br i1 %c.1, label %math, label %exit.fail 163 164math: 165 %op = tail call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %b, i8 %a) 166 %status = extractvalue { i8, i1 } %op, 1 167 br i1 %status, label %exit.fail, label %exit.ok 168 169exit.ok: 170 %res = extractvalue { i8, i1 } %op, 0 171 ret i8 %res 172 173exit.fail: 174 ret i8 0 175} 176 177define i8 @ssub_may_overflow2(i8 %a, i8 %b) { 178; CHECK-LABEL: @ssub_may_overflow2( 179; CHECK-NEXT: entry: 180; CHECK-NEXT: [[C_1:%.*]] = icmp sge i8 [[A:%.*]], 0 181; CHECK-NEXT: br i1 [[C_1]], label [[MATH:%.*]], label [[EXIT_FAIL:%.*]] 182; CHECK: math: 183; CHECK-NEXT: [[OP:%.*]] = tail call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 [[B:%.*]], i8 [[A]]) 184; CHECK-NEXT: [[STATUS:%.*]] = extractvalue { i8, i1 } [[OP]], 1 185; CHECK-NEXT: br i1 [[STATUS]], label [[EXIT_FAIL]], label [[EXIT_OK:%.*]] 186; CHECK: exit.ok: 187; CHECK-NEXT: [[RES:%.*]] = extractvalue { i8, i1 } [[OP]], 0 188; CHECK-NEXT: ret i8 [[RES]] 189; CHECK: exit.fail: 190; CHECK-NEXT: ret i8 0 191; 192entry: 193 %c.1 = icmp sge i8 %a, 0 194 br i1 %c.1, label %math, label %exit.fail 195 196math: 197 %op = tail call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %b, i8 %a) 198 %status = extractvalue { i8, i1 } %op, 1 199 br i1 %status, label %exit.fail, label %exit.ok 200 201exit.ok: 202 %res = extractvalue { i8, i1 } %op, 0 203 ret i8 %res 204 205exit.fail: 206 ret i8 0 207} 208 209define i8 @ssub_may_overflow3(i8 %a, i8 %b) { 210; CHECK-LABEL: @ssub_may_overflow3( 211; CHECK-NEXT: entry: 212; CHECK-NEXT: [[C_1:%.*]] = icmp sge i8 [[B:%.*]], [[A:%.*]] 213; CHECK-NEXT: [[C_2:%.*]] = icmp sge i8 [[A]], -1 214; CHECK-NEXT: [[AND:%.*]] = and i1 [[C_2]], [[C_1]] 215; CHECK-NEXT: br i1 [[AND]], label [[MATH:%.*]], label [[EXIT_FAIL:%.*]] 216; CHECK: math: 217; CHECK-NEXT: [[OP:%.*]] = tail call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 [[B]], i8 [[A]]) 218; CHECK-NEXT: [[STATUS:%.*]] = extractvalue { i8, i1 } [[OP]], 1 219; CHECK-NEXT: br i1 [[STATUS]], label [[EXIT_FAIL]], label [[EXIT_OK:%.*]] 220; CHECK: exit.ok: 221; CHECK-NEXT: [[RES:%.*]] = extractvalue { i8, i1 } [[OP]], 0 222; CHECK-NEXT: ret i8 [[RES]] 223; CHECK: exit.fail: 224; CHECK-NEXT: ret i8 0 225; 226entry: 227 %c.1 = icmp sge i8 %b, %a 228 %c.2 = icmp sge i8 %a, -1 229 %and = and i1 %c.2, %c.1 230 br i1 %and, label %math, label %exit.fail 231 232math: 233 %op = tail call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %b, i8 %a) 234 %status = extractvalue { i8, i1 } %op, 1 235 br i1 %status, label %exit.fail, label %exit.ok 236 237exit.ok: 238 %res = extractvalue { i8, i1 } %op, 0 239 ret i8 %res 240 241exit.fail: 242 ret i8 0 243} 244 245define i8 @ssub_may_overflow4(i8 %a, i8 %b) { 246; CHECK-LABEL: @ssub_may_overflow4( 247; CHECK-NEXT: entry: 248; CHECK-NEXT: [[C_1:%.*]] = icmp uge i8 [[B:%.*]], [[A:%.*]] 249; CHECK-NEXT: [[C_2:%.*]] = icmp sge i8 [[A]], 0 250; CHECK-NEXT: [[AND:%.*]] = and i1 [[C_2]], [[C_1]] 251; CHECK-NEXT: br i1 [[AND]], label [[MATH:%.*]], label [[EXIT_FAIL:%.*]] 252; CHECK: math: 253; CHECK-NEXT: [[OP:%.*]] = tail call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 [[B]], i8 [[A]]) 254; CHECK-NEXT: [[STATUS:%.*]] = extractvalue { i8, i1 } [[OP]], 1 255; CHECK-NEXT: br i1 [[STATUS]], label [[EXIT_FAIL]], label [[EXIT_OK:%.*]] 256; CHECK: exit.ok: 257; CHECK-NEXT: [[RES:%.*]] = extractvalue { i8, i1 } [[OP]], 0 258; CHECK-NEXT: ret i8 [[RES]] 259; CHECK: exit.fail: 260; CHECK-NEXT: ret i8 0 261; 262entry: 263 %c.1 = icmp uge i8 %b, %a 264 %c.2 = icmp sge i8 %a, 0 265 %and = and i1 %c.2, %c.1 266 br i1 %and, label %math, label %exit.fail 267 268math: 269 %op = tail call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %b, i8 %a) 270 %status = extractvalue { i8, i1 } %op, 1 271 br i1 %status, label %exit.fail, label %exit.ok 272 273exit.ok: 274 %res = extractvalue { i8, i1 } %op, 0 275 ret i8 %res 276 277exit.fail: 278 ret i8 0 279} 280 281define i8 @ssub_may_overflow5(i8 %a, i8 %b) { 282; CHECK-LABEL: @ssub_may_overflow5( 283; CHECK-NEXT: entry: 284; CHECK-NEXT: [[C_1:%.*]] = icmp sge i8 [[B:%.*]], [[A:%.*]] 285; CHECK-NEXT: [[C_2:%.*]] = icmp sge i8 [[B]], 0 286; CHECK-NEXT: [[AND:%.*]] = and i1 [[C_2]], [[C_1]] 287; CHECK-NEXT: br i1 [[AND]], label [[MATH:%.*]], label [[EXIT_FAIL:%.*]] 288; CHECK: math: 289; CHECK-NEXT: [[OP:%.*]] = tail call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 [[B]], i8 [[A]]) 290; CHECK-NEXT: [[STATUS:%.*]] = extractvalue { i8, i1 } [[OP]], 1 291; CHECK-NEXT: br i1 [[STATUS]], label [[EXIT_FAIL]], label [[EXIT_OK:%.*]] 292; CHECK: exit.ok: 293; CHECK-NEXT: [[RES:%.*]] = extractvalue { i8, i1 } [[OP]], 0 294; CHECK-NEXT: ret i8 [[RES]] 295; CHECK: exit.fail: 296; CHECK-NEXT: ret i8 0 297; 298entry: 299 %c.1 = icmp sge i8 %b, %a 300 %c.2 = icmp sge i8 %b, 0 301 %and = and i1 %c.2, %c.1 302 br i1 %and, label %math, label %exit.fail 303 304math: 305 %op = tail call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %b, i8 %a) 306 %status = extractvalue { i8, i1 } %op, 1 307 br i1 %status, label %exit.fail, label %exit.ok 308 309exit.ok: 310 %res = extractvalue { i8, i1 } %op, 0 311 ret i8 %res 312 313exit.fail: 314 ret i8 0 315} 316 317define i8 @ssub_may_overflow6(i8 %a, i8 %b) { 318; CHECK-LABEL: @ssub_may_overflow6( 319; CHECK-NEXT: entry: 320; CHECK-NEXT: [[C_1:%.*]] = icmp sle i8 [[B:%.*]], [[A:%.*]] 321; CHECK-NEXT: [[C_2:%.*]] = icmp slt i8 [[B]], 0 322; CHECK-NEXT: [[OR_COND:%.*]] = or i1 [[C_2]], [[C_1]] 323; CHECK-NEXT: br i1 [[OR_COND]], label [[EXIT_FAIL:%.*]], label [[MATH:%.*]] 324; CHECK: math: 325; CHECK-NEXT: [[OP:%.*]] = tail call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 [[B]], i8 [[A]]) 326; CHECK-NEXT: [[STATUS:%.*]] = extractvalue { i8, i1 } [[OP]], 1 327; CHECK-NEXT: br i1 [[STATUS]], label [[EXIT_FAIL]], label [[EXIT_OK:%.*]] 328; CHECK: exit.ok: 329; CHECK-NEXT: [[RES:%.*]] = extractvalue { i8, i1 } [[OP]], 0 330; CHECK-NEXT: ret i8 [[RES]] 331; CHECK: exit.fail: 332; CHECK-NEXT: ret i8 0 333; 334entry: 335 %c.1 = icmp sle i8 %b, %a 336 %c.2 = icmp slt i8 %b, 0 337 %or.cond = or i1 %c.2, %c.1 338 br i1 %or.cond, label %exit.fail, label %math 339 340math: 341 %op = tail call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %b, i8 %a) 342 %status = extractvalue { i8, i1 } %op, 1 343 br i1 %status, label %exit.fail, label %exit.ok 344 345exit.ok: 346 %res = extractvalue { i8, i1 } %op, 0 347 ret i8 %res 348 349exit.fail: 350 ret i8 0 351} 352