-
Notifications
You must be signed in to change notification settings - Fork 11.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[InstCombine] Convert or concat to fshl if opposite or concat exists #68502
Changes from 4 commits
5b3b1bb
68ab662
aca9aa3
b7810a1
116e529
c882da8
fb1af49
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2735,7 +2735,8 @@ Instruction *InstCombinerImpl::matchBSwapOrBitReverse(Instruction &I, | |
} | ||
|
||
/// Match UB-safe variants of the funnel shift intrinsic. | ||
static Instruction *matchFunnelShift(Instruction &Or, InstCombinerImpl &IC) { | ||
static Instruction *matchFunnelShift(Instruction &Or, InstCombinerImpl &IC, | ||
const DominatorTree &DT) { | ||
// TODO: Can we reduce the code duplication between this and the related | ||
// rotate matching code under visitSelect and visitTrunc? | ||
unsigned Width = Or.getType()->getScalarSizeInBits(); | ||
|
@@ -2840,6 +2841,60 @@ static Instruction *matchFunnelShift(Instruction &Or, InstCombinerImpl &IC) { | |
return nullptr; | ||
|
||
FShiftArgs = {ShVal0, ShVal1, ShAmt}; | ||
} else if (isa<ZExtInst>(Or0) || isa<ZExtInst>(Or1)) { | ||
// If there are two 'or' instructions concat variables in opposite order: | ||
// | ||
// Slot1 and Slot2 are all zero bits. | ||
// | Slot1 | Low | Slot2 | High | | ||
// LowHigh = or (shl (zext Low), ZextLowShlAmt), (zext High) | ||
// | Slot2 | High | Slot1 | Low | | ||
// HighLow = or (shl (zext High), ZextHighShlAmt), (zext Low) | ||
// | ||
// the latter 'or' can be safely convert to | ||
// -> HighLow = fshl LowHigh, LowHigh, ZextHighShlAmt | ||
// if ZextLowShlAmt + ZextHighShlAmt == Width. | ||
if (!isa<ZExtInst>(Or1)) | ||
std::swap(Or0, Or1); | ||
|
||
Value *High, *ZextHigh, *Low; | ||
const APInt *ZextHighShlAmt; | ||
if (!match(Or0, | ||
m_OneUse(m_Shl(m_Value(ZextHigh), m_APInt(ZextHighShlAmt))))) | ||
return nullptr; | ||
|
||
if (!match(Or1, m_ZExt(m_Value(Low))) || | ||
!match(ZextHigh, m_ZExt(m_Value(High)))) | ||
return nullptr; | ||
|
||
unsigned HighSize = High->getType()->getScalarSizeInBits(); | ||
unsigned LowSize = Low->getType()->getScalarSizeInBits(); | ||
// Make sure High does not overlap with Low and most significant bits of | ||
// High aren't shifted out. | ||
if (ZextHighShlAmt->ult(LowSize) || ZextHighShlAmt->ugt(Width - HighSize)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Think you are missing a negative test for this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
return nullptr; | ||
|
||
for (User *U : ZextHigh->users()) { | ||
Value *X, *Y; | ||
if (!match(U, m_Or(m_Value(X), m_Value(Y)))) | ||
continue; | ||
|
||
if (!isa<ZExtInst>(Y)) | ||
std::swap(X, Y); | ||
|
||
const APInt *ZextLowShlAmt; | ||
if (!match(X, m_Shl(m_Specific(Or1), m_APInt(ZextLowShlAmt))) || | ||
!match(Y, m_Specific(ZextHigh)) || !DT.dominates(U, &Or)) | ||
continue; | ||
|
||
// Make sure Low does not overlap with High and most significant bits of | ||
// Low aren't shifted out and we can rotate shift LowHigh to HighLow. | ||
if (ZextLowShlAmt->ult(HighSize) || ZextLowShlAmt->ugt(Width - LowSize) || | ||
*ZextLowShlAmt + *ZextHighShlAmt != Width) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Think you are missing negative test for this (also for non-dominating). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In fact, non-dominating was already tested: |
||
continue; | ||
|
||
FShiftArgs = {U, U, ConstantInt::get(Or0->getType(), *ZextHighShlAmt)}; | ||
break; | ||
} | ||
HaohaiWen marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
if (FShiftArgs.empty()) | ||
|
@@ -3341,7 +3396,7 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) { | |
/*MatchBitReversals*/ true)) | ||
return BitOp; | ||
|
||
if (Instruction *Funnel = matchFunnelShift(I, *this)) | ||
if (Instruction *Funnel = matchFunnelShift(I, *this, DT)) | ||
return Funnel; | ||
|
||
if (Instruction *Concat = matchOrConcat(I, Builder)) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you actually need the shifted value to be
zext
? I.e if you have(shl (zext i24 to i32), 8)
that is bitwise equivilent to(shl i32, 8)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we only match (shl i32, 8), we can't guarantee it's reverse concat since we don't know if the most significant 8bit in i32 is zero.
If not match zext:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahh, I see, although could handle masking
and
. Really its just a knownbits check though.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we don't need to check
zext
. An example withoutzext
: https://alive2.llvm.org/ce/z/MytePb