[ValueTracking] Improve ComputeNumSignBits to handle Trunc
authorOwen Anderson <resistor@mac.com>
Sat, 31 Dec 2022 06:12:20 +0000 (23:12 -0700)
committerOwen Anderson <resistor@mac.com>
Tue, 3 Jan 2023 22:26:21 +0000 (15:26 -0700)
Reviewed By: nikic

Differential Revision: https://reviews.llvm.org/D140796

llvm/lib/Analysis/ValueTracking.cpp
llvm/test/Transforms/InstCombine/high-bit-signmask-with-trunc.ll
llvm/test/Transforms/InstCombine/negated-bitmask.ll
llvm/test/Transforms/InstCombine/vector-trunc.ll [new file with mode: 0644]

index b563154..d12e4c7 100644 (file)
@@ -3312,10 +3312,17 @@ static unsigned ComputeNumSignBitsImpl(const Value *V,
       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
index ec7c3c8..e87d909 100644 (file)
@@ -138,7 +138,7 @@ define i32 @n10(i64 %x) {
 ; 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
index a41a5d9..fdd8e7e 100644 (file)
@@ -71,7 +71,7 @@ define i8 @sub_mask1_trunc_lshr(i64 %a0) {
 ; 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 @@ define i32 @sub_sext_mask1_trunc_lshr(i64 %a0) {
 ; 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 (file)
index 0000000..eeb5a3f
--- /dev/null
@@ -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:%.*]], <i32 17, i32 17, i32 17, i32 17>
+; CHECK-NEXT:    [[TMP3:%.*]] = trunc <4 x i32> [[TMP2]] to <4 x i16>
+; CHECK-NEXT:    [[TMP4:%.*]] = add nsw <4 x i16> [[TMP3]], <i16 1, i16 1, i16 1, i16 1>
+; CHECK-NEXT:    ret <4 x i16> [[TMP4]]
+;
+  %2 = ashr <4 x i32> %0, <i32 17, i32 17, i32 17, i32 17>
+  %3 = trunc <4 x i32> %2 to <4 x i16>
+  %4 = add <4 x i16> %3, <i16 1, i16 1, i16 1, i16 1>
+  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:%.*]], <i32 16, i32 16, i32 16, i32 16>
+; CHECK-NEXT:    [[TMP3:%.*]] = trunc <4 x i32> [[TMP2]] to <4 x i16>
+; CHECK-NEXT:    [[TMP4:%.*]] = add <4 x i16> [[TMP3]], <i16 1, i16 1, i16 1, i16 1>
+; CHECK-NEXT:    ret <4 x i16> [[TMP4]]
+;
+  %2 = ashr <4 x i32> %0, <i32 16, i32 16, i32 16, i32 16>
+  %3 = trunc <4 x i32> %2 to <4 x i16>
+  %4 = add <4 x i16> %3, <i16 1, i16 1, i16 1, i16 1>
+  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:%.*]], <i32 17, i32 16, i32 17, i32 16>
+; CHECK-NEXT:    [[TMP3:%.*]] = trunc <4 x i32> [[TMP2]] to <4 x i16>
+; CHECK-NEXT:    [[TMP4:%.*]] = add <4 x i16> [[TMP3]], <i16 1, i16 1, i16 1, i16 1>
+; CHECK-NEXT:    ret <4 x i16> [[TMP4]]
+;
+  %2 = ashr <4 x i32> %0, <i32 17, i32 16, i32 17, i32 16>
+  %3 = trunc <4 x i32> %2 to <4 x i16>
+  %4 = add <4 x i16> %3, <i16 1, i16 1, i16 1, i16 1>
+  ret <4 x i16> %4
+}