diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index 35123474381e7..ee893d8e384b6 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 ` or :ref:`ptrtoint ` instructions first. There is a caveat for bitcasts involving vector types in relation to -endianess. For example ``bitcast <2 x i8> to i16`` puts element zero +endianness. For example ``bitcast <2 x i8> 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 73438113651f5..20ad4c766a1a3 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(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 e831316efff52..3f06d0bd4eaa1 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 61cfcdc914cdb..70629b2a50a98 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) &&