363 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py2; RUN: opt -passes=instcombine -S %s | FileCheck %s3 4; Check that we simplify llvm.umul.with.overflow, if the overflow check is5; weakened by or (icmp ne %res, 0) %overflow. This is generated by code using6; __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) #013 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]], 018; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i64 [[B]], 019; CHECK-NEXT: [[OVERFLOW_1:%.*]] = and i1 [[TMP1]], [[TMP2]]20; CHECK-NEXT: store i64 [[MUL]], ptr [[PTR:%.*]], align 821; 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, 126 %mul = extractvalue { i64, i1 } %res, 027 %cmp = icmp ne i64 %mul, 028 %overflow.1 = or i1 %overflow, %cmp29 store i64 %mul, ptr %ptr, align 830 ret i1 %overflow.131}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]], 037; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i64 [[B]], 038; CHECK-NEXT: [[OVERFLOW_1:%.*]] = and i1 [[TMP1]], [[TMP2]]39; CHECK-NEXT: store i64 [[MUL]], ptr [[PTR:%.*]], align 840; 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, 145 %mul = extractvalue { i64, i1 } %res, 046 %cmp = icmp ne i64 %mul, 047 %overflow.1 = select i1 %overflow, i1 true, i1 %cmp48 store i64 %mul, ptr %ptr, align 849 ret i1 %overflow.150}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]], 056; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i64 [[B]], 057; CHECK-NEXT: [[OVERFLOW_1:%.*]] = and i1 [[TMP1]], [[TMP2]]58; CHECK-NEXT: store i64 [[MUL]], ptr [[PTR:%.*]], align 859; 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, 165 %mul = extractvalue { i64, i1 } %res, 066 %cmp = icmp ne i64 %mul, 067 %overflow.1 = or i1 %cmp, %overflow68 store i64 %mul, ptr %ptr, align 869 ret i1 %overflow.170}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]], 076; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i64 [[B]], 077; CHECK-NEXT: [[OVERFLOW_1:%.*]] = and i1 [[TMP1]], [[TMP2]]78; CHECK-NEXT: store i64 [[MUL]], ptr [[PTR:%.*]], align 879; 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, 185 %mul = extractvalue { i64, i1 } %res, 086 %cmp = icmp ne i64 %mul, 087 %overflow.1 = select i1 %cmp, i1 true, i1 %overflow88 store i64 %mul, ptr %ptr, align 889 ret i1 %overflow.190}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]], 096; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i64 [[B]], 097; 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 8100; 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, 1105 %mul = extractvalue { i64, i1 } %res, 0106 %cmp = icmp ne i64 %mul, 0107 %overflow.1 = or i1 %overflow, %cmp108 %neg = sub i64 0, %mul109 store i64 %neg, ptr %ptr, align 8110 ret i1 %overflow.1111}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]], 0117; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i64 [[B]], 0118; 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 8121; 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, 1126 %mul = extractvalue { i64, i1 } %res, 0127 %cmp = icmp ne i64 %mul, 0128 %overflow.1 = select i1 %overflow, i1 true, i1 %cmp129 %neg = sub i64 0, %mul130 store i64 %neg, ptr %ptr, align 8131 ret i1 %overflow.1132}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]], 1140; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[A]], 0141; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i64 [[B]], 0142; 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, 1148 %mul = extractvalue { i64, i1 } %res, 0149 %cmp = icmp ne i64 %mul, 0150 %overflow.1 = or i1 %overflow, %cmp151 call void @use(i1 %overflow)152 ret i1 %overflow.1153}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]], 1159; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[A]], 0160; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i64 [[B]], 0161; 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, 1167 %mul = extractvalue { i64, i1 } %res, 0168 %cmp = icmp ne i64 %mul, 0169 %overflow.1 = select i1 %overflow, i1 true, i1 %cmp170 call void @use(i1 %overflow)171 ret i1 %overflow.1172}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]], 1179; CHECK-NEXT: [[MUL:%.*]] = extractvalue { i64, i1 } [[RES]], 0180; CHECK-NEXT: [[CMP:%.*]] = icmp ne i64 [[MUL]], 0181; 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 8184; 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, 1189 %mul = extractvalue { i64, i1 } %res, 0190 %cmp = icmp ne i64 %mul, 0191 %overflow.1 = or i1 %overflow, %cmp192 %neg = sub i64 0, %mul193 store i64 %neg, ptr %ptr, align 8194 call void @use(i1 %overflow)195 ret i1 %overflow.1196}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]], 1202; CHECK-NEXT: [[MUL:%.*]] = extractvalue { i64, i1 } [[RES]], 0203; CHECK-NEXT: [[CMP:%.*]] = icmp ne i64 [[MUL]], 0204; 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 8207; 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, 1212 %mul = extractvalue { i64, i1 } %res, 0213 %cmp = icmp ne i64 %mul, 0214 %overflow.1 = select i1 %overflow, i1 true, i1 %cmp215 %neg = sub i64 0, %mul216 store i64 %neg, ptr %ptr, align 8217 call void @use(i1 %overflow)218 ret i1 %overflow.1219}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]], 0227; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[A]], 0228; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i64 [[B]], 0229; 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 8232; 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, 1237 %mul = extractvalue { i64, i1 } %res, 0238 %cmp = icmp ne i64 %mul, 0239 %overflow.1 = or i1 %overflow, %cmp240 %neg = sub i64 0, %mul241 store i64 %neg, ptr %ptr, align 8242 call void @use.2({ i64, i1 } %res)243 ret i1 %overflow.1244}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]], 0250; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[A]], 0251; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i64 [[B]], 0252; 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 8255; 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, 1260 %mul = extractvalue { i64, i1 } %res, 0261 %cmp = icmp ne i64 %mul, 0262 %overflow.1 = select i1 %overflow, i1 true, i1 %cmp263 %neg = sub i64 0, %mul264 store i64 %neg, ptr %ptr, align 8265 call void @use.2({ i64, i1 } %res)266 ret i1 %overflow.1267}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]], 0276; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i64 [[B]], 0277; 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 8280; 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, 1286 %mul = extractvalue { i64, i1 } %res, 0287 %cmp = icmp ne i64 %mul, 0288 %overflow.1 = or i1 %overflow, %cmp289 %neg = sub i64 0, %mul290 store i64 %neg, ptr %ptr, align 8291 call void @use.3(i64 %mul)292 ret i1 %overflow.1293}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]], 0299; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i64 [[B]], 0300; 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 8303; 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, 1309 %mul = extractvalue { i64, i1 } %res, 0310 %cmp = icmp ne i64 %mul, 0311 %overflow.1 = select i1 %overflow, i1 true, i1 %cmp312 %neg = sub i64 0, %mul313 store i64 %neg, ptr %ptr, align 8314 call void @use.3(i64 %mul)315 ret i1 %overflow.1316}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]], 1324; CHECK-NEXT: [[MUL:%.*]] = extractvalue { i64, i1 } [[RES]], 0325; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i64 [[MUL]], 0326; 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 8329; 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, 1333 %mul = extractvalue { i64, i1 } %res, 0334 %cmp = icmp sgt i64 %mul, 0335 %overflow.1 = or i1 %overflow, %cmp336 %neg = sub i64 0, %mul337 store i64 %neg, ptr %ptr, align 8338 ret i1 %overflow.1339}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]], 1345; CHECK-NEXT: [[MUL:%.*]] = extractvalue { i64, i1 } [[RES]], 0346; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i64 [[MUL]], 0347; 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 8350; 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, 1354 %mul = extractvalue { i64, i1 } %res, 0355 %cmp = icmp sgt i64 %mul, 0356 %overflow.1 = select i1 %overflow, i1 true, i1 %cmp357 %neg = sub i64 0, %mul358 store i64 %neg, ptr %ptr, align 8359 ret i1 %overflow.1360}361 362attributes #0 = { nounwind readnone speculatable willreturn }363