[llvm] 5492150 - [ConstantFold] Support byte values in `bitcast` constant folding (#188030)
via llvm-commits
llvm-commits at lists.llvm.org
Sun Apr 19 11:58:23 PDT 2026
Author: Pedro Lobo
Date: 2026-04-19T19:58:19+01:00
New Revision: 5492150b2078f03c9c1942c13f6d0428a530e165
URL: https://github.com/llvm/llvm-project/commit/5492150b2078f03c9c1942c13f6d0428a530e165
DIFF: https://github.com/llvm/llvm-project/commit/5492150b2078f03c9c1942c13f6d0428a530e165.diff
LOG: [ConstantFold] Support byte values in `bitcast` constant folding (#188030)
Add support for constant folding `bitcast` instructions including
`ConstantByte` values. This patch handles bitcasts between byte types
and integer, FP, and other byte types in both directions.
`poison` source bytes are preserved, rather than letting the generic
integer fold refine them to `undef` or zero. This is because some
threading optimizations just compare the result of constant folding
(e.g., https://github.com/llvm/llvm-project/pull/114280).
Folds are skipped for byte `bitcast`s where element counts don't divide
evenly and the source contains `poison` values. Some of these casts can
be folded. However, this is left for a future PR.
Added:
Modified:
llvm/lib/Analysis/ConstantFolding.cpp
llvm/lib/IR/ConstantFold.cpp
llvm/test/Transforms/InstSimplify/bitcast-vector-fold.ll
Removed:
################################################################################
diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp
index cb8ecc3872c0c..91d9f3fb34a03 100644
--- a/llvm/lib/Analysis/ConstantFolding.cpp
+++ b/llvm/lib/Analysis/ConstantFolding.cpp
@@ -22,6 +22,7 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallBitVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Analysis/TargetFolder.h"
@@ -105,6 +106,76 @@ static Constant *foldConstVectorToAPInt(APInt &Result, Type *DestTy,
return nullptr;
}
+/// Check whether folding this bitcast into a byte vector would mix poison and
+/// non-poison bits in the same output lane. While integer types track poison on
+/// a per-value basis, byte types track it on a per-bit basis. However,
+/// `ConstantByte` cannot represent values with both poison and non-poison bits.
+///
+/// Source elements are grouped by the output lane they map to. Returns true if
+/// any group contains both poison and non-poison elements.
+static bool foldMixesPoisonBits(Constant *C, unsigned NumSrcElt,
+ unsigned NumDstElt) {
+ // If element counts don't divide evenly, bail out if a poison source element
+ // might span multiple destination lanes.
+ if (NumSrcElt % NumDstElt != 0)
+ return C->containsPoisonElement();
+ unsigned Ratio = NumSrcElt / NumDstElt;
+ for (unsigned i = 0; i != NumSrcElt; i += Ratio) {
+ bool HasPoison = false;
+ bool HasNonPoison = false;
+ for (unsigned j = 0; j != Ratio; ++j) {
+ Constant *Src = C->getAggregateElement(i + j);
+ // Conservatively bail out.
+ if (!Src)
+ return true;
+ if (isa<PoisonValue>(Src))
+ HasPoison = true;
+ else
+ HasNonPoison = true;
+ }
+ if (HasPoison && HasNonPoison)
+ return true;
+ }
+ return false;
+}
+
+/// Track which destination lanes of a bitcast are produced from poison bytes.
+/// A destination lane is marked if any source element mapped to it is poison.
+/// Returns false if an aggregate element cannot be inspected. The caller should
+/// bail out of folding.
+static bool computePoisonDstLanes(Constant *C, unsigned NumSrcElt,
+ unsigned NumDstElt,
+ SmallBitVector &PoisonDstElts) {
+ // If element counts don't divide evenly, bail out if a poison source element
+ // might span multiple destination lanes.
+ if ((NumDstElt < NumSrcElt ? NumSrcElt % NumDstElt : NumDstElt % NumSrcElt))
+ return !C->containsPoisonElement();
+ if (NumDstElt < NumSrcElt) {
+ unsigned Ratio = NumSrcElt / NumDstElt;
+ for (unsigned i = 0; i != NumDstElt; ++i) {
+ for (unsigned j = 0; j != Ratio; ++j) {
+ Constant *Src = C->getAggregateElement(i * Ratio + j);
+ if (!Src)
+ return false;
+ if (isa<PoisonValue>(Src)) {
+ PoisonDstElts[i] = true;
+ break;
+ }
+ }
+ }
+ } else {
+ unsigned Ratio = NumDstElt / NumSrcElt;
+ for (unsigned i = 0; i != NumSrcElt; ++i) {
+ Constant *Src = C->getAggregateElement(i);
+ if (!Src)
+ return false;
+ if (isa<PoisonValue>(Src))
+ PoisonDstElts.set(i * Ratio, (i + 1) * Ratio);
+ }
+ }
+ return true;
+}
+
/// Constant fold bitcast, symbolically evaluating it with DataLayout.
/// This always returns a non-null constant, but it may be a
/// ConstantExpr if unfoldable.
@@ -122,12 +193,17 @@ Constant *FoldBitCast(Constant *C, Type *DestTy, const DataLayout &DL) {
unsigned NumSrcElts = cast<FixedVectorType>(VTy)->getNumElements();
Type *SrcEltTy = VTy->getElementType();
- // If the vector is a vector of floating point, convert it to vector of int
- // to simplify things.
- if (SrcEltTy->isFloatingPointTy()) {
- unsigned FPWidth = SrcEltTy->getPrimitiveSizeInBits();
+ // Bitcasting a byte containing any poison bit to an integer or fp type
+ // yields poison.
+ if (SrcEltTy->isByteTy() && C->containsPoisonElement())
+ return PoisonValue::get(DestTy);
+
+ // If the vector is a vector of floating point or bytes, convert it to a
+ // vector of int to simplify things.
+ if (SrcEltTy->isFloatingPointTy() || SrcEltTy->isByteTy()) {
+ unsigned Width = SrcEltTy->getPrimitiveSizeInBits();
auto *SrcIVTy = FixedVectorType::get(
- IntegerType::get(C->getContext(), FPWidth), NumSrcElts);
+ IntegerType::get(C->getContext(), Width), NumSrcElts);
// Ask IR to do the conversion now that #elts line up.
C = ConstantExpr::getBitCast(C, SrcIVTy);
}
@@ -153,7 +229,7 @@ Constant *FoldBitCast(Constant *C, Type *DestTy, const DataLayout &DL) {
// If this is a scalar -> vector cast, convert the input into a <1 x scalar>
// vector so the code below can handle it uniformly.
if (!isa<VectorType>(C->getType()) &&
- (isa<ConstantFP>(C) || isa<ConstantInt>(C))) {
+ (isa<ConstantFP>(C) || isa<ConstantInt>(C) || isa<ConstantByte>(C))) {
Constant *Ops = C; // don't take the address of C!
return FoldBitCast(ConstantVector::get(Ops), DestTy, DL);
}
@@ -165,7 +241,7 @@ Constant *FoldBitCast(Constant *C, Type *DestTy, const DataLayout &DL) {
// If this is a bitcast from constant vector -> vector, fold it.
if (!isa<ConstantDataVector>(C) && !isa<ConstantVector>(C) &&
- !isa<ConstantInt>(C) && !isa<ConstantFP>(C))
+ !isa<ConstantInt>(C) && !isa<ConstantFP>(C) && !isa<ConstantByte>(C))
return ConstantExpr::getBitCast(C, DestTy);
// If the element types match, IR can fold it.
@@ -199,6 +275,22 @@ Constant *FoldBitCast(Constant *C, Type *DestTy, const DataLayout &DL) {
return ConstantExpr::getBitCast(C, DestTy);
}
+ // Handle byte destination type by folding through integers.
+ if (DstEltTy->isByteTy()) {
+ // When combining elements into larger byte values, bail out if the fold
+ // mixes poison and non-poison bits in the same destination element. Byte
+ // types track poison per bit, and no constant value can represent that.
+ if (NumDstElt < NumSrcElt && foldMixesPoisonBits(C, NumSrcElt, NumDstElt))
+ return ConstantExpr::getBitCast(C, DestTy);
+
+ // Fold to a vector of integers with same size as the byte type.
+ unsigned ByteWidth = DstEltTy->getPrimitiveSizeInBits();
+ auto *DestIVTy = FixedVectorType::get(
+ IntegerType::get(C->getContext(), ByteWidth), NumDstElt);
+ C = FoldBitCast(C, DestIVTy, DL);
+ return ConstantExpr::getBitCast(C, DestTy);
+ }
+
// Okay, we know the destination is integer, if the input is FP, convert
// it to integer first.
if (SrcEltTy->isFloatingPointTy()) {
@@ -212,6 +304,25 @@ Constant *FoldBitCast(Constant *C, Type *DestTy, const DataLayout &DL) {
"Constant folding cannot fail for plain fp->int bitcast!");
}
+ // Handle byte source type by folding through integers. Byte types track
+ // poison per bit, so any poison bit makes the destination lane poison.
+ // Record which destination lanes contain poison bits, before the generic
+ // fold below refines them to undef/zero, so they can be restored.
+ SmallBitVector PoisonDstElts(NumDstElt);
+ if (SrcEltTy->isByteTy()) {
+ if (!computePoisonDstLanes(C, NumSrcElt, NumDstElt, PoisonDstElts))
+ return ConstantExpr::getBitCast(C, DestTy);
+
+ unsigned ByteWidth = SrcEltTy->getPrimitiveSizeInBits();
+ auto *SrcIVTy = FixedVectorType::get(
+ IntegerType::get(C->getContext(), ByteWidth), NumSrcElt);
+ // Ask IR to do the conversion now that #elts line up.
+ C = ConstantExpr::getBitCast(C, SrcIVTy);
+ assert((isa<ConstantVector>(C) || // FIXME: Remove ConstantVector.
+ isa<ConstantDataVector>(C) || isa<ConstantInt>(C)) &&
+ "Constant folding cannot fail for plain byte->int bitcast!");
+ }
+
// Now we know that the input and output vectors are both integer vectors
// of the same size, and that their #elements is not the same.
// Use data buffer for easy non-integer element ratio vectors handling,
@@ -288,6 +399,10 @@ Constant *FoldBitCast(Constant *C, Type *DestTy, const DataLayout &DL) {
}
}
+ // Restore destination lanes whose source bytes contained poison bits.
+ for (unsigned I : PoisonDstElts.set_bits())
+ Result[I] = PoisonValue::get(DstEltTy);
+
return ConstantVector::get(Result);
}
diff --git a/llvm/lib/IR/ConstantFold.cpp b/llvm/lib/IR/ConstantFold.cpp
index 87a70391fbec4..ef87b1037beb6 100644
--- a/llvm/lib/IR/ConstantFold.cpp
+++ b/llvm/lib/IR/ConstantFold.cpp
@@ -68,7 +68,7 @@ static Constant *FoldBitCast(Constant *V, Type *DestTy) {
if (V->isAllOnesValue())
return Constant::getAllOnesValue(DestTy);
- // Handle ConstantInt -> ConstantFP
+ // Handle ConstantInt -> Constant{Byte, FP}
if (ConstantInt *CI = dyn_cast<ConstantInt>(V)) {
// Canonicalize scalar-to-vector bitcasts into vector-to-vector bitcasts
// This allows for other simplifications (although some of them
@@ -76,18 +76,45 @@ static Constant *FoldBitCast(Constant *V, Type *DestTy) {
if (isa<VectorType>(DestTy) && !isa<VectorType>(SrcTy))
return ConstantExpr::getBitCast(ConstantVector::get(V), DestTy);
+ if (DestTy->isByteOrByteVectorTy() &&
+ DestTy->getScalarSizeInBits() == SrcTy->getScalarSizeInBits())
+ return ConstantByte::get(DestTy, CI->getValue());
+
// Make sure dest type is compatible with the folded fp constant.
// See note below regarding the PPC_FP128 restriction.
- if (!DestTy->isFPOrFPVectorTy() || DestTy->isPPC_FP128Ty() ||
- DestTy->getScalarSizeInBits() != SrcTy->getScalarSizeInBits())
- return nullptr;
+ if (DestTy->isFPOrFPVectorTy() && !DestTy->isPPC_FP128Ty() &&
+ DestTy->getScalarSizeInBits() == SrcTy->getScalarSizeInBits())
+ return ConstantFP::get(
+ DestTy,
+ APFloat(DestTy->getScalarType()->getFltSemantics(), CI->getValue()));
- return ConstantFP::get(
- DestTy,
- APFloat(DestTy->getScalarType()->getFltSemantics(), CI->getValue()));
+ return nullptr;
}
- // Handle ConstantFP -> Constant{Int, FP}
+ // Handle ConstantByte -> Constant{Int, FP}
+ if (ConstantByte *CB = dyn_cast<ConstantByte>(V)) {
+ // Canonicalize scalar-to-vector bitcasts into vector-to-vector bitcasts
+ // This allows for other simplifications (although some of them
+ // can only be handled by Analysis/ConstantFolding.cpp).
+ if (isa<VectorType>(DestTy) && !isa<VectorType>(SrcTy))
+ return ConstantExpr::getBitCast(ConstantVector::get(V), DestTy);
+
+ if (DestTy->isIntOrIntVectorTy() &&
+ DestTy->getScalarSizeInBits() == SrcTy->getScalarSizeInBits())
+ return ConstantInt::get(DestTy, CB->getValue());
+
+ // Make sure dest type is compatible with the folded fp constant.
+ // See note below regarding the PPC_FP128 restriction.
+ if (DestTy->isFPOrFPVectorTy() && !DestTy->isPPC_FP128Ty() &&
+ DestTy->getScalarSizeInBits() == SrcTy->getScalarSizeInBits())
+ return ConstantFP::get(
+ DestTy,
+ APFloat(DestTy->getScalarType()->getFltSemantics(), CB->getValue()));
+
+ return nullptr;
+ }
+
+ // Handle ConstantFP -> Constant{Int, Byte, FP}
if (ConstantFP *FP = dyn_cast<ConstantFP>(V)) {
// Handle half <-> bfloat
if (!isa<VectorType>(SrcTy) && DestTy->isFloatingPointTy()) {
@@ -111,11 +138,16 @@ static Constant *FoldBitCast(Constant *V, Type *DestTy) {
return nullptr;
// Make sure dest type is compatible with the folded integer constant.
- if (!DestTy->isIntOrIntVectorTy() ||
- DestTy->getScalarSizeInBits() != SrcTy->getScalarSizeInBits())
- return nullptr;
+ if (DestTy->isIntOrIntVectorTy() &&
+ DestTy->getScalarSizeInBits() == SrcTy->getScalarSizeInBits())
+ return ConstantInt::get(DestTy, FP->getValueAPF().bitcastToAPInt());
- return ConstantInt::get(DestTy, FP->getValueAPF().bitcastToAPInt());
+ // Make sure dest type is compatible with the folded byte constant.
+ if (DestTy->isByteOrByteVectorTy() &&
+ DestTy->getScalarSizeInBits() == SrcTy->getScalarSizeInBits())
+ return ConstantByte::get(DestTy, FP->getValueAPF().bitcastToAPInt());
+
+ return nullptr;
}
return nullptr;
diff --git a/llvm/test/Transforms/InstSimplify/bitcast-vector-fold.ll b/llvm/test/Transforms/InstSimplify/bitcast-vector-fold.ll
index be00d78fc88d5..c4b83dffcd0f8 100644
--- a/llvm/test/Transforms/InstSimplify/bitcast-vector-fold.ll
+++ b/llvm/test/Transforms/InstSimplify/bitcast-vector-fold.ll
@@ -433,3 +433,350 @@ define <2 x i64> @bitcast_constexpr_4f32_2i64_1111() {
%res = bitcast <4 x float> splat (float 1.0) to <2 x i64>
ret <2 x i64> %res
}
+
+define <2 x b64> @bitcast_constexpr_16i8_2b64() {
+; CHECK-LABEL: @bitcast_constexpr_16i8_2b64(
+; CHECK-NEXT: ret <2 x b64> splat (b64 144680345676153346)
+;
+ %res = bitcast <16 x i8> splat (i8 2) to <2 x b64>
+ ret <2 x b64> %res
+}
+
+define <2 x b64> @bitcast_constexpr_16b8_2b64() {
+; CHECK-LABEL: @bitcast_constexpr_16b8_2b64(
+; CHECK-NEXT: ret <2 x b64> splat (b64 144680345676153346)
+;
+ %res = bitcast <16 x b8> splat (b8 2) to <2 x b64>
+ ret <2 x b64> %res
+}
+
+define <2 x i64> @bitcast_constexpr_4b32_2i64() {
+; LE-LABEL: @bitcast_constexpr_4b32_2i64(
+; LE-NEXT: ret <2 x i64> <i64 4294967296, i64 12884901890>
+;
+; BE-LABEL: @bitcast_constexpr_4b32_2i64(
+; BE-NEXT: ret <2 x i64> <i64 1, i64 8589934595>
+;
+ %res = bitcast <4 x b32> <b32 0, b32 1, b32 2, b32 3> to <2 x i64>
+ ret <2 x i64> %res
+}
+
+define <4 x i32> @bitcast_constexpr_2b64_4i32() {
+; LE-LABEL: @bitcast_constexpr_2b64_4i32(
+; LE-NEXT: ret <4 x i32> <i32 0, i32 0, i32 1, i32 0>
+;
+; BE-LABEL: @bitcast_constexpr_2b64_4i32(
+; BE-NEXT: ret <4 x i32> <i32 0, i32 0, i32 0, i32 1>
+;
+ %res = bitcast <2 x b64> <b64 0, b64 1> to <4 x i32>
+ ret <4 x i32> %res
+}
+
+define <2 x b64> @bitcast_constexpr_4i32_2b64() {
+; LE-LABEL: @bitcast_constexpr_4i32_2b64(
+; LE-NEXT: ret <2 x b64> <b64 4294967296, b64 12884901890>
+;
+; BE-LABEL: @bitcast_constexpr_4i32_2b64(
+; BE-NEXT: ret <2 x b64> <b64 1, b64 8589934595>
+;
+ %res = bitcast <4 x i32> <i32 0, i32 1, i32 2, i32 3> to <2 x b64>
+ ret <2 x b64> %res
+}
+
+define <4 x b32> @bitcast_constexpr_2i64_4b32() {
+; LE-LABEL: @bitcast_constexpr_2i64_4b32(
+; LE-NEXT: ret <4 x b32> <b32 0, b32 0, b32 1, b32 0>
+;
+; BE-LABEL: @bitcast_constexpr_2i64_4b32(
+; BE-NEXT: ret <4 x b32> <b32 0, b32 0, b32 0, b32 1>
+;
+ %res = bitcast <2 x i64> <i64 0, i64 1> to <4 x b32>
+ ret <4 x b32> %res
+}
+
+define <2 x b64> @bitcast_constexpr_4b32_2b64() {
+; LE-LABEL: @bitcast_constexpr_4b32_2b64(
+; LE-NEXT: ret <2 x b64> <b64 4294967296, b64 12884901890>
+;
+; BE-LABEL: @bitcast_constexpr_4b32_2b64(
+; BE-NEXT: ret <2 x b64> <b64 1, b64 8589934595>
+;
+ %res = bitcast <4 x b32> <b32 0, b32 1, b32 2, b32 3> to <2 x b64>
+ ret <2 x b64> %res
+}
+
+define <16 x b8> @bitcast_constexpr_2b64_16b8() {
+; LE-LABEL: @bitcast_constexpr_2b64_16b8(
+; LE-NEXT: ret <16 x b8> <b8 0, b8 0, b8 0, b8 0, b8 0, b8 0, b8 0, b8 0, b8 1, b8 0, b8 0, b8 0, b8 0, b8 0, b8 0, b8 0>
+;
+; BE-LABEL: @bitcast_constexpr_2b64_16b8(
+; BE-NEXT: ret <16 x b8> <b8 0, b8 0, b8 0, b8 0, b8 0, b8 0, b8 0, b8 0, b8 0, b8 0, b8 0, b8 0, b8 0, b8 0, b8 0, b8 1>
+;
+ %res = bitcast <2 x b64> <b64 0, b64 1> to <16 x b8>
+ ret <16 x b8> %res
+}
+
+define <2 x i32> @bitcast_constexpr_scalar_b64_to_vector_2i32() {
+; LE-LABEL: @bitcast_constexpr_scalar_b64_to_vector_2i32(
+; LE-NEXT: ret <2 x i32> <i32 1, i32 0>
+;
+; BE-LABEL: @bitcast_constexpr_scalar_b64_to_vector_2i32(
+; BE-NEXT: ret <2 x i32> <i32 0, i32 1>
+;
+ %res = bitcast b64 1 to <2 x i32>
+ ret <2 x i32> %res
+}
+
+define <2 x b32> @bitcast_constexpr_scalar_i64_to_vector_2b32() {
+; LE-LABEL: @bitcast_constexpr_scalar_i64_to_vector_2b32(
+; LE-NEXT: ret <2 x b32> <b32 1, b32 0>
+;
+; BE-LABEL: @bitcast_constexpr_scalar_i64_to_vector_2b32(
+; BE-NEXT: ret <2 x b32> <b32 0, b32 1>
+;
+ %res = bitcast i64 1 to <2 x b32>
+ ret <2 x b32> %res
+}
+
+define <2 x b64> @bitcast_constexpr_4f32_2b64() {
+; CHECK-LABEL: @bitcast_constexpr_4f32_2b64(
+; CHECK-NEXT: ret <2 x b64> splat (b64 4575657222473777152)
+;
+ %res = bitcast <4 x float> splat (float 1.0) to <2 x b64>
+ ret <2 x b64> %res
+}
+
+define <4 x float> @bitcast_constexpr_2b64_4f32() {
+; LE-LABEL: @bitcast_constexpr_2b64_4f32(
+; LE-NEXT: ret <4 x float> <float 0.000000e+00, float 0.000000e+00, float 0x36A0000000000000, float 0.000000e+00>
+;
+; BE-LABEL: @bitcast_constexpr_2b64_4f32(
+; BE-NEXT: ret <4 x float> <float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, float 0x36A0000000000000>
+;
+ %res = bitcast <2 x b64> <b64 0, b64 1> to <4 x float>
+ ret <4 x float> %res
+}
+
+define <2 x i64> @bitcast_constexpr_allones_4b32_2i64() {
+; CHECK-LABEL: @bitcast_constexpr_allones_4b32_2i64(
+; CHECK-NEXT: ret <2 x i64> splat (i64 -1)
+;
+ %res = bitcast <4 x b32> splat (b32 -1) to <2 x i64>
+ ret <2 x i64> %res
+}
+
+define <4 x i32> @bitcast_constexpr_allones_4b32_4i32() {
+; CHECK-LABEL: @bitcast_constexpr_allones_4b32_4i32(
+; CHECK-NEXT: ret <4 x i32> splat (i32 -1)
+;
+ %res = bitcast <4 x b32> splat (b32 -1) to <4 x i32>
+ ret <4 x i32> %res
+}
+
+define <4 x b32> @bitcast_constexpr_allones_2i64_4b32() {
+; CHECK-LABEL: @bitcast_constexpr_allones_2i64_4b32(
+; CHECK-NEXT: ret <4 x b32> splat (b32 -1)
+;
+ %res = bitcast <2 x i64> splat (i64 -1) to <4 x b32>
+ ret <4 x b32> %res
+}
+
+define <4 x b32> @bitcast_constexpr_allones_4i32_4b32() {
+; CHECK-LABEL: @bitcast_constexpr_allones_4i32_4b32(
+; CHECK-NEXT: ret <4 x b32> splat (b32 -1)
+;
+ %res = bitcast <4 x i32> splat (i32 -1) to <4 x b32>
+ ret <4 x b32> %res
+}
+
+define <2 x b64> @bitcast_constexpr_4b32_2b64_poison() {
+; CHECK-LABEL: @bitcast_constexpr_4b32_2b64_poison(
+; CHECK-NEXT: ret <2 x b64> bitcast (<4 x b32> <b32 poison, b32 1, b32 2, b32 3> to <2 x b64>)
+;
+ %res = bitcast <4 x b32> <b32 poison, b32 1, b32 2, b32 3> to <2 x b64>
+ ret <2 x b64> %res
+}
+
+define <2 x b64> @bitcast_constexpr_4i32_2b64_poison() {
+; CHECK-LABEL: @bitcast_constexpr_4i32_2b64_poison(
+; CHECK-NEXT: ret <2 x b64> bitcast (<4 x i32> <i32 0, i32 1, i32 poison, i32 3> to <2 x b64>)
+;
+ %res = bitcast <4 x i32> <i32 0, i32 1, i32 poison, i32 3> to <2 x b64>
+ ret <2 x b64> %res
+}
+
+define <2 x b64> @bitcast_constexpr_4f32_2b64_poison() {
+; CHECK-LABEL: @bitcast_constexpr_4f32_2b64_poison(
+; CHECK-NEXT: ret <2 x b64> bitcast (<4 x float> <float 1.000000e+00, float poison, float 2.000000e+00, float 3.000000e+00> to <2 x b64>)
+;
+ %res = bitcast <4 x float> <float 1.0, float poison, float 2.0, float 3.0> to <2 x b64>
+ ret <2 x b64> %res
+}
+
+define <2 x b64> @bitcast_constexpr_8b16_2b64_poison() {
+; CHECK-LABEL: @bitcast_constexpr_8b16_2b64_poison(
+; CHECK-NEXT: ret <2 x b64> bitcast (<8 x b16> <b16 0, b16 1, b16 2, b16 poison, b16 4, b16 5, b16 6, b16 7> to <2 x b64>)
+;
+ %res = bitcast <8 x b16> <b16 0, b16 1, b16 2, b16 poison, b16 4, b16 5, b16 6, b16 7> to <2 x b64>
+ ret <2 x b64> %res
+}
+
+define <2 x b64> @bitcast_constexpr_4b32_2b64_all_poison_group() {
+; LE-LABEL: @bitcast_constexpr_4b32_2b64_all_poison_group(
+; LE-NEXT: ret <2 x b64> <b64 poison, b64 12884901890>
+;
+; BE-LABEL: @bitcast_constexpr_4b32_2b64_all_poison_group(
+; BE-NEXT: ret <2 x b64> <b64 poison, b64 8589934595>
+;
+ %res = bitcast <4 x b32> <b32 poison, b32 poison, b32 2, b32 3> to <2 x b64>
+ ret <2 x b64> %res
+}
+
+define <2 x b64> @bitcast_constexpr_4i32_2b64_all_poison_group() {
+; LE-LABEL: @bitcast_constexpr_4i32_2b64_all_poison_group(
+; LE-NEXT: ret <2 x b64> <b64 poison, b64 12884901890>
+;
+; BE-LABEL: @bitcast_constexpr_4i32_2b64_all_poison_group(
+; BE-NEXT: ret <2 x b64> <b64 poison, b64 8589934595>
+;
+ %res = bitcast <4 x i32> <i32 poison, i32 poison, i32 2, i32 3> to <2 x b64>
+ ret <2 x b64> %res
+}
+
+define <2 x i64> @bitcast_constexpr_4b32_2i64_poison() {
+; LE-LABEL: @bitcast_constexpr_4b32_2i64_poison(
+; LE-NEXT: ret <2 x i64> <i64 poison, i64 12884901890>
+;
+; BE-LABEL: @bitcast_constexpr_4b32_2i64_poison(
+; BE-NEXT: ret <2 x i64> <i64 poison, i64 8589934595>
+;
+ %res = bitcast <4 x b32> <b32 poison, b32 1, b32 2, b32 3> to <2 x i64>
+ ret <2 x i64> %res
+}
+
+define <4 x b32> @bitcast_constexpr_2b64_4b32_poison() {
+; LE-LABEL: @bitcast_constexpr_2b64_4b32_poison(
+; LE-NEXT: ret <4 x b32> <b32 poison, b32 poison, b32 1, b32 0>
+;
+; BE-LABEL: @bitcast_constexpr_2b64_4b32_poison(
+; BE-NEXT: ret <4 x b32> <b32 poison, b32 poison, b32 0, b32 1>
+;
+ %res = bitcast <2 x b64> <b64 poison, b64 1> to <4 x b32>
+ ret <4 x b32> %res
+}
+
+define <2 x b64> @bitcast_constexpr_4b32_2b64_all_poison() {
+; CHECK-LABEL: @bitcast_constexpr_4b32_2b64_all_poison(
+; CHECK-NEXT: ret <2 x b64> poison
+;
+ %res = bitcast <4 x b32> splat (b32 poison) to <2 x b64>
+ ret <2 x b64> %res
+}
+
+define <4 x i32> @bitcast_constexpr_2b64_4i32_poison() {
+; LE-LABEL: @bitcast_constexpr_2b64_4i32_poison(
+; LE-NEXT: ret <4 x i32> <i32 poison, i32 poison, i32 1, i32 0>
+;
+; BE-LABEL: @bitcast_constexpr_2b64_4i32_poison(
+; BE-NEXT: ret <4 x i32> <i32 poison, i32 poison, i32 0, i32 1>
+;
+ %res = bitcast <2 x b64> <b64 poison, b64 1> to <4 x i32>
+ ret <4 x i32> %res
+}
+
+define <2 x double> @bitcast_constexpr_4b32_2f64_poison() {
+; LE-LABEL: @bitcast_constexpr_4b32_2f64_poison(
+; LE-NEXT: ret <2 x double> <double poison, double 0x300000002>
+;
+; BE-LABEL: @bitcast_constexpr_4b32_2f64_poison(
+; BE-NEXT: ret <2 x double> <double poison, double 0x200000003>
+;
+ %res = bitcast <4 x b32> <b32 poison, b32 1, b32 2, b32 3> to <2 x double>
+ ret <2 x double> %res
+}
+
+define <4 x float> @bitcast_constexpr_2b64_4f32_poison() {
+; LE-LABEL: @bitcast_constexpr_2b64_4f32_poison(
+; LE-NEXT: ret <4 x float> <float poison, float poison, float 0x36A0000000000000, float 0.000000e+00>
+;
+; BE-LABEL: @bitcast_constexpr_2b64_4f32_poison(
+; BE-NEXT: ret <4 x float> <float poison, float poison, float 0.000000e+00, float 0x36A0000000000000>
+;
+ %res = bitcast <2 x b64> <b64 poison, b64 1> to <4 x float>
+ ret <4 x float> %res
+}
+
+define i128 @bitcast_constexpr_2b64_i128() {
+; LE-LABEL: @bitcast_constexpr_2b64_i128(
+; LE-NEXT: ret i128 18446744073709551618
+;
+; BE-LABEL: @bitcast_constexpr_2b64_i128(
+; BE-NEXT: ret i128 36893488147419103233
+;
+ %res = bitcast <2 x b64> <b64 2, b64 1> to i128
+ ret i128 %res
+}
+
+define i128 @bitcast_constexpr_2b64_i128_poison() {
+; CHECK-LABEL: @bitcast_constexpr_2b64_i128_poison(
+; CHECK-NEXT: ret i128 poison
+;
+ %res = bitcast <2 x b64> <b64 poison, b64 1> to i128
+ ret i128 %res
+}
+
+define double @bitcast_constexpr_2b32_f64() {
+; LE-LABEL: @bitcast_constexpr_2b32_f64(
+; LE-NEXT: ret double 0x100000002
+;
+; BE-LABEL: @bitcast_constexpr_2b32_f64(
+; BE-NEXT: ret double 0x200000001
+;
+ %res = bitcast <2 x b32> <b32 2, b32 1> to double
+ ret double %res
+}
+
+define double @bitcast_constexpr_2b32_f64_poison() {
+; CHECK-LABEL: @bitcast_constexpr_2b32_f64_poison(
+; CHECK-NEXT: ret double poison
+;
+ %res = bitcast <2 x b32> <b32 poison, b32 1> to double
+ ret double %res
+}
+
+define <3 x b8> @bitcast_constexpr_8b3_3b8() {
+; LE-LABEL: @bitcast_constexpr_8b3_3b8(
+; LE-NEXT: ret <3 x b8> <b8 -120, b8 -58, b8 -6>
+;
+; BE-LABEL: @bitcast_constexpr_8b3_3b8(
+; BE-NEXT: ret <3 x b8> <b8 5, b8 57, b8 119>
+;
+ %res = bitcast <8 x b3> <b3 0, b3 1, b3 2, b3 3, b3 4, b3 5, b3 6, b3 7> to <3 x b8>
+ ret <3 x b8> %res
+}
+
+define <3 x b8> @bitcast_constexpr_8b3_3b8_poison() {
+; CHECK-LABEL: @bitcast_constexpr_8b3_3b8_poison(
+; CHECK-NEXT: ret <3 x b8> bitcast (<8 x b3> <b3 poison, b3 poison, b3 1, b3 2, b3 3, b3 -4, b3 -3, b3 -2> to <3 x b8>)
+;
+ %res = bitcast <8 x b3> <b3 poison, b3 poison, b3 1, b3 2, b3 3, b3 4, b3 5, b3 6> to <3 x b8>
+ ret <3 x b8> %res
+}
+
+; TODO: this can be folded.
+define <3 x i8> @bitcast_constexpr_8b3_3i8_poison() {
+; CHECK-LABEL: @bitcast_constexpr_8b3_3i8_poison(
+; CHECK-NEXT: ret <3 x i8> bitcast (<8 x b3> <b3 poison, b3 poison, b3 1, b3 2, b3 3, b3 -4, b3 -3, b3 -2> to <3 x i8>)
+;
+ %res = bitcast <8 x b3> <b3 poison, b3 poison, b3 1, b3 2, b3 3, b3 4, b3 5, b3 6> to <3 x i8>
+ ret <3 x i8> %res
+}
+
+; TODO: this can be folded.
+define <3 x i8> @bitcast_constexpr_8b3_3i8_crossing_poison() {
+; CHECK-LABEL: @bitcast_constexpr_8b3_3i8_crossing_poison(
+; CHECK-NEXT: ret <3 x i8> bitcast (<8 x b3> <b3 1, b3 2, b3 poison, b3 3, b3 -4, b3 -3, b3 -2, b3 -1> to <3 x i8>)
+;
+ %res = bitcast <8 x b3> <b3 1, b3 2, b3 poison, b3 3, b3 4, b3 5, b3 6, b3 7> to <3 x i8>
+ ret <3 x i8> %res
+}
More information about the llvm-commits
mailing list