Skip to content

Commit 0806d7b

Browse files
author
Salinas, David
authored
[InstCombine] Added pattern for recognising the construction of packe… (llvm#4099)
2 parents 9303cdf + a397ae6 commit 0806d7b

File tree

2 files changed

+1080
-0
lines changed

2 files changed

+1080
-0
lines changed

llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,13 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "InstCombineInternal.h"
14+
#include "llvm/ADT/SmallBitVector.h"
1415
#include "llvm/Analysis/CmpInstAnalysis.h"
1516
#include "llvm/Analysis/FloatingPointPredicateUtils.h"
1617
#include "llvm/Analysis/InstructionSimplify.h"
1718
#include "llvm/IR/ConstantRange.h"
19+
#include "llvm/IR/DerivedTypes.h"
20+
#include "llvm/IR/Instructions.h"
1821
#include "llvm/IR/Intrinsics.h"
1922
#include "llvm/IR/PatternMatch.h"
2023
#include "llvm/Transforms/InstCombine/InstCombiner.h"
@@ -3592,6 +3595,154 @@ static Value *foldOrOfInversions(BinaryOperator &I,
35923595
return nullptr;
35933596
}
35943597

3598+
/// Match \p V as "shufflevector -> bitcast" or "extractelement -> zext -> shl"
3599+
/// patterns, which extract vector elements and pack them in the same relative
3600+
/// positions.
3601+
///
3602+
/// \p Vec is the underlying vector being extracted from.
3603+
/// \p Mask is a bitmask identifying which packed elements are obtained from the
3604+
/// vector.
3605+
/// \p VecOffset is the vector element corresponding to index 0 of the
3606+
/// mask.
3607+
static bool matchSubIntegerPackFromVector(Value *V, Value *&Vec,
3608+
int64_t &VecOffset,
3609+
SmallBitVector &Mask,
3610+
const DataLayout &DL) {
3611+
static const auto m_ConstShlOrSelf = [](const auto &Base, uint64_t &ShlAmt) {
3612+
ShlAmt = 0;
3613+
return m_CombineOr(m_Shl(Base, m_ConstantInt(ShlAmt)), Base);
3614+
};
3615+
3616+
// First try to match extractelement -> zext -> shl
3617+
uint64_t VecIdx, ShlAmt;
3618+
if (match(V, m_ConstShlOrSelf(m_ZExtOrSelf(m_ExtractElt(
3619+
m_Value(Vec), m_ConstantInt(VecIdx))),
3620+
ShlAmt))) {
3621+
auto *VecTy = dyn_cast<FixedVectorType>(Vec->getType());
3622+
if (!VecTy)
3623+
return false;
3624+
auto *EltTy = dyn_cast<IntegerType>(VecTy->getElementType());
3625+
if (!EltTy)
3626+
return false;
3627+
3628+
const unsigned EltBitWidth = EltTy->getBitWidth();
3629+
const unsigned TargetBitWidth = V->getType()->getIntegerBitWidth();
3630+
if (TargetBitWidth % EltBitWidth != 0 || ShlAmt % EltBitWidth != 0)
3631+
return false;
3632+
const unsigned TargetEltWidth = TargetBitWidth / EltBitWidth;
3633+
const unsigned ShlEltAmt = ShlAmt / EltBitWidth;
3634+
3635+
const unsigned MaskIdx =
3636+
DL.isLittleEndian() ? ShlEltAmt : TargetEltWidth - ShlEltAmt - 1;
3637+
3638+
VecOffset = static_cast<int64_t>(VecIdx) - static_cast<int64_t>(MaskIdx);
3639+
Mask.resize(TargetEltWidth);
3640+
Mask.set(MaskIdx);
3641+
return true;
3642+
}
3643+
3644+
// Now try to match a bitcasted subvector.
3645+
Instruction *SrcVecI;
3646+
if (!match(V, m_BitCast(m_Instruction(SrcVecI))))
3647+
return false;
3648+
3649+
auto *SrcTy = dyn_cast<FixedVectorType>(SrcVecI->getType());
3650+
if (!SrcTy)
3651+
return false;
3652+
3653+
Mask.resize(SrcTy->getNumElements());
3654+
3655+
// First check for a subvector obtained from a shufflevector.
3656+
if (isa<ShuffleVectorInst>(SrcVecI)) {
3657+
Constant *ConstVec;
3658+
ArrayRef<int> ShuffleMask;
3659+
if (!match(SrcVecI, m_Shuffle(m_Value(Vec), m_Constant(ConstVec),
3660+
m_Mask(ShuffleMask))))
3661+
return false;
3662+
3663+
auto *VecTy = dyn_cast<FixedVectorType>(Vec->getType());
3664+
if (!VecTy)
3665+
return false;
3666+
3667+
const unsigned NumVecElts = VecTy->getNumElements();
3668+
bool FoundVecOffset = false;
3669+
for (unsigned Idx = 0; Idx < ShuffleMask.size(); ++Idx) {
3670+
if (ShuffleMask[Idx] == PoisonMaskElem)
3671+
return false;
3672+
const unsigned ShuffleIdx = ShuffleMask[Idx];
3673+
if (ShuffleIdx >= NumVecElts) {
3674+
const unsigned ConstIdx = ShuffleIdx - NumVecElts;
3675+
auto *ConstElt =
3676+
dyn_cast<ConstantInt>(ConstVec->getAggregateElement(ConstIdx));
3677+
if (!ConstElt || !ConstElt->isNullValue())
3678+
return false;
3679+
continue;
3680+
}
3681+
3682+
if (FoundVecOffset) {
3683+
if (VecOffset + Idx != ShuffleIdx)
3684+
return false;
3685+
} else {
3686+
if (ShuffleIdx < Idx)
3687+
return false;
3688+
VecOffset = ShuffleIdx - Idx;
3689+
FoundVecOffset = true;
3690+
}
3691+
Mask.set(Idx);
3692+
}
3693+
return FoundVecOffset;
3694+
}
3695+
3696+
// Check for a subvector obtained as an (insertelement V, 0, idx)
3697+
uint64_t InsertIdx;
3698+
if (!match(SrcVecI,
3699+
m_InsertElt(m_Value(Vec), m_Zero(), m_ConstantInt(InsertIdx))))
3700+
return false;
3701+
3702+
auto *VecTy = dyn_cast<FixedVectorType>(Vec->getType());
3703+
if (!VecTy)
3704+
return false;
3705+
VecOffset = 0;
3706+
bool AlreadyInsertedMaskedElt = Mask.test(InsertIdx);
3707+
Mask.set();
3708+
if (!AlreadyInsertedMaskedElt)
3709+
Mask.reset(InsertIdx);
3710+
return true;
3711+
}
3712+
3713+
/// Try to fold the join of two scalar integers whose contents are packed
3714+
/// elements of the same vector.
3715+
static Instruction *foldIntegerPackFromVector(Instruction &I,
3716+
InstCombiner::BuilderTy &Builder,
3717+
const DataLayout &DL) {
3718+
assert(I.getOpcode() == Instruction::Or);
3719+
Value *LhsVec, *RhsVec;
3720+
int64_t LhsVecOffset, RhsVecOffset;
3721+
SmallBitVector Mask;
3722+
if (!matchSubIntegerPackFromVector(I.getOperand(0), LhsVec, LhsVecOffset,
3723+
Mask, DL))
3724+
return nullptr;
3725+
if (!matchSubIntegerPackFromVector(I.getOperand(1), RhsVec, RhsVecOffset,
3726+
Mask, DL))
3727+
return nullptr;
3728+
if (LhsVec != RhsVec || LhsVecOffset != RhsVecOffset)
3729+
return nullptr;
3730+
3731+
// Convert into shufflevector -> bitcast;
3732+
const unsigned ZeroVecIdx =
3733+
cast<FixedVectorType>(LhsVec->getType())->getNumElements();
3734+
SmallVector<int> ShuffleMask(Mask.size(), ZeroVecIdx);
3735+
for (unsigned Idx : Mask.set_bits()) {
3736+
assert(LhsVecOffset + Idx >= 0);
3737+
ShuffleMask[Idx] = LhsVecOffset + Idx;
3738+
}
3739+
3740+
Value *MaskedVec = Builder.CreateShuffleVector(
3741+
LhsVec, Constant::getNullValue(LhsVec->getType()), ShuffleMask,
3742+
I.getName() + ".v");
3743+
return CastInst::Create(Instruction::BitCast, MaskedVec, I.getType());
3744+
}
3745+
35953746
// A decomposition of ((X & Mask) * Factor). The NUW / NSW bools
35963747
// track these properities for preservation. Note that we can decompose
35973748
// equivalent select form of this expression (e.g. (!(X & Mask) ? 0 : Mask *
@@ -3770,6 +3921,9 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) {
37703921
if (Instruction *X = foldComplexAndOrPatterns(I, Builder))
37713922
return X;
37723923

3924+
if (Instruction *X = foldIntegerPackFromVector(I, Builder, DL))
3925+
return X;
3926+
37733927
// (A & B) | (C & D) -> A ^ D where A == ~C && B == ~D
37743928
// (A & B) | (C & D) -> A ^ C where A == ~D && B == ~C
37753929
if (Value *V = foldOrOfInversions(I, Builder))

0 commit comments

Comments
 (0)