[llvm] 4acb96c - [SelectionDAG] Tidy up around endianness and isConstantSplat (#68212)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Oct 16 05:53:57 PDT 2023
Author: Björn Pettersson
Date: 2023-10-16T14:53:53+02:00
New Revision: 4acb96c99f3b9c414f403f6e1ab2b317851abf0f
URL: https://github.com/llvm/llvm-project/commit/4acb96c99f3b9c414f403f6e1ab2b317851abf0f
DIFF: https://github.com/llvm/llvm-project/commit/4acb96c99f3b9c414f403f6e1ab2b317851abf0f.diff
LOG: [SelectionDAG] Tidy up around endianness and isConstantSplat (#68212)
The BuildVectorSDNode::isConstantSplat function could depend on
endianness, and it takes a bool argument that can be used to indicate
if big or little endian should be considered when internally casting
from a vector to a scalar. However, that argument is default set to
false (= little endian). And in many situations, even in target
generic code such as DAGCombiner, the endianness isn't specified when
using the function.
The intent with this patch is to highlight that endianness doesn't
matter, depending on the context in which the function is used.
In DAGCombiner the code is slightly refactored. Back in the days when
the code was written it wasn't possible to request a MinSplatBits
size when calling isConstantSplat. Instead the code re-expanded the
found SplatValue to match with the EltBitWidth. Now we can just
provide EltBitWidth as MinSplatBits and remove the logic for doing
the re-expand.
While being at it, tidying up around isConstantSplat, this patch also
adds an explicit check in BuildVectorSDNode::isConstantSplat to break
out from the loop if trying to split an on VecWidth into two halves.
Haven't been able to prove that there could be miscompiles involved
if not doing so. There are lit tests that trigger that scenario,
although I think they happen to later discard the returned SplatValue
for other reasons.
Added:
Modified:
llvm/docs/LangRef.rst
llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
Removed:
################################################################################
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 35123474381e7d6..ee893d8e384b6fd 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -3888,7 +3888,7 @@ integer to memory.
A bitcast from a vector type to a scalar integer type will see the elements
being packed together (without padding). The order in which elements are
-inserted in the integer depends on endianess. For little endian element zero
+inserted in the integer depends on endianness. For little endian element zero
is put in the least significant bits of the integer, and for big endian
element zero is put in the most significant bits.
@@ -11677,7 +11677,7 @@ To convert pointers to other types, use the :ref:`inttoptr <i_inttoptr>`
or :ref:`ptrtoint <i_ptrtoint>` instructions first.
There is a caveat for bitcasts involving vector types in relation to
-endianess. For example ``bitcast <2 x i8> <value> to i16`` puts element zero
+endianness. For example ``bitcast <2 x i8> <value> to i16`` puts element zero
of the vector in the least significant bits of the i16 for little-endian while
element zero ends up in the most significant bits for big-endian.
@@ -11686,9 +11686,9 @@ Example:
.. code-block:: text
- %X = bitcast i8 255 to i8 ; yields i8 :-1
- %Y = bitcast i32* %x to i16* ; yields i16*:%x
- %Z = bitcast <2 x i32> %V to i64; ; yields i64: %V (depends on endianess)
+ %X = bitcast i8 255 to i8 ; yields i8 :-1
+ %Y = bitcast i32* %x to i16* ; yields i16*:%x
+ %Z = bitcast <2 x i32> %V to i64; ; yields i64: %V (depends on endianness)
%Z = bitcast <2 x i32*> %V to <2 x i64*> ; yields <2 x i64*>
.. _i_addrspacecast:
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 73438113651f55d..20ad4c766a1a3fc 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -7076,12 +7076,23 @@ SDValue DAGCombiner::visitAND(SDNode *N) {
N1, /*AllowUndef=*/false, /*AllowTruncation=*/true)) {
Constant = C->getAPIntValue();
} else if (BuildVectorSDNode *Vector = dyn_cast<BuildVectorSDNode>(N1)) {
+ unsigned EltBitWidth = Vector->getValueType(0).getScalarSizeInBits();
APInt SplatValue, SplatUndef;
unsigned SplatBitSize;
bool HasAnyUndefs;
- bool IsSplat = Vector->isConstantSplat(SplatValue, SplatUndef,
- SplatBitSize, HasAnyUndefs);
- if (IsSplat) {
+ // Endianness should not matter here. Code below makes sure that we only
+ // use the result if the SplatBitSize is a multiple of the vector element
+ // size. And after that we AND all element sized parts of the splat
+ // together. So the end result should be the same regardless of in which
+ // order we do those operations.
+ const bool IsBigEndian = false;
+ bool IsSplat =
+ Vector->isConstantSplat(SplatValue, SplatUndef, SplatBitSize,
+ HasAnyUndefs, EltBitWidth, IsBigEndian);
+
+ // Make sure that variable 'Constant' is only set if 'SplatBitSize' is a
+ // multiple of 'BitWidth'. Otherwise, we could propagate a wrong value.
+ if (IsSplat && (SplatBitSize % EltBitWidth) == 0) {
// Undef bits can contribute to a possible optimisation if set, so
// set them.
SplatValue |= SplatUndef;
@@ -7090,23 +7101,9 @@ SDValue DAGCombiner::visitAND(SDNode *N) {
// the first vector value and FF for the rest, repeating. We need a mask
// that will apply equally to all members of the vector, so AND all the
// lanes of the constant together.
- unsigned EltBitWidth = Vector->getValueType(0).getScalarSizeInBits();
-
- // If the splat value has been compressed to a bitlength lower
- // than the size of the vector lane, we need to re-expand it to
- // the lane size.
- if (EltBitWidth > SplatBitSize)
- for (SplatValue = SplatValue.zextOrTrunc(EltBitWidth);
- SplatBitSize < EltBitWidth; SplatBitSize = SplatBitSize * 2)
- SplatValue |= SplatValue.shl(SplatBitSize);
-
- // Make sure that variable 'Constant' is only set if 'SplatBitSize' is a
- // multiple of 'BitWidth'. Otherwise, we could propagate a wrong value.
- if ((SplatBitSize % EltBitWidth) == 0) {
- Constant = APInt::getAllOnes(EltBitWidth);
- for (unsigned i = 0, n = (SplatBitSize / EltBitWidth); i < n; ++i)
- Constant &= SplatValue.extractBits(EltBitWidth, i * EltBitWidth);
- }
+ Constant = APInt::getAllOnes(EltBitWidth);
+ for (unsigned i = 0, n = (SplatBitSize / EltBitWidth); i < n; ++i)
+ Constant &= SplatValue.extractBits(EltBitWidth, i * EltBitWidth);
}
}
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index e831316efff52ba..3f06d0bd4eaa1d5 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -161,8 +161,13 @@ bool ISD::isConstantSplatVector(const SDNode *N, APInt &SplatVal) {
unsigned SplatBitSize;
bool HasUndefs;
unsigned EltSize = N->getValueType(0).getVectorElementType().getSizeInBits();
+ // Endianness does not matter here. We are checking for a splat given the
+ // element size of the vector, and if we find such a splat for little endian
+ // layout, then that should be valid also for big endian (as the full vector
+ // size is known to be a multiple of the element size).
+ const bool IsBigEndian = false;
return BV->isConstantSplat(SplatVal, SplatUndef, SplatBitSize, HasUndefs,
- EltSize) &&
+ EltSize, IsBigEndian) &&
EltSize == SplatBitSize;
}
@@ -12357,6 +12362,10 @@ bool BuildVectorSDNode::isConstantSplat(APInt &SplatValue, APInt &SplatUndef,
// FIXME: This does not work for vectors with elements less than 8 bits.
while (VecWidth > 8) {
+ // If we can't split in half, stop here.
+ if (VecWidth & 1)
+ break;
+
unsigned HalfSize = VecWidth / 2;
APInt HighValue = SplatValue.extractBits(HalfSize, HalfSize);
APInt LowValue = SplatValue.extractBits(HalfSize, 0);
@@ -12374,6 +12383,12 @@ bool BuildVectorSDNode::isConstantSplat(APInt &SplatValue, APInt &SplatUndef,
VecWidth = HalfSize;
}
+ // FIXME: The loop above only tries to split in halves. But if the input
+ // vector for example is <3 x i16> it wouldn't be able to detect a
+ // SplatBitSize of 16. No idea if that is a design flaw currently limiting
+ // optimizations. I guess that back in the days when this helper was created
+ // vectors normally was power-of-2 sized.
+
SplatBitSize = VecWidth;
return true;
}
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
index 61cfcdc914cdb93..70629b2a50a982a 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
@@ -2576,6 +2576,8 @@ performVectorTruncZeroCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI) {
APInt SplatValue, SplatUndef;
unsigned SplatBitSize;
bool HasAnyUndefs;
+ // Endianness doesn't matter in this context because we are looking for
+ // an all-zero value.
return Splat &&
Splat->isConstantSplat(SplatValue, SplatUndef, SplatBitSize,
HasAnyUndefs) &&
More information about the llvm-commits
mailing list