Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

[GlobalISel] Add known bits and sign-bits handling for G_SPLAT_VECTOR #140204

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
Loading
from

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.

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)
+...

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
Morty Proxy This is a proxified and sanitized view of the page, visit original site.