[GlobalISel] Add known bits and sign-bits handling for G_SPLAT_VECTOR#140204
Conversation
|
@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.
d2af7d1 to
0a22c65
Compare
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.