Index: lib/Analysis/ValueTracking.cpp =================================================================== --- lib/Analysis/ValueTracking.cpp +++ lib/Analysis/ValueTracking.cpp @@ -2196,6 +2196,16 @@ if (Tmp == 1) return 1; // Early out. return std::min(Tmp, Tmp2)-1; + case Instruction::Mul: { + // The output of the Mul can at most twice the valid bits in the inputs. + Tmp = ComputeNumSignBits(U->getOperand(0), Depth + 1, Q); + if (Tmp == 1) return 1; // Early out. + Tmp2 = ComputeNumSignBits(U->getOperand(1), Depth + 1, Q); + if (Tmp2 == 1) return 1; + unsigned OutValidBits = (TyBits - Tmp + 1) + (TyBits - Tmp2 + 1); + return OutValidBits > TyBits ? 1 : TyBits - OutValidBits + 1; + } + case Instruction::PHI: { const PHINode *PN = cast(U); unsigned NumIncomingValues = PN->getNumIncomingValues(); Index: test/Transforms/InstCombine/trunc.ll =================================================================== --- test/Transforms/InstCombine/trunc.ll +++ test/Transforms/InstCombine/trunc.ll @@ -89,6 +89,21 @@ ret i32 %D } +define i16 @ashr_mul(i8 %X, i8 %Y) { +; CHECK-LABEL: @ashr_mul( +; CHECK-NEXT: [[A:%.*]] = sext i8 %X to i16 +; CHECK-NEXT: [[B:%.*]] = sext i8 %Y to i16 +; CHECK-NEXT: [[C:%.*]] = mul nsw i16 [[A]], [[B]] +; CHECK-NEXT: [[D:%.*]] = ashr i16 [[C]], 8 +; CHECK-NEXT: ret i16 [[D]] + %A = sext i8 %X to i20 + %B = sext i8 %Y to i20 + %C = mul i20 %A, %B + %D = ashr i20 %C, 8 + %E = trunc i20 %D to i16 + ret i16 %E +} + define i32 @trunc_ashr(i32 %X) { ; CHECK-LABEL: @trunc_ashr( ; CHECK-NEXT: [[B:%.*]] = or i32 [[X:%.*]], -2147483648