1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt -passes=instcombine -S %s | FileCheck %s 3 4; Check that we simplify llvm.umul.with.overflow, if the overflow check is 5; weakened by or (icmp ne %res, 0) %overflow. This is generated by code using 6; __builtin_mul_overflow with negative integer constants, e.g. 7 8; bool test(unsigned long long v, unsigned long long *res) { 9; return __builtin_mul_overflow(v, -4775807LL, res); 10; } 11 12declare { i64, i1 } @llvm.umul.with.overflow.i64(i64, i64) #0 13 14define i1 @test1(i64 %a, i64 %b, ptr %ptr) { 15; CHECK-LABEL: @test1( 16; CHECK-NEXT: [[MUL:%.*]] = mul i64 [[A:%.*]], [[B:%.*]] 17; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[A]], 0 18; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i64 [[B]], 0 19; CHECK-NEXT: [[OVERFLOW_1:%.*]] = and i1 [[TMP1]], [[TMP2]] 20; CHECK-NEXT: store i64 [[MUL]], ptr [[PTR:%.*]], align 8 21; CHECK-NEXT: ret i1 [[OVERFLOW_1]] 22; 23 24 %res = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %a, i64 %b) 25 %overflow = extractvalue { i64, i1 } %res, 1 26 %mul = extractvalue { i64, i1 } %res, 0 27 %cmp = icmp ne i64 %mul, 0 28 %overflow.1 = or i1 %overflow, %cmp 29 store i64 %mul, ptr %ptr, align 8 30 ret i1 %overflow.1 31} 32 33define i1 @test1_logical(i64 %a, i64 %b, ptr %ptr) { 34; CHECK-LABEL: @test1_logical( 35; CHECK-NEXT: [[MUL:%.*]] = mul i64 [[A:%.*]], [[B:%.*]] 36; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[A]], 0 37; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i64 [[B]], 0 38; CHECK-NEXT: [[OVERFLOW_1:%.*]] = and i1 [[TMP1]], [[TMP2]] 39; CHECK-NEXT: store i64 [[MUL]], ptr [[PTR:%.*]], align 8 40; CHECK-NEXT: ret i1 [[OVERFLOW_1]] 41; 42 43 %res = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %a, i64 %b) 44 %overflow = extractvalue { i64, i1 } %res, 1 45 %mul = extractvalue { i64, i1 } %res, 0 46 %cmp = icmp ne i64 %mul, 0 47 %overflow.1 = select i1 %overflow, i1 true, i1 %cmp 48 store i64 %mul, ptr %ptr, align 8 49 ret i1 %overflow.1 50} 51 52define i1 @test1_or_ops_swapped(i64 %a, i64 %b, ptr %ptr) { 53; CHECK-LABEL: @test1_or_ops_swapped( 54; CHECK-NEXT: [[MUL:%.*]] = mul i64 [[A:%.*]], [[B:%.*]] 55; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[A]], 0 56; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i64 [[B]], 0 57; CHECK-NEXT: [[OVERFLOW_1:%.*]] = and i1 [[TMP1]], [[TMP2]] 58; CHECK-NEXT: store i64 [[MUL]], ptr [[PTR:%.*]], align 8 59; CHECK-NEXT: ret i1 [[OVERFLOW_1]] 60; 61 62 63 %res = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %a, i64 %b) 64 %overflow = extractvalue { i64, i1 } %res, 1 65 %mul = extractvalue { i64, i1 } %res, 0 66 %cmp = icmp ne i64 %mul, 0 67 %overflow.1 = or i1 %cmp, %overflow 68 store i64 %mul, ptr %ptr, align 8 69 ret i1 %overflow.1 70} 71 72define i1 @test1_or_ops_swapped_logical(i64 %a, i64 %b, ptr %ptr) { 73; CHECK-LABEL: @test1_or_ops_swapped_logical( 74; CHECK-NEXT: [[MUL:%.*]] = mul i64 [[A:%.*]], [[B:%.*]] 75; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[A]], 0 76; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i64 [[B]], 0 77; CHECK-NEXT: [[OVERFLOW_1:%.*]] = and i1 [[TMP1]], [[TMP2]] 78; CHECK-NEXT: store i64 [[MUL]], ptr [[PTR:%.*]], align 8 79; CHECK-NEXT: ret i1 [[OVERFLOW_1]] 80; 81 82 83 %res = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %a, i64 %b) 84 %overflow = extractvalue { i64, i1 } %res, 1 85 %mul = extractvalue { i64, i1 } %res, 0 86 %cmp = icmp ne i64 %mul, 0 87 %overflow.1 = select i1 %cmp, i1 true, i1 %overflow 88 store i64 %mul, ptr %ptr, align 8 89 ret i1 %overflow.1 90} 91 92define i1 @test2(i64 %a, i64 %b, ptr %ptr) { 93; CHECK-LABEL: @test2( 94; CHECK-NEXT: [[MUL:%.*]] = mul i64 [[A:%.*]], [[B:%.*]] 95; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[A]], 0 96; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i64 [[B]], 0 97; CHECK-NEXT: [[OVERFLOW_1:%.*]] = and i1 [[TMP1]], [[TMP2]] 98; CHECK-NEXT: [[NEG:%.*]] = sub i64 0, [[MUL]] 99; CHECK-NEXT: store i64 [[NEG]], ptr [[PTR:%.*]], align 8 100; CHECK-NEXT: ret i1 [[OVERFLOW_1]] 101; 102 103 %res = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %a, i64 %b) 104 %overflow = extractvalue { i64, i1 } %res, 1 105 %mul = extractvalue { i64, i1 } %res, 0 106 %cmp = icmp ne i64 %mul, 0 107 %overflow.1 = or i1 %overflow, %cmp 108 %neg = sub i64 0, %mul 109 store i64 %neg, ptr %ptr, align 8 110 ret i1 %overflow.1 111} 112 113define i1 @test2_logical(i64 %a, i64 %b, ptr %ptr) { 114; CHECK-LABEL: @test2_logical( 115; CHECK-NEXT: [[MUL:%.*]] = mul i64 [[A:%.*]], [[B:%.*]] 116; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[A]], 0 117; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i64 [[B]], 0 118; CHECK-NEXT: [[OVERFLOW_1:%.*]] = and i1 [[TMP1]], [[TMP2]] 119; CHECK-NEXT: [[NEG:%.*]] = sub i64 0, [[MUL]] 120; CHECK-NEXT: store i64 [[NEG]], ptr [[PTR:%.*]], align 8 121; CHECK-NEXT: ret i1 [[OVERFLOW_1]] 122; 123 124 %res = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %a, i64 %b) 125 %overflow = extractvalue { i64, i1 } %res, 1 126 %mul = extractvalue { i64, i1 } %res, 0 127 %cmp = icmp ne i64 %mul, 0 128 %overflow.1 = select i1 %overflow, i1 true, i1 %cmp 129 %neg = sub i64 0, %mul 130 store i64 %neg, ptr %ptr, align 8 131 ret i1 %overflow.1 132} 133 134declare void @use(i1) 135 136define i1 @test3_multiple_overflow_users(i64 %a, i64 %b, ptr %ptr) { 137; CHECK-LABEL: @test3_multiple_overflow_users( 138; CHECK-NEXT: [[RES:%.*]] = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[A:%.*]], i64 [[B:%.*]]) 139; CHECK-NEXT: [[OVERFLOW:%.*]] = extractvalue { i64, i1 } [[RES]], 1 140; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[A]], 0 141; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i64 [[B]], 0 142; CHECK-NEXT: [[OVERFLOW_1:%.*]] = and i1 [[TMP1]], [[TMP2]] 143; CHECK-NEXT: call void @use(i1 [[OVERFLOW]]) 144; CHECK-NEXT: ret i1 [[OVERFLOW_1]] 145; 146 %res = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %a, i64 %b) 147 %overflow = extractvalue { i64, i1 } %res, 1 148 %mul = extractvalue { i64, i1 } %res, 0 149 %cmp = icmp ne i64 %mul, 0 150 %overflow.1 = or i1 %overflow, %cmp 151 call void @use(i1 %overflow) 152 ret i1 %overflow.1 153} 154 155define i1 @test3_multiple_overflow_users_logical(i64 %a, i64 %b, ptr %ptr) { 156; CHECK-LABEL: @test3_multiple_overflow_users_logical( 157; CHECK-NEXT: [[RES:%.*]] = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[A:%.*]], i64 [[B:%.*]]) 158; CHECK-NEXT: [[OVERFLOW:%.*]] = extractvalue { i64, i1 } [[RES]], 1 159; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[A]], 0 160; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i64 [[B]], 0 161; CHECK-NEXT: [[OVERFLOW_1:%.*]] = and i1 [[TMP1]], [[TMP2]] 162; CHECK-NEXT: call void @use(i1 [[OVERFLOW]]) 163; CHECK-NEXT: ret i1 [[OVERFLOW_1]] 164; 165 %res = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %a, i64 %b) 166 %overflow = extractvalue { i64, i1 } %res, 1 167 %mul = extractvalue { i64, i1 } %res, 0 168 %cmp = icmp ne i64 %mul, 0 169 %overflow.1 = select i1 %overflow, i1 true, i1 %cmp 170 call void @use(i1 %overflow) 171 ret i1 %overflow.1 172} 173 174; Do not simplify if %overflow and %mul have multiple uses. 175define i1 @test3_multiple_overflow_and_mul_users(i64 %a, i64 %b, ptr %ptr) { 176; CHECK-LABEL: @test3_multiple_overflow_and_mul_users( 177; CHECK-NEXT: [[RES:%.*]] = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[A:%.*]], i64 [[B:%.*]]) 178; CHECK-NEXT: [[OVERFLOW:%.*]] = extractvalue { i64, i1 } [[RES]], 1 179; CHECK-NEXT: [[MUL:%.*]] = extractvalue { i64, i1 } [[RES]], 0 180; CHECK-NEXT: [[CMP:%.*]] = icmp ne i64 [[MUL]], 0 181; CHECK-NEXT: [[OVERFLOW_1:%.*]] = or i1 [[OVERFLOW]], [[CMP]] 182; CHECK-NEXT: [[NEG:%.*]] = sub i64 0, [[MUL]] 183; CHECK-NEXT: store i64 [[NEG]], ptr [[PTR:%.*]], align 8 184; CHECK-NEXT: call void @use(i1 [[OVERFLOW]]) 185; CHECK-NEXT: ret i1 [[OVERFLOW_1]] 186; 187 %res = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %a, i64 %b) 188 %overflow = extractvalue { i64, i1 } %res, 1 189 %mul = extractvalue { i64, i1 } %res, 0 190 %cmp = icmp ne i64 %mul, 0 191 %overflow.1 = or i1 %overflow, %cmp 192 %neg = sub i64 0, %mul 193 store i64 %neg, ptr %ptr, align 8 194 call void @use(i1 %overflow) 195 ret i1 %overflow.1 196} 197 198define i1 @test3_multiple_overflow_and_mul_users_logical(i64 %a, i64 %b, ptr %ptr) { 199; CHECK-LABEL: @test3_multiple_overflow_and_mul_users_logical( 200; CHECK-NEXT: [[RES:%.*]] = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[A:%.*]], i64 [[B:%.*]]) 201; CHECK-NEXT: [[OVERFLOW:%.*]] = extractvalue { i64, i1 } [[RES]], 1 202; CHECK-NEXT: [[MUL:%.*]] = extractvalue { i64, i1 } [[RES]], 0 203; CHECK-NEXT: [[CMP:%.*]] = icmp ne i64 [[MUL]], 0 204; CHECK-NEXT: [[OVERFLOW_1:%.*]] = or i1 [[OVERFLOW]], [[CMP]] 205; CHECK-NEXT: [[NEG:%.*]] = sub i64 0, [[MUL]] 206; CHECK-NEXT: store i64 [[NEG]], ptr [[PTR:%.*]], align 8 207; CHECK-NEXT: call void @use(i1 [[OVERFLOW]]) 208; CHECK-NEXT: ret i1 [[OVERFLOW_1]] 209; 210 %res = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %a, i64 %b) 211 %overflow = extractvalue { i64, i1 } %res, 1 212 %mul = extractvalue { i64, i1 } %res, 0 213 %cmp = icmp ne i64 %mul, 0 214 %overflow.1 = select i1 %overflow, i1 true, i1 %cmp 215 %neg = sub i64 0, %mul 216 store i64 %neg, ptr %ptr, align 8 217 call void @use(i1 %overflow) 218 ret i1 %overflow.1 219} 220 221 222declare void @use.2({ i64, i1 }) 223define i1 @test3_multiple_res_users(i64 %a, i64 %b, ptr %ptr) { 224; CHECK-LABEL: @test3_multiple_res_users( 225; CHECK-NEXT: [[RES:%.*]] = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[A:%.*]], i64 [[B:%.*]]) 226; CHECK-NEXT: [[MUL:%.*]] = extractvalue { i64, i1 } [[RES]], 0 227; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[A]], 0 228; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i64 [[B]], 0 229; CHECK-NEXT: [[OVERFLOW_1:%.*]] = and i1 [[TMP1]], [[TMP2]] 230; CHECK-NEXT: [[NEG:%.*]] = sub i64 0, [[MUL]] 231; CHECK-NEXT: store i64 [[NEG]], ptr [[PTR:%.*]], align 8 232; CHECK-NEXT: call void @use.2({ i64, i1 } [[RES]]) 233; CHECK-NEXT: ret i1 [[OVERFLOW_1]] 234; 235 %res = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %a, i64 %b) 236 %overflow = extractvalue { i64, i1 } %res, 1 237 %mul = extractvalue { i64, i1 } %res, 0 238 %cmp = icmp ne i64 %mul, 0 239 %overflow.1 = or i1 %overflow, %cmp 240 %neg = sub i64 0, %mul 241 store i64 %neg, ptr %ptr, align 8 242 call void @use.2({ i64, i1 } %res) 243 ret i1 %overflow.1 244} 245 246define i1 @test3_multiple_res_users_logical(i64 %a, i64 %b, ptr %ptr) { 247; CHECK-LABEL: @test3_multiple_res_users_logical( 248; CHECK-NEXT: [[RES:%.*]] = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[A:%.*]], i64 [[B:%.*]]) 249; CHECK-NEXT: [[MUL:%.*]] = extractvalue { i64, i1 } [[RES]], 0 250; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[A]], 0 251; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i64 [[B]], 0 252; CHECK-NEXT: [[OVERFLOW_1:%.*]] = and i1 [[TMP1]], [[TMP2]] 253; CHECK-NEXT: [[NEG:%.*]] = sub i64 0, [[MUL]] 254; CHECK-NEXT: store i64 [[NEG]], ptr [[PTR:%.*]], align 8 255; CHECK-NEXT: call void @use.2({ i64, i1 } [[RES]]) 256; CHECK-NEXT: ret i1 [[OVERFLOW_1]] 257; 258 %res = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %a, i64 %b) 259 %overflow = extractvalue { i64, i1 } %res, 1 260 %mul = extractvalue { i64, i1 } %res, 0 261 %cmp = icmp ne i64 %mul, 0 262 %overflow.1 = select i1 %overflow, i1 true, i1 %cmp 263 %neg = sub i64 0, %mul 264 store i64 %neg, ptr %ptr, align 8 265 call void @use.2({ i64, i1 } %res) 266 ret i1 %overflow.1 267} 268 269declare void @use.3(i64) 270 271; Simplify if %mul has multiple uses. 272define i1 @test3_multiple_mul_users(i64 %a, i64 %b, ptr %ptr) { 273; CHECK-LABEL: @test3_multiple_mul_users( 274; CHECK-NEXT: [[MUL:%.*]] = mul i64 [[A:%.*]], [[B:%.*]] 275; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[A]], 0 276; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i64 [[B]], 0 277; CHECK-NEXT: [[OVERFLOW_1:%.*]] = and i1 [[TMP1]], [[TMP2]] 278; CHECK-NEXT: [[NEG:%.*]] = sub i64 0, [[MUL]] 279; CHECK-NEXT: store i64 [[NEG]], ptr [[PTR:%.*]], align 8 280; CHECK-NEXT: call void @use.3(i64 [[MUL]]) 281; CHECK-NEXT: ret i1 [[OVERFLOW_1]] 282; 283 284 %res = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %a, i64 %b) 285 %overflow = extractvalue { i64, i1 } %res, 1 286 %mul = extractvalue { i64, i1 } %res, 0 287 %cmp = icmp ne i64 %mul, 0 288 %overflow.1 = or i1 %overflow, %cmp 289 %neg = sub i64 0, %mul 290 store i64 %neg, ptr %ptr, align 8 291 call void @use.3(i64 %mul) 292 ret i1 %overflow.1 293} 294 295define i1 @test3_multiple_mul_users_logical(i64 %a, i64 %b, ptr %ptr) { 296; CHECK-LABEL: @test3_multiple_mul_users_logical( 297; CHECK-NEXT: [[MUL:%.*]] = mul i64 [[A:%.*]], [[B:%.*]] 298; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[A]], 0 299; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i64 [[B]], 0 300; CHECK-NEXT: [[OVERFLOW_1:%.*]] = and i1 [[TMP1]], [[TMP2]] 301; CHECK-NEXT: [[NEG:%.*]] = sub i64 0, [[MUL]] 302; CHECK-NEXT: store i64 [[NEG]], ptr [[PTR:%.*]], align 8 303; CHECK-NEXT: call void @use.3(i64 [[MUL]]) 304; CHECK-NEXT: ret i1 [[OVERFLOW_1]] 305; 306 307 %res = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %a, i64 %b) 308 %overflow = extractvalue { i64, i1 } %res, 1 309 %mul = extractvalue { i64, i1 } %res, 0 310 %cmp = icmp ne i64 %mul, 0 311 %overflow.1 = select i1 %overflow, i1 true, i1 %cmp 312 %neg = sub i64 0, %mul 313 store i64 %neg, ptr %ptr, align 8 314 call void @use.3(i64 %mul) 315 ret i1 %overflow.1 316} 317 318 319 320define i1 @test4_no_icmp_ne(i64 %a, i64 %b, ptr %ptr) { 321; CHECK-LABEL: @test4_no_icmp_ne( 322; CHECK-NEXT: [[RES:%.*]] = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[A:%.*]], i64 [[B:%.*]]) 323; CHECK-NEXT: [[OVERFLOW:%.*]] = extractvalue { i64, i1 } [[RES]], 1 324; CHECK-NEXT: [[MUL:%.*]] = extractvalue { i64, i1 } [[RES]], 0 325; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i64 [[MUL]], 0 326; CHECK-NEXT: [[OVERFLOW_1:%.*]] = or i1 [[OVERFLOW]], [[CMP]] 327; CHECK-NEXT: [[NEG:%.*]] = sub i64 0, [[MUL]] 328; CHECK-NEXT: store i64 [[NEG]], ptr [[PTR:%.*]], align 8 329; CHECK-NEXT: ret i1 [[OVERFLOW_1]] 330; 331 %res = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %a, i64 %b) 332 %overflow = extractvalue { i64, i1 } %res, 1 333 %mul = extractvalue { i64, i1 } %res, 0 334 %cmp = icmp sgt i64 %mul, 0 335 %overflow.1 = or i1 %overflow, %cmp 336 %neg = sub i64 0, %mul 337 store i64 %neg, ptr %ptr, align 8 338 ret i1 %overflow.1 339} 340 341define i1 @test4_no_icmp_ne_logical(i64 %a, i64 %b, ptr %ptr) { 342; CHECK-LABEL: @test4_no_icmp_ne_logical( 343; CHECK-NEXT: [[RES:%.*]] = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[A:%.*]], i64 [[B:%.*]]) 344; CHECK-NEXT: [[OVERFLOW:%.*]] = extractvalue { i64, i1 } [[RES]], 1 345; CHECK-NEXT: [[MUL:%.*]] = extractvalue { i64, i1 } [[RES]], 0 346; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i64 [[MUL]], 0 347; CHECK-NEXT: [[OVERFLOW_1:%.*]] = or i1 [[OVERFLOW]], [[CMP]] 348; CHECK-NEXT: [[NEG:%.*]] = sub i64 0, [[MUL]] 349; CHECK-NEXT: store i64 [[NEG]], ptr [[PTR:%.*]], align 8 350; CHECK-NEXT: ret i1 [[OVERFLOW_1]] 351; 352 %res = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %a, i64 %b) 353 %overflow = extractvalue { i64, i1 } %res, 1 354 %mul = extractvalue { i64, i1 } %res, 0 355 %cmp = icmp sgt i64 %mul, 0 356 %overflow.1 = select i1 %overflow, i1 true, i1 %cmp 357 %neg = sub i64 0, %mul 358 store i64 %neg, ptr %ptr, align 8 359 ret i1 %overflow.1 360} 361 362attributes #0 = { nounwind readnone speculatable willreturn } 363