1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4 2; RUN: opt < %s -passes=instcombine -S | FileCheck %s 3 4declare { i32, i1 } @llvm.sadd.with.overflow.i32(i32, i32) 5declare { i32, i1 } @llvm.ssub.with.overflow.i32(i32, i32) 6declare { i32, i1 } @llvm.smul.with.overflow.i32(i32, i32) 7declare { i32, i1 } @llvm.uadd.with.overflow.i32(i32, i32) 8 9declare void @use(i1) 10 11; Tests from PR75360 12define i1 @ckd_add_unsigned(i31 %num) { 13; CHECK-LABEL: define i1 @ckd_add_unsigned( 14; CHECK-SAME: i31 [[NUM:%.*]]) { 15; CHECK-NEXT: [[A2:%.*]] = icmp eq i31 [[NUM]], -1 16; CHECK-NEXT: ret i1 [[A2]] 17; 18 %a0 = zext i31 %num to i32 19 %a1 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %a0, i32 1) 20 %a2 = extractvalue { i32, i1 } %a1, 1 21 %a3 = extractvalue { i32, i1 } %a1, 0 22 %a4 = icmp slt i32 %a3, 0 23 %a5 = or i1 %a2, %a4 24 ret i1 %a5 25} 26 27define i1 @ckd_add_unsigned_commuted(i31 %num) { 28; CHECK-LABEL: define i1 @ckd_add_unsigned_commuted( 29; CHECK-SAME: i31 [[NUM:%.*]]) { 30; CHECK-NEXT: [[A2:%.*]] = icmp eq i31 [[NUM]], -1 31; CHECK-NEXT: ret i1 [[A2]] 32; 33 %a0 = zext i31 %num to i32 34 %a1 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %a0, i32 1) 35 %a2 = extractvalue { i32, i1 } %a1, 1 36 %a3 = extractvalue { i32, i1 } %a1, 0 37 %a4 = icmp slt i32 %a3, 0 38 %a5 = or i1 %a4, %a2 39 ret i1 %a5 40} 41 42define i1 @ckd_add_unsigned_imply_true(i31 %num) { 43; CHECK-LABEL: define i1 @ckd_add_unsigned_imply_true( 44; CHECK-SAME: i31 [[NUM:%.*]]) { 45; CHECK-NEXT: ret i1 true 46; 47 %a0 = zext i31 %num to i32 48 %a1 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %a0, i32 1) 49 %a2 = extractvalue { i32, i1 } %a1, 1 50 %a3 = extractvalue { i32, i1 } %a1, 0 51 %a4 = icmp sgt i32 %a3, -1 52 %a5 = or i1 %a2, %a4 53 ret i1 %a5 54} 55 56define i1 @canonicalize_or_sadd_with_overflow_icmp(i32 %a0) { 57; CHECK-LABEL: define i1 @canonicalize_or_sadd_with_overflow_icmp( 58; CHECK-SAME: i32 [[A0:%.*]]) { 59; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[A0]], -2147483647 60; CHECK-NEXT: [[A5:%.*]] = icmp sgt i32 [[TMP1]], -1 61; CHECK-NEXT: ret i1 [[A5]] 62; 63 %a1 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %a0, i32 1) 64 %a2 = extractvalue { i32, i1 } %a1, 1 65 %a3 = extractvalue { i32, i1 } %a1, 0 66 %a4 = icmp slt i32 %a3, 0 67 %a5 = or i1 %a2, %a4 68 ret i1 %a5 69} 70 71define i1 @canonicalize_or_ssub_with_overflow_icmp(i32 %a0) { 72; CHECK-LABEL: define i1 @canonicalize_or_ssub_with_overflow_icmp( 73; CHECK-SAME: i32 [[A0:%.*]]) { 74; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[A0]], 1 75; CHECK-NEXT: ret i1 [[TMP1]] 76; 77 %a1 = tail call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 %a0, i32 1) 78 %a2 = extractvalue { i32, i1 } %a1, 1 79 %a3 = extractvalue { i32, i1 } %a1, 0 80 %a4 = icmp slt i32 %a3, 0 81 %a5 = or i1 %a2, %a4 82 ret i1 %a5 83} 84 85define i1 @canonicalize_or_uadd_with_overflow_icmp(i32 %a0) { 86; CHECK-LABEL: define i1 @canonicalize_or_uadd_with_overflow_icmp( 87; CHECK-SAME: i32 [[A0:%.*]]) { 88; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[A0]], 1 89; CHECK-NEXT: [[A5:%.*]] = icmp ult i32 [[TMP1]], 10 90; CHECK-NEXT: ret i1 [[A5]] 91; 92 %a1 = tail call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 %a0, i32 1) 93 %a2 = extractvalue { i32, i1 } %a1, 1 94 %a3 = extractvalue { i32, i1 } %a1, 0 95 %a4 = icmp ult i32 %a3, 10 96 %a5 = or i1 %a2, %a4 97 ret i1 %a5 98} 99 100define i1 @canonicalize_or_sadd_with_overflow_icmp_eq(i32 %a0) { 101; CHECK-LABEL: define i1 @canonicalize_or_sadd_with_overflow_icmp_eq( 102; CHECK-SAME: i32 [[A0:%.*]]) { 103; CHECK-NEXT: [[A2:%.*]] = icmp eq i32 [[A0]], 2147483647 104; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[A0]], 9 105; CHECK-NEXT: [[A5:%.*]] = or i1 [[A2]], [[TMP1]] 106; CHECK-NEXT: ret i1 [[A5]] 107; 108 %a1 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %a0, i32 1) 109 %a2 = extractvalue { i32, i1 } %a1, 1 110 %a3 = extractvalue { i32, i1 } %a1, 0 111 %a4 = icmp eq i32 %a3, 10 112 %a5 = or i1 %a2, %a4 113 ret i1 %a5 114} 115 116define i1 @canonicalize_or_uadd_with_overflow_icmp_ne(i32 %a0) { 117; CHECK-LABEL: define i1 @canonicalize_or_uadd_with_overflow_icmp_ne( 118; CHECK-SAME: i32 [[A0:%.*]]) { 119; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i32 [[A0]], 9 120; CHECK-NEXT: ret i1 [[TMP1]] 121; 122 %a1 = tail call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 %a0, i32 1) 123 %a2 = extractvalue { i32, i1 } %a1, 1 124 %a3 = extractvalue { i32, i1 } %a1, 0 125 %a4 = icmp ne i32 %a3, 10 126 %a5 = or i1 %a2, %a4 127 ret i1 %a5 128} 129 130; Negative tests 131define i1 @canonicalize_or_sadd_with_overflow_icmp_mismatched_pred(i32 %a0) { 132; CHECK-LABEL: define i1 @canonicalize_or_sadd_with_overflow_icmp_mismatched_pred( 133; CHECK-SAME: i32 [[A0:%.*]]) { 134; CHECK-NEXT: [[A1:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[A0]], i32 1) 135; CHECK-NEXT: [[A2:%.*]] = extractvalue { i32, i1 } [[A1]], 1 136; CHECK-NEXT: [[A3:%.*]] = extractvalue { i32, i1 } [[A1]], 0 137; CHECK-NEXT: [[A4:%.*]] = icmp ult i32 [[A3]], 2 138; CHECK-NEXT: [[A5:%.*]] = or i1 [[A2]], [[A4]] 139; CHECK-NEXT: ret i1 [[A5]] 140; 141 %a1 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %a0, i32 1) 142 %a2 = extractvalue { i32, i1 } %a1, 1 143 %a3 = extractvalue { i32, i1 } %a1, 0 144 %a4 = icmp ult i32 %a3, 2 145 %a5 = or i1 %a2, %a4 146 ret i1 %a5 147} 148 149define i1 @canonicalize_or_sadd_with_overflow_icmp_non_constant1(i32 %a0, i32 %c) { 150; CHECK-LABEL: define i1 @canonicalize_or_sadd_with_overflow_icmp_non_constant1( 151; CHECK-SAME: i32 [[A0:%.*]], i32 [[C:%.*]]) { 152; CHECK-NEXT: [[A1:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[A0]], i32 [[C]]) 153; CHECK-NEXT: [[A2:%.*]] = extractvalue { i32, i1 } [[A1]], 1 154; CHECK-NEXT: [[A3:%.*]] = extractvalue { i32, i1 } [[A1]], 0 155; CHECK-NEXT: [[A4:%.*]] = icmp slt i32 [[A3]], 0 156; CHECK-NEXT: [[A5:%.*]] = or i1 [[A2]], [[A4]] 157; CHECK-NEXT: ret i1 [[A5]] 158; 159 %a1 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %a0, i32 %c) 160 %a2 = extractvalue { i32, i1 } %a1, 1 161 %a3 = extractvalue { i32, i1 } %a1, 0 162 %a4 = icmp slt i32 %a3, 0 163 %a5 = or i1 %a2, %a4 164 ret i1 %a5 165} 166 167define i1 @canonicalize_or_sadd_with_overflow_icmp_non_constant2(i32 %a0, i32 %c) { 168; CHECK-LABEL: define i1 @canonicalize_or_sadd_with_overflow_icmp_non_constant2( 169; CHECK-SAME: i32 [[A0:%.*]], i32 [[C:%.*]]) { 170; CHECK-NEXT: [[A1:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[A0]], i32 1) 171; CHECK-NEXT: [[A2:%.*]] = extractvalue { i32, i1 } [[A1]], 1 172; CHECK-NEXT: [[A3:%.*]] = extractvalue { i32, i1 } [[A1]], 0 173; CHECK-NEXT: [[A4:%.*]] = icmp slt i32 [[A3]], [[C]] 174; CHECK-NEXT: [[A5:%.*]] = or i1 [[A2]], [[A4]] 175; CHECK-NEXT: ret i1 [[A5]] 176; 177 %a1 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %a0, i32 1) 178 %a2 = extractvalue { i32, i1 } %a1, 1 179 %a3 = extractvalue { i32, i1 } %a1, 0 180 %a4 = icmp slt i32 %a3, %c 181 %a5 = or i1 %a2, %a4 182 ret i1 %a5 183} 184 185define i1 @canonicalize_or_sadd_with_overflow_icmp_multiuse(i32 %a0) { 186; CHECK-LABEL: define i1 @canonicalize_or_sadd_with_overflow_icmp_multiuse( 187; CHECK-SAME: i32 [[A0:%.*]]) { 188; CHECK-NEXT: [[A1:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[A0]], i32 1) 189; CHECK-NEXT: [[A2:%.*]] = extractvalue { i32, i1 } [[A1]], 1 190; CHECK-NEXT: [[A3:%.*]] = extractvalue { i32, i1 } [[A1]], 0 191; CHECK-NEXT: [[A4:%.*]] = icmp slt i32 [[A3]], 0 192; CHECK-NEXT: call void @use(i1 [[A4]]) 193; CHECK-NEXT: [[A5:%.*]] = or i1 [[A2]], [[A4]] 194; CHECK-NEXT: ret i1 [[A5]] 195; 196 %a1 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %a0, i32 1) 197 %a2 = extractvalue { i32, i1 } %a1, 1 198 %a3 = extractvalue { i32, i1 } %a1, 0 199 %a4 = icmp slt i32 %a3, 0 200 call void @use(i1 %a4) 201 %a5 = or i1 %a2, %a4 202 ret i1 %a5 203} 204 205define i1 @canonicalize_or_sadd_with_overflow_icmp_overflow(i32 %a0) { 206; CHECK-LABEL: define i1 @canonicalize_or_sadd_with_overflow_icmp_overflow( 207; CHECK-SAME: i32 [[A0:%.*]]) { 208; CHECK-NEXT: [[A1:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[A0]], i32 -2147483647) 209; CHECK-NEXT: [[A2:%.*]] = extractvalue { i32, i1 } [[A1]], 1 210; CHECK-NEXT: [[A3:%.*]] = extractvalue { i32, i1 } [[A1]], 0 211; CHECK-NEXT: [[A4:%.*]] = icmp slt i32 [[A3]], 2 212; CHECK-NEXT: [[A5:%.*]] = or i1 [[A2]], [[A4]] 213; CHECK-NEXT: ret i1 [[A5]] 214; 215 %a1 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %a0, i32 -2147483647) 216 %a2 = extractvalue { i32, i1 } %a1, 1 217 %a3 = extractvalue { i32, i1 } %a1, 0 218 %a4 = icmp slt i32 %a3, 2 219 %a5 = or i1 %a2, %a4 220 ret i1 %a5 221} 222 223define i1 @canonicalize_or_uadd_with_overflow_icmp_overflow(i32 %a0) { 224; CHECK-LABEL: define i1 @canonicalize_or_uadd_with_overflow_icmp_overflow( 225; CHECK-SAME: i32 [[A0:%.*]]) { 226; CHECK-NEXT: [[A1:%.*]] = tail call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[A0]], i32 3) 227; CHECK-NEXT: [[A2:%.*]] = extractvalue { i32, i1 } [[A1]], 1 228; CHECK-NEXT: [[A3:%.*]] = extractvalue { i32, i1 } [[A1]], 0 229; CHECK-NEXT: [[A4:%.*]] = icmp ult i32 [[A3]], 2 230; CHECK-NEXT: [[A5:%.*]] = or i1 [[A2]], [[A4]] 231; CHECK-NEXT: ret i1 [[A5]] 232; 233 %a1 = tail call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 %a0, i32 3) 234 %a2 = extractvalue { i32, i1 } %a1, 1 235 %a3 = extractvalue { i32, i1 } %a1, 0 236 %a4 = icmp ult i32 %a3, 2 237 %a5 = or i1 %a2, %a4 238 ret i1 %a5 239} 240 241define i1 @canonicalize_or_ssub_with_overflow_icmp_overflow(i32 %a0) { 242; CHECK-LABEL: define i1 @canonicalize_or_ssub_with_overflow_icmp_overflow( 243; CHECK-SAME: i32 [[A0:%.*]]) { 244; CHECK-NEXT: [[A1:%.*]] = tail call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 [[A0]], i32 -2147483648) 245; CHECK-NEXT: [[A2:%.*]] = extractvalue { i32, i1 } [[A1]], 1 246; CHECK-NEXT: [[A3:%.*]] = extractvalue { i32, i1 } [[A1]], 0 247; CHECK-NEXT: [[A4:%.*]] = icmp slt i32 [[A3]], -1 248; CHECK-NEXT: [[A5:%.*]] = or i1 [[A2]], [[A4]] 249; CHECK-NEXT: ret i1 [[A5]] 250; 251 %a1 = tail call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 %a0, i32 -2147483648) 252 %a2 = extractvalue { i32, i1 } %a1, 1 253 %a3 = extractvalue { i32, i1 } %a1, 0 254 %a4 = icmp slt i32 %a3, -1 255 %a5 = or i1 %a2, %a4 256 ret i1 %a5 257} 258 259define i1 @canonicalize_or_smul_with_overflow_icmp(i32 %a0) { 260; CHECK-LABEL: define i1 @canonicalize_or_smul_with_overflow_icmp( 261; CHECK-SAME: i32 [[A0:%.*]]) { 262; CHECK-NEXT: [[A1:%.*]] = tail call { i32, i1 } @llvm.smul.with.overflow.i32(i32 [[A0]], i32 3) 263; CHECK-NEXT: [[A2:%.*]] = extractvalue { i32, i1 } [[A1]], 1 264; CHECK-NEXT: [[A3:%.*]] = extractvalue { i32, i1 } [[A1]], 0 265; CHECK-NEXT: [[A4:%.*]] = icmp slt i32 [[A3]], 10 266; CHECK-NEXT: [[A5:%.*]] = or i1 [[A2]], [[A4]] 267; CHECK-NEXT: ret i1 [[A5]] 268; 269 %a1 = tail call { i32, i1 } @llvm.smul.with.overflow.i32(i32 %a0, i32 3) 270 %a2 = extractvalue { i32, i1 } %a1, 1 271 %a3 = extractvalue { i32, i1 } %a1, 0 272 %a4 = icmp slt i32 %a3, 10 273 %a5 = or i1 %a2, %a4 274 ret i1 %a5 275} 276