1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt < %s -passes=instcombine -S | FileCheck %s 3 4declare { i64, i1 } @llvm.ssub.with.overflow.i64(i64, i64) 5declare { i8, i1 } @llvm.ssub.with.overflow.i8(i8, i8) 6 7declare void @use(i1) 8 9define i1 @test_generic(i64 %a, i64 %b) { 10; CHECK-LABEL: @test_generic( 11; CHECK-NEXT: [[RES:%.*]] = tail call { i64, i1 } @llvm.ssub.with.overflow.i64(i64 [[A:%.*]], i64 [[B:%.*]]) 12; CHECK-NEXT: [[OVERFLOW:%.*]] = extractvalue { i64, i1 } [[RES]], 1 13; CHECK-NEXT: ret i1 [[OVERFLOW]] 14; 15 %res = tail call { i64, i1 } @llvm.ssub.with.overflow.i64(i64 %a, i64 %b) 16 %overflow = extractvalue { i64, i1 } %res, 1 17 ret i1 %overflow 18} 19 20define i1 @test_constant0(i8 %a) { 21; CHECK-LABEL: @test_constant0( 22; CHECK-NEXT: ret i1 false 23; 24 %res = tail call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %a, i8 0) 25 %overflow = extractvalue { i8, i1 } %res, 1 26 ret i1 %overflow 27} 28 29define i1 @test_constant1(i8 %a) { 30; CHECK-LABEL: @test_constant1( 31; CHECK-NEXT: [[OVERFLOW:%.*]] = icmp eq i8 [[A:%.*]], -128 32; CHECK-NEXT: ret i1 [[OVERFLOW]] 33; 34 %res = tail call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %a, i8 1) 35 %overflow = extractvalue { i8, i1 } %res, 1 36 ret i1 %overflow 37} 38 39define i1 @test_constant2(i8 %a) { 40; CHECK-LABEL: @test_constant2( 41; CHECK-NEXT: [[OVERFLOW:%.*]] = icmp slt i8 [[A:%.*]], -126 42; CHECK-NEXT: ret i1 [[OVERFLOW]] 43; 44 %res = tail call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %a, i8 2) 45 %overflow = extractvalue { i8, i1 } %res, 1 46 ret i1 %overflow 47} 48 49define i1 @test_constant3(i8 %a) { 50; CHECK-LABEL: @test_constant3( 51; CHECK-NEXT: [[OVERFLOW:%.*]] = icmp slt i8 [[A:%.*]], -125 52; CHECK-NEXT: ret i1 [[OVERFLOW]] 53; 54 %res = tail call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %a, i8 3) 55 %overflow = extractvalue { i8, i1 } %res, 1 56 ret i1 %overflow 57} 58 59define i1 @test_constant4(i8 %a) { 60; CHECK-LABEL: @test_constant4( 61; CHECK-NEXT: [[OVERFLOW:%.*]] = icmp slt i8 [[A:%.*]], -124 62; CHECK-NEXT: ret i1 [[OVERFLOW]] 63; 64 %res = tail call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %a, i8 4) 65 %overflow = extractvalue { i8, i1 } %res, 1 66 ret i1 %overflow 67} 68 69 70define i1 @test_constant127(i8 %a) { 71; CHECK-LABEL: @test_constant127( 72; CHECK-NEXT: [[OVERFLOW:%.*]] = icmp slt i8 [[A:%.*]], -1 73; CHECK-NEXT: ret i1 [[OVERFLOW]] 74; 75 %res = tail call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %a, i8 127) 76 %overflow = extractvalue { i8, i1 } %res, 1 77 ret i1 %overflow 78} 79 80define i1 @test_constant128(i8 %a) { 81; CHECK-LABEL: @test_constant128( 82; CHECK-NEXT: [[OVERFLOW:%.*]] = icmp sgt i8 [[A:%.*]], -1 83; CHECK-NEXT: ret i1 [[OVERFLOW]] 84; 85 %res = tail call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %a, i8 128) 86 %overflow = extractvalue { i8, i1 } %res, 1 87 ret i1 %overflow 88} 89 90define i1 @test_constant255(i8 %a) { 91; CHECK-LABEL: @test_constant255( 92; CHECK-NEXT: [[OVERFLOW:%.*]] = icmp eq i8 [[A:%.*]], 127 93; CHECK-NEXT: ret i1 [[OVERFLOW]] 94; 95 %res = tail call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %a, i8 255) 96 %overflow = extractvalue { i8, i1 } %res, 1 97 ret i1 %overflow 98} 99 100define i1 @sub_eq0(i8 %x, i8 %y, i1 %b) { 101; CHECK-LABEL: @sub_eq0( 102; CHECK-NEXT: [[SS:%.*]] = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) 103; CHECK-NEXT: [[OV:%.*]] = extractvalue { i8, i1 } [[SS]], 1 104; CHECK-NEXT: call void @use(i1 [[OV]]) 105; CHECK-NEXT: [[EQ0:%.*]] = icmp eq i8 [[X]], [[Y]] 106; CHECK-NEXT: ret i1 [[EQ0]] 107; 108 %ss = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %x, i8 %y) 109 %ov = extractvalue { i8, i1 } %ss, 1 110 call void @use(i1 %ov) 111 %sub = extractvalue { i8, i1 } %ss, 0 112 %eq0 = icmp eq i8 %sub, 0 113 ret i1 %eq0 114} 115 116define i1 @sub_ne0(i8 %x, i8 %y, i1 %b) { 117; CHECK-LABEL: @sub_ne0( 118; CHECK-NEXT: [[SS:%.*]] = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) 119; CHECK-NEXT: [[OV:%.*]] = extractvalue { i8, i1 } [[SS]], 1 120; CHECK-NEXT: call void @use(i1 [[OV]]) 121; CHECK-NEXT: [[NE0:%.*]] = icmp ne i8 [[X]], [[Y]] 122; CHECK-NEXT: ret i1 [[NE0]] 123; 124 %ss = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %x, i8 %y) 125 %ov = extractvalue { i8, i1 } %ss, 1 126 call void @use(i1 %ov) 127 %sub = extractvalue { i8, i1 } %ss, 0 128 %ne0 = icmp ne i8 %sub, 0 129 ret i1 %ne0 130} 131 132; negative test - need zero 133 134define i1 @sub_eq1(i8 %x, i8 %y, i1 %b) { 135; CHECK-LABEL: @sub_eq1( 136; CHECK-NEXT: [[SS:%.*]] = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) 137; CHECK-NEXT: [[OV:%.*]] = extractvalue { i8, i1 } [[SS]], 1 138; CHECK-NEXT: call void @use(i1 [[OV]]) 139; CHECK-NEXT: [[SUB:%.*]] = extractvalue { i8, i1 } [[SS]], 0 140; CHECK-NEXT: [[EQ1:%.*]] = icmp eq i8 [[SUB]], 1 141; CHECK-NEXT: ret i1 [[EQ1]] 142; 143 %ss = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %x, i8 %y) 144 %ov = extractvalue { i8, i1 } %ss, 1 145 call void @use(i1 %ov) 146 %sub = extractvalue { i8, i1 } %ss, 0 147 %eq1 = icmp eq i8 %sub, 1 148 ret i1 %eq1 149} 150 151; negative test - need equality pred 152 153define i1 @sub_sgt0(i8 %x, i8 %y, i1 %b) { 154; CHECK-LABEL: @sub_sgt0( 155; CHECK-NEXT: [[SS:%.*]] = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) 156; CHECK-NEXT: [[OV:%.*]] = extractvalue { i8, i1 } [[SS]], 1 157; CHECK-NEXT: call void @use(i1 [[OV]]) 158; CHECK-NEXT: [[SUB:%.*]] = extractvalue { i8, i1 } [[SS]], 0 159; CHECK-NEXT: [[SGT0:%.*]] = icmp sgt i8 [[SUB]], 0 160; CHECK-NEXT: ret i1 [[SGT0]] 161; 162 %ss = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %x, i8 %y) 163 %ov = extractvalue { i8, i1 } %ss, 1 164 call void @use(i1 %ov) 165 %sub = extractvalue { i8, i1 } %ss, 0 166 %sgt0 = icmp sgt i8 %sub, 0 167 ret i1 %sgt0 168} 169