diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp @@ -713,6 +713,25 @@ return replaceInstUsesWith(Trunc, Res); } + // For integer types, check if we can shorten the entire input expression to + // DestWidth * 2, which won't allow removing the truncate, but reducing the + // width may enable further optimizations, e.g. allowing for larger + // vectorization factors. + if (auto *DestITy = dyn_cast(DestTy)) { + if (DestWidth * 2 < SrcWidth) { + auto *NewDestTy = DestITy->getExtendedType(); + if (shouldChangeType(SrcTy, DestTy) && + canEvaluateTruncated(Src, NewDestTy, *this, &Trunc)) { + LLVM_DEBUG( + dbgs() << "ICE: EvaluateInDifferentType converting expression type" + " to reduce the width of operand of" + << Trunc << '\n'); + Value *Res = EvaluateInDifferentType(Src, NewDestTy, false); + return new TruncInst(Res, DestTy); + } + } + } + // Test if the trunc is the user of a select which is part of a // minimum or maximum operation. If so, don't do any more simplification. // Even simplifying demanded bits can break the canonical form of a diff --git a/llvm/test/Transforms/InstCombine/trunc-binop-ext.ll b/llvm/test/Transforms/InstCombine/trunc-binop-ext.ll --- a/llvm/test/Transforms/InstCombine/trunc-binop-ext.ll +++ b/llvm/test/Transforms/InstCombine/trunc-binop-ext.ll @@ -318,11 +318,11 @@ ; Test cases for PR43580 define i8 @narrow_zext_ashr_keep_trunc(i8 %i1, i8 %i2) { ; CHECK-LABEL: @narrow_zext_ashr_keep_trunc( -; CHECK-NEXT: [[I1_EXT:%.*]] = sext i8 [[I1:%.*]] to i32 -; CHECK-NEXT: [[I2_EXT:%.*]] = sext i8 [[I2:%.*]] to i32 -; CHECK-NEXT: [[SUB:%.*]] = add nsw i32 [[I1_EXT]], [[I2_EXT]] -; CHECK-NEXT: [[SHIFT:%.*]] = lshr i32 [[SUB]], 1 -; CHECK-NEXT: [[T:%.*]] = trunc i32 [[SHIFT]] to i8 +; CHECK-NEXT: [[I1_EXT:%.*]] = sext i8 [[I1:%.*]] to i16 +; CHECK-NEXT: [[I2_EXT:%.*]] = sext i8 [[I2:%.*]] to i16 +; CHECK-NEXT: [[SUB:%.*]] = add nsw i16 [[I1_EXT]], [[I2_EXT]] +; CHECK-NEXT: [[SHIFT:%.*]] = lshr i16 [[SUB]], 1 +; CHECK-NEXT: [[T:%.*]] = trunc i16 [[SHIFT]] to i8 ; CHECK-NEXT: ret i8 [[T]] ; %i1.ext = sext i8 %i1 to i32 @@ -338,8 +338,8 @@ ; CHECK-NEXT: [[I1_EXT:%.*]] = sext i8 [[I1:%.*]] to i16 ; CHECK-NEXT: [[I2_EXT:%.*]] = sext i8 [[I2:%.*]] to i16 ; CHECK-NEXT: [[SUB:%.*]] = add nsw i16 [[I1_EXT]], [[I2_EXT]] -; CHECK-NEXT: [[SHIFT:%.*]] = lshr i16 [[SUB]], 1 -; CHECK-NEXT: [[T:%.*]] = trunc i16 [[SHIFT]] to i8 +; CHECK-NEXT: [[TMP1:%.*]] = lshr i16 [[SUB]], 1 +; CHECK-NEXT: [[T:%.*]] = trunc i16 [[TMP1]] to i8 ; CHECK-NEXT: ret i8 [[T]] ; %i1.ext = sext i8 %i1 to i16