-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[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
base: main
Are you sure you want to change the base?
Conversation
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.
@llvm/pr-subscribers-llvm-globalisel Author: David Green (davemgreen) ChangesThis 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:
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)
+...
|
@llvm/pr-subscribers-backend-aarch64 Author: David Green (davemgreen) ChangesThis 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:
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.