diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -3312,10 +3312,17 @@ return Tmp; } - case Instruction::Trunc: - // FIXME: it's tricky to do anything useful for this, but it is an - // important case for targets like X86. - break; + case Instruction::Trunc: { + // If the input contained enough sign bits that some remain after the + // truncation, then we can make use of that. Otherwise we don't know + // anything. + Tmp = ComputeNumSignBits(U->getOperand(0), Depth + 1, Q); + unsigned OperandTyBits = U->getOperand(0)->getType()->getScalarSizeInBits(); + if (Tmp > (OperandTyBits - TyBits)) + return Tmp - (OperandTyBits - TyBits); + + return 1; + } case Instruction::ExtractElement: // Look through extract element. At the moment we keep this simple and diff --git a/llvm/test/Transforms/InstCombine/high-bit-signmask-with-trunc.ll b/llvm/test/Transforms/InstCombine/high-bit-signmask-with-trunc.ll --- a/llvm/test/Transforms/InstCombine/high-bit-signmask-with-trunc.ll +++ b/llvm/test/Transforms/InstCombine/high-bit-signmask-with-trunc.ll @@ -138,7 +138,7 @@ ; CHECK-LABEL: @n10( ; CHECK-NEXT: [[T0_NEG:%.*]] = ashr i64 [[X:%.*]], 63 ; CHECK-NEXT: [[T1_NEG:%.*]] = trunc i64 [[T0_NEG]] to i32 -; CHECK-NEXT: [[R:%.*]] = add i32 [[T1_NEG]], 1 +; CHECK-NEXT: [[R:%.*]] = add nsw i32 [[T1_NEG]], 1 ; CHECK-NEXT: ret i32 [[R]] ; %t0 = lshr i64 %x, 63 diff --git a/llvm/test/Transforms/InstCombine/negated-bitmask.ll b/llvm/test/Transforms/InstCombine/negated-bitmask.ll --- a/llvm/test/Transforms/InstCombine/negated-bitmask.ll +++ b/llvm/test/Transforms/InstCombine/negated-bitmask.ll @@ -71,7 +71,7 @@ ; CHECK-NEXT: [[TMP1:%.*]] = shl i64 [[A0:%.*]], 48 ; CHECK-NEXT: [[TMP2:%.*]] = ashr i64 [[TMP1]], 63 ; CHECK-NEXT: [[TMP3:%.*]] = trunc i64 [[TMP2]] to i8 -; CHECK-NEXT: [[NEG:%.*]] = add i8 [[TMP3]], 10 +; CHECK-NEXT: [[NEG:%.*]] = add nsw i8 [[TMP3]], 10 ; CHECK-NEXT: ret i8 [[NEG]] ; %shift = lshr i64 %a0, 15 @@ -86,7 +86,7 @@ ; CHECK-NEXT: [[TMP1:%.*]] = shl i64 [[A0:%.*]], 48 ; CHECK-NEXT: [[TMP2:%.*]] = ashr i64 [[TMP1]], 63 ; CHECK-NEXT: [[TMP3:%.*]] = trunc i64 [[TMP2]] to i8 -; CHECK-NEXT: [[NARROW:%.*]] = add i8 [[TMP3]], 10 +; CHECK-NEXT: [[NARROW:%.*]] = add nsw i8 [[TMP3]], 10 ; CHECK-NEXT: [[NEG:%.*]] = zext i8 [[NARROW]] to i32 ; CHECK-NEXT: ret i32 [[NEG]] ; diff --git a/llvm/test/Transforms/InstCombine/vector-trunc.ll b/llvm/test/Transforms/InstCombine/vector-trunc.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/vector-trunc.ll @@ -0,0 +1,41 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -passes=instcombine -S | FileCheck %s + +define <4 x i16> @trunc_add_nsw(<4 x i32> %0) { +; CHECK-LABEL: @trunc_add_nsw( +; CHECK-NEXT: [[TMP2:%.*]] = ashr <4 x i32> [[TMP0:%.*]], +; CHECK-NEXT: [[TMP3:%.*]] = trunc <4 x i32> [[TMP2]] to <4 x i16> +; CHECK-NEXT: [[TMP4:%.*]] = add nsw <4 x i16> [[TMP3]], +; CHECK-NEXT: ret <4 x i16> [[TMP4]] +; + %2 = ashr <4 x i32> %0, + %3 = trunc <4 x i32> %2 to <4 x i16> + %4 = add <4 x i16> %3, + ret <4 x i16> %4 +} + +define <4 x i16> @trunc_add_no_nsw(<4 x i32> %0) { +; CHECK-LABEL: @trunc_add_no_nsw( +; CHECK-NEXT: [[TMP2:%.*]] = lshr <4 x i32> [[TMP0:%.*]], +; CHECK-NEXT: [[TMP3:%.*]] = trunc <4 x i32> [[TMP2]] to <4 x i16> +; CHECK-NEXT: [[TMP4:%.*]] = add <4 x i16> [[TMP3]], +; CHECK-NEXT: ret <4 x i16> [[TMP4]] +; + %2 = ashr <4 x i32> %0, + %3 = trunc <4 x i32> %2 to <4 x i16> + %4 = add <4 x i16> %3, + ret <4 x i16> %4 +} + +define <4 x i16> @trunc_add_mixed(<4 x i32> %0) { +; CHECK-LABEL: @trunc_add_mixed( +; CHECK-NEXT: [[TMP2:%.*]] = ashr <4 x i32> [[TMP0:%.*]], +; CHECK-NEXT: [[TMP3:%.*]] = trunc <4 x i32> [[TMP2]] to <4 x i16> +; CHECK-NEXT: [[TMP4:%.*]] = add <4 x i16> [[TMP3]], +; CHECK-NEXT: ret <4 x i16> [[TMP4]] +; + %2 = ashr <4 x i32> %0, + %3 = trunc <4 x i32> %2 to <4 x i16> + %4 = add <4 x i16> %3, + ret <4 x i16> %4 +}