1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt -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, i64* %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]], i64* [[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, i64* %ptr, align 8 30 ret i1 %overflow.1 31} 32 33define i1 @test1_or_ops_swapped(i64 %a, i64 %b, i64* %ptr) { 34; CHECK-LABEL: @test1_or_ops_swapped( 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]], i64* [[PTR:%.*]], align 8 40; CHECK-NEXT: ret i1 [[OVERFLOW_1]] 41; 42 43 44 %res = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %a, i64 %b) 45 %overflow = extractvalue { i64, i1 } %res, 1 46 %mul = extractvalue { i64, i1 } %res, 0 47 %cmp = icmp ne i64 %mul, 0 48 %overflow.1 = or i1 %cmp, %overflow 49 store i64 %mul, i64* %ptr, align 8 50 ret i1 %overflow.1 51} 52 53define i1 @test2(i64 %a, i64 %b, i64* %ptr) { 54; CHECK-LABEL: @test2( 55; CHECK-NEXT: [[MUL:%.*]] = mul i64 [[A:%.*]], [[B:%.*]] 56; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[A]], 0 57; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i64 [[B]], 0 58; CHECK-NEXT: [[OVERFLOW_1:%.*]] = and i1 [[TMP1]], [[TMP2]] 59; CHECK-NEXT: [[NEG:%.*]] = sub i64 0, [[MUL]] 60; CHECK-NEXT: store i64 [[NEG]], i64* [[PTR:%.*]], align 8 61; CHECK-NEXT: ret i1 [[OVERFLOW_1]] 62; 63 64 %res = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %a, i64 %b) 65 %overflow = extractvalue { i64, i1 } %res, 1 66 %mul = extractvalue { i64, i1 } %res, 0 67 %cmp = icmp ne i64 %mul, 0 68 %overflow.1 = or i1 %overflow, %cmp 69 %neg = sub i64 0, %mul 70 store i64 %neg, i64* %ptr, align 8 71 ret i1 %overflow.1 72} 73 74declare void @use(i1) 75 76define i1 @test3_multiple_overflow_users(i64 %a, i64 %b, i64* %ptr) { 77; CHECK-LABEL: @test3_multiple_overflow_users( 78; CHECK-NEXT: [[RES:%.*]] = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[A:%.*]], i64 [[B:%.*]]) 79; CHECK-NEXT: [[OVERFLOW:%.*]] = extractvalue { i64, i1 } [[RES]], 1 80; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[A]], 0 81; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i64 [[B]], 0 82; CHECK-NEXT: [[OVERFLOW_1:%.*]] = and i1 [[TMP1]], [[TMP2]] 83; CHECK-NEXT: call void @use(i1 [[OVERFLOW]]) 84; CHECK-NEXT: ret i1 [[OVERFLOW_1]] 85; 86 %res = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %a, i64 %b) 87 %overflow = extractvalue { i64, i1 } %res, 1 88 %mul = extractvalue { i64, i1 } %res, 0 89 %cmp = icmp ne i64 %mul, 0 90 %overflow.1 = or i1 %overflow, %cmp 91 call void @use(i1 %overflow) 92 ret i1 %overflow.1 93} 94 95; Do not simplify if %overflow and %mul have multiple uses. 96define i1 @test3_multiple_overflow_and_mul_users(i64 %a, i64 %b, i64* %ptr) { 97; CHECK-LABEL: @test3_multiple_overflow_and_mul_users( 98; CHECK-NEXT: [[RES:%.*]] = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[A:%.*]], i64 [[B:%.*]]) 99; CHECK-NEXT: [[OVERFLOW:%.*]] = extractvalue { i64, i1 } [[RES]], 1 100; CHECK-NEXT: [[MUL:%.*]] = extractvalue { i64, i1 } [[RES]], 0 101; CHECK-NEXT: [[CMP:%.*]] = icmp ne i64 [[MUL]], 0 102; CHECK-NEXT: [[OVERFLOW_1:%.*]] = or i1 [[OVERFLOW]], [[CMP]] 103; CHECK-NEXT: [[NEG:%.*]] = sub i64 0, [[MUL]] 104; CHECK-NEXT: store i64 [[NEG]], i64* [[PTR:%.*]], align 8 105; CHECK-NEXT: call void @use(i1 [[OVERFLOW]]) 106; CHECK-NEXT: ret i1 [[OVERFLOW_1]] 107; 108 %res = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %a, i64 %b) 109 %overflow = extractvalue { i64, i1 } %res, 1 110 %mul = extractvalue { i64, i1 } %res, 0 111 %cmp = icmp ne i64 %mul, 0 112 %overflow.1 = or i1 %overflow, %cmp 113 %neg = sub i64 0, %mul 114 store i64 %neg, i64* %ptr, align 8 115 call void @use(i1 %overflow) 116 ret i1 %overflow.1 117} 118 119 120declare void @use.2({ i64, i1 }) 121define i1 @test3_multiple_res_users(i64 %a, i64 %b, i64* %ptr) { 122; CHECK-LABEL: @test3_multiple_res_users( 123; CHECK-NEXT: [[RES:%.*]] = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[A:%.*]], i64 [[B:%.*]]) 124; CHECK-NEXT: [[MUL:%.*]] = extractvalue { i64, i1 } [[RES]], 0 125; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[A]], 0 126; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i64 [[B]], 0 127; CHECK-NEXT: [[OVERFLOW_1:%.*]] = and i1 [[TMP1]], [[TMP2]] 128; CHECK-NEXT: [[NEG:%.*]] = sub i64 0, [[MUL]] 129; CHECK-NEXT: store i64 [[NEG]], i64* [[PTR:%.*]], align 8 130; CHECK-NEXT: call void @use.2({ i64, i1 } [[RES]]) 131; CHECK-NEXT: ret i1 [[OVERFLOW_1]] 132; 133 %res = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %a, i64 %b) 134 %overflow = extractvalue { i64, i1 } %res, 1 135 %mul = extractvalue { i64, i1 } %res, 0 136 %cmp = icmp ne i64 %mul, 0 137 %overflow.1 = or i1 %overflow, %cmp 138 %neg = sub i64 0, %mul 139 store i64 %neg, i64* %ptr, align 8 140 call void @use.2({ i64, i1 } %res) 141 ret i1 %overflow.1 142} 143 144declare void @use.3(i64) 145 146; Simplify if %mul has multiple uses. 147define i1 @test3_multiple_mul_users(i64 %a, i64 %b, i64* %ptr) { 148; CHECK-LABEL: @test3_multiple_mul_users( 149; CHECK-NEXT: [[MUL:%.*]] = mul i64 [[A:%.*]], [[B:%.*]] 150; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[A]], 0 151; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i64 [[B]], 0 152; CHECK-NEXT: [[OVERFLOW_1:%.*]] = and i1 [[TMP1]], [[TMP2]] 153; CHECK-NEXT: [[NEG:%.*]] = sub i64 0, [[MUL]] 154; CHECK-NEXT: store i64 [[NEG]], i64* [[PTR:%.*]], align 8 155; CHECK-NEXT: call void @use.3(i64 [[MUL]]) 156; CHECK-NEXT: ret i1 [[OVERFLOW_1]] 157; 158 159 %res = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %a, i64 %b) 160 %overflow = extractvalue { i64, i1 } %res, 1 161 %mul = extractvalue { i64, i1 } %res, 0 162 %cmp = icmp ne i64 %mul, 0 163 %overflow.1 = or i1 %overflow, %cmp 164 %neg = sub i64 0, %mul 165 store i64 %neg, i64* %ptr, align 8 166 call void @use.3(i64 %mul) 167 ret i1 %overflow.1 168} 169 170 171 172define i1 @test4_no_icmp_ne(i64 %a, i64 %b, i64* %ptr) { 173; CHECK-LABEL: @test4_no_icmp_ne( 174; CHECK-NEXT: [[RES:%.*]] = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[A:%.*]], i64 [[B:%.*]]) 175; CHECK-NEXT: [[OVERFLOW:%.*]] = extractvalue { i64, i1 } [[RES]], 1 176; CHECK-NEXT: [[MUL:%.*]] = extractvalue { i64, i1 } [[RES]], 0 177; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i64 [[MUL]], 0 178; CHECK-NEXT: [[OVERFLOW_1:%.*]] = or i1 [[OVERFLOW]], [[CMP]] 179; CHECK-NEXT: [[NEG:%.*]] = sub i64 0, [[MUL]] 180; CHECK-NEXT: store i64 [[NEG]], i64* [[PTR:%.*]], align 8 181; CHECK-NEXT: ret i1 [[OVERFLOW_1]] 182; 183 %res = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %a, i64 %b) 184 %overflow = extractvalue { i64, i1 } %res, 1 185 %mul = extractvalue { i64, i1 } %res, 0 186 %cmp = icmp sgt i64 %mul, 0 187 %overflow.1 = or i1 %overflow, %cmp 188 %neg = sub i64 0, %mul 189 store i64 %neg, i64* %ptr, align 8 190 ret i1 %overflow.1 191} 192 193attributes #0 = { nounwind readnone speculatable willreturn } 194