Index: llvm/trunk/lib/Analysis/ValueTracking.cpp =================================================================== --- llvm/trunk/lib/Analysis/ValueTracking.cpp +++ llvm/trunk/lib/Analysis/ValueTracking.cpp @@ -2196,6 +2196,17 @@ if (Tmp == 1) return 1; // Early out. return std::min(Tmp, Tmp2)-1; + case Instruction::Mul: { + // The output of the Mul can be at most twice the valid bits in the inputs. + unsigned SignBitsOp0 = ComputeNumSignBits(U->getOperand(0), Depth + 1, Q); + if (SignBitsOp0 == 1) return 1; // Early out. + unsigned SignBitsOp1 = ComputeNumSignBits(U->getOperand(1), Depth + 1, Q); + if (SignBitsOp1 == 1) return 1; + unsigned OutValidBits = + (TyBits - SignBitsOp0 + 1) + (TyBits - SignBitsOp1 + 1); + return OutValidBits > TyBits ? 1 : TyBits - OutValidBits + 1; + } + case Instruction::PHI: { const PHINode *PN = cast(U); unsigned NumIncomingValues = PN->getNumIncomingValues(); Index: llvm/trunk/test/Transforms/InstCombine/trunc.ll =================================================================== --- llvm/trunk/test/Transforms/InstCombine/trunc.ll +++ llvm/trunk/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