Skip to content

Commit 6bbc776

Browse files
committed
[InstCombine] Refactoring matchFunnelShift (NFC)
The matchFunnelShift function was doing pattern matching and creating the fshl/fshr instruction if needed. Moved the pattern matching code to function convertShlOrLShrToFShlOrFShr. It can be reused for other optimizations.
1 parent 0fea00d commit 6bbc776

File tree

2 files changed

+26
-13
lines changed

2 files changed

+26
-13
lines changed

llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2706,17 +2706,16 @@ Instruction *InstCombinerImpl::matchBSwapOrBitReverse(Instruction &I,
27062706
return LastInst;
27072707
}
27082708

2709-
/// Match UB-safe variants of the funnel shift intrinsic.
2710-
static Instruction *matchFunnelShift(Instruction &Or, InstCombinerImpl &IC,
2711-
const DominatorTree &DT) {
2709+
std::optional<std::tuple<Intrinsic::ID, SmallVector<Value *, 3>>>
2710+
InstCombinerImpl::convertShlOrLShrToFShlOrFShr(Instruction &Or) {
27122711
// TODO: Can we reduce the code duplication between this and the related
27132712
// rotate matching code under visitSelect and visitTrunc?
27142713
unsigned Width = Or.getType()->getScalarSizeInBits();
27152714

27162715
Instruction *Or0, *Or1;
27172716
if (!match(Or.getOperand(0), m_Instruction(Or0)) ||
27182717
!match(Or.getOperand(1), m_Instruction(Or1)))
2719-
return nullptr;
2718+
return std::nullopt;
27202719

27212720
bool IsFshl = true; // Sub on LSHR.
27222721
SmallVector<Value *, 3> FShiftArgs;
@@ -2730,7 +2729,7 @@ static Instruction *matchFunnelShift(Instruction &Or, InstCombinerImpl &IC,
27302729
!match(Or1,
27312730
m_OneUse(m_LogicalShift(m_Value(ShVal1), m_Value(ShAmt1)))) ||
27322731
Or0->getOpcode() == Or1->getOpcode())
2733-
return nullptr;
2732+
return std::nullopt;
27342733

27352734
// Canonicalize to or(shl(ShVal0, ShAmt0), lshr(ShVal1, ShAmt1)).
27362735
if (Or0->getOpcode() == BinaryOperator::LShr) {
@@ -2766,7 +2765,7 @@ static Instruction *matchFunnelShift(Instruction &Or, InstCombinerImpl &IC,
27662765
// might remove it after this fold). This still doesn't guarantee that the
27672766
// final codegen will match this original pattern.
27682767
if (match(R, m_OneUse(m_Sub(m_SpecificInt(Width), m_Specific(L))))) {
2769-
KnownBits KnownL = IC.computeKnownBits(L, /*Depth*/ 0, &Or);
2768+
KnownBits KnownL = computeKnownBits(L, /*Depth*/ 0, &Or);
27702769
return KnownL.getMaxValue().ult(Width) ? L : nullptr;
27712770
}
27722771

@@ -2810,7 +2809,7 @@ static Instruction *matchFunnelShift(Instruction &Or, InstCombinerImpl &IC,
28102809
IsFshl = false; // Sub on SHL.
28112810
}
28122811
if (!ShAmt)
2813-
return nullptr;
2812+
return std::nullopt;
28142813

28152814
FShiftArgs = {ShVal0, ShVal1, ShAmt};
28162815
} else if (isa<ZExtInst>(Or0) || isa<ZExtInst>(Or1)) {
@@ -2832,18 +2831,18 @@ static Instruction *matchFunnelShift(Instruction &Or, InstCombinerImpl &IC,
28322831
const APInt *ZextHighShlAmt;
28332832
if (!match(Or0,
28342833
m_OneUse(m_Shl(m_Value(ZextHigh), m_APInt(ZextHighShlAmt)))))
2835-
return nullptr;
2834+
return std::nullopt;
28362835

28372836
if (!match(Or1, m_ZExt(m_Value(Low))) ||
28382837
!match(ZextHigh, m_ZExt(m_Value(High))))
2839-
return nullptr;
2838+
return std::nullopt;
28402839

28412840
unsigned HighSize = High->getType()->getScalarSizeInBits();
28422841
unsigned LowSize = Low->getType()->getScalarSizeInBits();
28432842
// Make sure High does not overlap with Low and most significant bits of
28442843
// High aren't shifted out.
28452844
if (ZextHighShlAmt->ult(LowSize) || ZextHighShlAmt->ugt(Width - HighSize))
2846-
return nullptr;
2845+
return std::nullopt;
28472846

28482847
for (User *U : ZextHigh->users()) {
28492848
Value *X, *Y;
@@ -2874,11 +2873,22 @@ static Instruction *matchFunnelShift(Instruction &Or, InstCombinerImpl &IC,
28742873
}
28752874

28762875
if (FShiftArgs.empty())
2877-
return nullptr;
2876+
return std::nullopt;
28782877

28792878
Intrinsic::ID IID = IsFshl ? Intrinsic::fshl : Intrinsic::fshr;
2880-
Function *F = Intrinsic::getDeclaration(Or.getModule(), IID, Or.getType());
2881-
return CallInst::Create(F, FShiftArgs);
2879+
return std::make_tuple(IID, FShiftArgs);
2880+
}
2881+
2882+
/// Match UB-safe variants of the funnel shift intrinsic.
2883+
static Instruction *matchFunnelShift(Instruction &Or, InstCombinerImpl &IC,
2884+
const DominatorTree &DT) {
2885+
if (auto Opt = IC.convertShlOrLShrToFShlOrFShr(Or)) {
2886+
auto [IID, FShiftArgs] = *Opt;
2887+
Function *F = Intrinsic::getDeclaration(Or.getModule(), IID, Or.getType());
2888+
return CallInst::Create(F, FShiftArgs);
2889+
}
2890+
2891+
return nullptr;
28822892
}
28832893

28842894
/// Attempt to combine or(zext(x),shl(zext(y),bw/2) concat packing patterns.

llvm/lib/Transforms/InstCombine/InstCombineInternal.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,9 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final
236236
return getLosslessTrunc(C, TruncTy, Instruction::SExt);
237237
}
238238

239+
std::optional<std::tuple<Intrinsic::ID, SmallVector<Value *, 3>>>
240+
convertShlOrLShrToFShlOrFShr(Instruction &Or);
241+
239242
private:
240243
bool annotateAnyAllocSite(CallBase &Call, const TargetLibraryInfo *TLI);
241244
bool isDesirableIntType(unsigned BitWidth) const;

0 commit comments

Comments
 (0)