Skip to content

Conversation

@davemgreen
Copy link
Collaborator

This forwards the KnownBits / SignBits from the scalar operand through to the vector elements. The value is implicitly truncated if it is larger than the vector element size. The change in GISelValueTracking::computeNumSignBits allows scalable sign-bits using a single element demanded elts, and brings it in line with what is done in ValueTracking and SDAG (and GISelValueTracking::getKnownBits). That was my main reason for adding this opcode, to prevent scalable vector asserts.

@llvmbot
Copy link
Member

llvmbot commented May 16, 2025

@llvm/pr-subscribers-llvm-globalisel

Author: David Green (davemgreen)

Changes

This forwards the KnownBits / SignBits from the scalar operand through to the vector elements. The value is implicitly truncated if it is larger than the vector element size. The change in GISelValueTracking::computeNumSignBits allows scalable sign-bits using a single element demanded elts, and brings it in line with what is done in ValueTracking and SDAG (and GISelValueTracking::getKnownBits). That was my main reason for adding this opcode, to prevent scalable vector asserts.


Full diff: https://github.com/llvm/llvm-project/pull/140204.diff

2 Files Affected:

  • (modified) llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp (+18-1)
  • (added) llvm/test/CodeGen/AArch64/GlobalISel/knownbits-sve-splat.mir (+35)
diff --git a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
index 589936b6c260f..fd42b85251398 100644
--- a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
@@ -222,6 +222,14 @@ void GISelValueTracking::computeKnownBitsImpl(Register R, KnownBits &Known,
     }
     break;
   }
+  case TargetOpcode::G_SPLAT_VECTOR: {
+    computeKnownBitsImpl(MI.getOperand(1).getReg(), Known, APInt(1, 1),
+                         Depth + 1);
+    // Implicitly truncate the bits to match the official semantics of
+    // G_SPLAT_VECTOR.
+    Known = Known.trunc(BitWidth);
+    break;
+  }
   case TargetOpcode::COPY:
   case TargetOpcode::G_PHI:
   case TargetOpcode::PHI: {
@@ -854,6 +862,15 @@ unsigned GISelValueTracking::computeNumSignBits(Register R,
     }
     break;
   }
+  case TargetOpcode::G_SPLAT_VECTOR: {
+    // Check if the sign bits of source go down as far as the truncated value.
+    Register Src = MI.getOperand(1).getReg();
+    unsigned NumSrcSignBits = computeNumSignBits(Src, APInt(1, 1), Depth + 1);
+    unsigned NumSrcBits = MRI.getType(Src).getSizeInBits();
+    if (NumSrcSignBits > (NumSrcBits - TyBits))
+      return NumSrcSignBits - (NumSrcBits - TyBits);
+    break;
+  }
   case TargetOpcode::G_INTRINSIC:
   case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
   case TargetOpcode::G_INTRINSIC_CONVERGENT:
@@ -889,7 +906,7 @@ unsigned GISelValueTracking::computeNumSignBits(Register R,
 unsigned GISelValueTracking::computeNumSignBits(Register R, unsigned Depth) {
   LLT Ty = MRI.getType(R);
   APInt DemandedElts =
-      Ty.isVector() ? APInt::getAllOnes(Ty.getNumElements()) : APInt(1, 1);
+      Ty.isFixedVector() ? APInt::getAllOnes(Ty.getNumElements()) : APInt(1, 1);
   return computeNumSignBits(R, DemandedElts, Depth);
 }
 
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-sve-splat.mir b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-sve-splat.mir
new file mode 100644
index 0000000000000..27c11ee1641e9
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-sve-splat.mir
@@ -0,0 +1,35 @@
+# NOTE: Assertions have been autogenerated by utils/update_givaluetracking_test_checks.py UTC_ARGS: --version 5
+# RUN: llc -mtriple aarch64 -mattr=+sve -passes="print<gisel-value-tracking>" %s -o - 2>&1 | FileCheck %s
+
+---
+name:            Scalable
+body:             |
+  bb.1:
+  ; CHECK-LABEL: name: @Scalable
+  ; CHECK-NEXT: %0:_ KnownBits:0000000000001010 SignBits:12
+  ; CHECK-NEXT: %1:_ KnownBits:0000000000001010 SignBits:12
+    %0:_(s16) = G_CONSTANT i16 10
+    %1:_(<vscale x 8 x s16>) = G_SPLAT_VECTOR %0(s16)
+...
+---
+name:            Scalable_trunc
+body:             |
+  bb.1:
+  ; CHECK-LABEL: name: @Scalable_trunc
+  ; CHECK-NEXT: %0:_ KnownBits:00000000000000000000000000001010 SignBits:28
+  ; CHECK-NEXT: %1:_ KnownBits:0000000000001010 SignBits:12
+    %0:_(s32) = G_CONSTANT i32 10
+    %1:_(<vscale x 8 x s16>) = G_SPLAT_VECTOR %0(s32)
+...
+---
+name:            Scalable_signbits
+body:             |
+  bb.1:
+  ; CHECK-LABEL: name: @Scalable_signbits
+  ; CHECK-NEXT: %0:_ KnownBits:???????????????? SignBits:1
+  ; CHECK-NEXT: %1:_ KnownBits:???????????????????????????????? SignBits:17
+  ; CHECK-NEXT: %2:_ KnownBits:???????????????????????????????? SignBits:17
+    %0:_(s16) = COPY $h0
+    %1:_(s32) = G_SEXT %0(s16)
+    %2:_(<vscale x 4 x s32>) = G_SPLAT_VECTOR %1(s32)
+...

@llvmbot
Copy link
Member

llvmbot commented May 16, 2025

@llvm/pr-subscribers-backend-aarch64

Author: David Green (davemgreen)

Changes

This forwards the KnownBits / SignBits from the scalar operand through to the vector elements. The value is implicitly truncated if it is larger than the vector element size. The change in GISelValueTracking::computeNumSignBits allows scalable sign-bits using a single element demanded elts, and brings it in line with what is done in ValueTracking and SDAG (and GISelValueTracking::getKnownBits). That was my main reason for adding this opcode, to prevent scalable vector asserts.


Full diff: https://github.com/llvm/llvm-project/pull/140204.diff

2 Files Affected:

  • (modified) llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp (+18-1)
  • (added) llvm/test/CodeGen/AArch64/GlobalISel/knownbits-sve-splat.mir (+35)
diff --git a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
index 589936b6c260f..fd42b85251398 100644
--- a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
@@ -222,6 +222,14 @@ void GISelValueTracking::computeKnownBitsImpl(Register R, KnownBits &Known,
     }
     break;
   }
+  case TargetOpcode::G_SPLAT_VECTOR: {
+    computeKnownBitsImpl(MI.getOperand(1).getReg(), Known, APInt(1, 1),
+                         Depth + 1);
+    // Implicitly truncate the bits to match the official semantics of
+    // G_SPLAT_VECTOR.
+    Known = Known.trunc(BitWidth);
+    break;
+  }
   case TargetOpcode::COPY:
   case TargetOpcode::G_PHI:
   case TargetOpcode::PHI: {
@@ -854,6 +862,15 @@ unsigned GISelValueTracking::computeNumSignBits(Register R,
     }
     break;
   }
+  case TargetOpcode::G_SPLAT_VECTOR: {
+    // Check if the sign bits of source go down as far as the truncated value.
+    Register Src = MI.getOperand(1).getReg();
+    unsigned NumSrcSignBits = computeNumSignBits(Src, APInt(1, 1), Depth + 1);
+    unsigned NumSrcBits = MRI.getType(Src).getSizeInBits();
+    if (NumSrcSignBits > (NumSrcBits - TyBits))
+      return NumSrcSignBits - (NumSrcBits - TyBits);
+    break;
+  }
   case TargetOpcode::G_INTRINSIC:
   case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
   case TargetOpcode::G_INTRINSIC_CONVERGENT:
@@ -889,7 +906,7 @@ unsigned GISelValueTracking::computeNumSignBits(Register R,
 unsigned GISelValueTracking::computeNumSignBits(Register R, unsigned Depth) {
   LLT Ty = MRI.getType(R);
   APInt DemandedElts =
-      Ty.isVector() ? APInt::getAllOnes(Ty.getNumElements()) : APInt(1, 1);
+      Ty.isFixedVector() ? APInt::getAllOnes(Ty.getNumElements()) : APInt(1, 1);
   return computeNumSignBits(R, DemandedElts, Depth);
 }
 
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-sve-splat.mir b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-sve-splat.mir
new file mode 100644
index 0000000000000..27c11ee1641e9
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-sve-splat.mir
@@ -0,0 +1,35 @@
+# NOTE: Assertions have been autogenerated by utils/update_givaluetracking_test_checks.py UTC_ARGS: --version 5
+# RUN: llc -mtriple aarch64 -mattr=+sve -passes="print<gisel-value-tracking>" %s -o - 2>&1 | FileCheck %s
+
+---
+name:            Scalable
+body:             |
+  bb.1:
+  ; CHECK-LABEL: name: @Scalable
+  ; CHECK-NEXT: %0:_ KnownBits:0000000000001010 SignBits:12
+  ; CHECK-NEXT: %1:_ KnownBits:0000000000001010 SignBits:12
+    %0:_(s16) = G_CONSTANT i16 10
+    %1:_(<vscale x 8 x s16>) = G_SPLAT_VECTOR %0(s16)
+...
+---
+name:            Scalable_trunc
+body:             |
+  bb.1:
+  ; CHECK-LABEL: name: @Scalable_trunc
+  ; CHECK-NEXT: %0:_ KnownBits:00000000000000000000000000001010 SignBits:28
+  ; CHECK-NEXT: %1:_ KnownBits:0000000000001010 SignBits:12
+    %0:_(s32) = G_CONSTANT i32 10
+    %1:_(<vscale x 8 x s16>) = G_SPLAT_VECTOR %0(s32)
+...
+---
+name:            Scalable_signbits
+body:             |
+  bb.1:
+  ; CHECK-LABEL: name: @Scalable_signbits
+  ; CHECK-NEXT: %0:_ KnownBits:???????????????? SignBits:1
+  ; CHECK-NEXT: %1:_ KnownBits:???????????????????????????????? SignBits:17
+  ; CHECK-NEXT: %2:_ KnownBits:???????????????????????????????? SignBits:17
+    %0:_(s16) = COPY $h0
+    %1:_(s32) = G_SEXT %0(s16)
+    %2:_(<vscale x 4 x s32>) = G_SPLAT_VECTOR %1(s32)
+...

This forwards the KnownBits / SignBits from the scalar operand through to the
vector elements. The value is implicitly truncated if it is larger than the
vector element size.  The change in GISelValueTracking::computeNumSignBits
allows scalable sign-bits using a single element demanded elts, and brings it
in line with what is done in ValueTracking and SDAG (and
GISelValueTracking::getKnownBits). That was my main reason for adding this
opcode, to prevent scalable vector asserts.
@davemgreen davemgreen force-pushed the gh-gi-knownbits-splat branch from d2af7d1 to 0a22c65 Compare May 20, 2025 11:26
@davemgreen davemgreen merged commit 85a6bed into llvm:main May 20, 2025
6 of 10 checks passed
@davemgreen davemgreen deleted the gh-gi-knownbits-splat branch May 20, 2025 11:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants