forked from OSchip/llvm-project
[InstCombine] Catch more bswap cases missed due to zext and truncs.
Fixes PR27824. Differential Revision: http://reviews.llvm.org/D20591. llvm-svn: 270853
This commit is contained in:
parent
50c37ceb3b
commit
e5819e2732
|
@ -1620,6 +1620,30 @@ Instruction *InstCombiner::visitAnd(BinaryOperator &I) {
|
|||
/// Given an OR instruction, check to see if this is a bswap idiom. If so,
|
||||
/// insert the new intrinsic and return it.
|
||||
Instruction *InstCombiner::MatchBSwap(BinaryOperator &I) {
|
||||
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
|
||||
|
||||
// Look through zero extends.
|
||||
if (Instruction *Ext = dyn_cast<ZExtInst>(Op0))
|
||||
Op0 = Ext->getOperand(0);
|
||||
|
||||
if (Instruction *Ext = dyn_cast<ZExtInst>(Op1))
|
||||
Op1 = Ext->getOperand(0);
|
||||
|
||||
// (A | B) | C and A | (B | C) -> bswap if possible.
|
||||
bool OrOfOrs = match(Op0, m_Or(m_Value(), m_Value())) ||
|
||||
match(Op1, m_Or(m_Value(), m_Value()));
|
||||
|
||||
// (A >> B) | (C << D) and (A << B) | (B >> C) -> bswap if possible.
|
||||
bool OrOfShifts = match(Op0, m_LogicalShift(m_Value(), m_Value())) &&
|
||||
match(Op1, m_LogicalShift(m_Value(), m_Value()));
|
||||
|
||||
// (A & B) | (C & D) -> bswap if possible.
|
||||
bool OrOfAnds = match(Op0, m_And(m_Value(), m_Value())) &&
|
||||
match(Op1, m_And(m_Value(), m_Value()));
|
||||
|
||||
if (!OrOfOrs && !OrOfShifts && !OrOfAnds)
|
||||
return nullptr;
|
||||
|
||||
SmallVector<Instruction*, 4> Insts;
|
||||
if (!recognizeBSwapOrBitReverseIdiom(&I, true, false, Insts))
|
||||
return nullptr;
|
||||
|
@ -2162,23 +2186,13 @@ Instruction *InstCombiner::visitOr(BinaryOperator &I) {
|
|||
return NV;
|
||||
}
|
||||
|
||||
// Given an OR instruction, check to see if this is a bswap.
|
||||
if (Instruction *BSwap = MatchBSwap(I))
|
||||
return BSwap;
|
||||
|
||||
Value *A = nullptr, *B = nullptr;
|
||||
ConstantInt *C1 = nullptr, *C2 = nullptr;
|
||||
|
||||
// (A | B) | C and A | (B | C) -> bswap if possible.
|
||||
bool OrOfOrs = match(Op0, m_Or(m_Value(), m_Value())) ||
|
||||
match(Op1, m_Or(m_Value(), m_Value()));
|
||||
// (A >> B) | (C << D) and (A << B) | (B >> C) -> bswap if possible.
|
||||
bool OrOfShifts = match(Op0, m_LogicalShift(m_Value(), m_Value())) &&
|
||||
match(Op1, m_LogicalShift(m_Value(), m_Value()));
|
||||
// (A & B) | (C & D) -> bswap if possible.
|
||||
bool OrOfAnds = match(Op0, m_And(m_Value(), m_Value())) &&
|
||||
match(Op1, m_And(m_Value(), m_Value()));
|
||||
|
||||
if (OrOfOrs || OrOfShifts || OrOfAnds)
|
||||
if (Instruction *BSwap = MatchBSwap(I))
|
||||
return BSwap;
|
||||
|
||||
// (X^C)|Y -> (X|Y)^C iff Y&C == 0
|
||||
if (Op0->hasOneUse() &&
|
||||
match(Op0, m_Xor(m_Value(A), m_ConstantInt(C1))) &&
|
||||
|
|
|
@ -1773,7 +1773,23 @@ collectBitParts(Value *V, bool MatchBSwaps, bool MatchBitReversals,
|
|||
// If the AndMask is zero for this bit, clear the bit.
|
||||
if ((AndMask & Bit) == 0)
|
||||
Result->Provenance[i] = BitPart::Unset;
|
||||
return Result;
|
||||
}
|
||||
|
||||
// If this is a zext instruction zero extend the result.
|
||||
if (I->getOpcode() == Instruction::ZExt) {
|
||||
auto &Res = collectBitParts(I->getOperand(0), MatchBSwaps,
|
||||
MatchBitReversals, BPS);
|
||||
if (!Res)
|
||||
return Result;
|
||||
|
||||
Result = BitPart(Res->Provider, BitWidth);
|
||||
auto NarrowBitWidth =
|
||||
cast<IntegerType>(cast<ZExtInst>(I)->getSrcTy())->getBitWidth();
|
||||
for (unsigned i = 0; i < NarrowBitWidth; ++i)
|
||||
Result->Provenance[i] = Res->Provenance[i];
|
||||
for (unsigned i = NarrowBitWidth; i < BitWidth; ++i)
|
||||
Result->Provenance[i] = BitPart::Unset;
|
||||
return Result;
|
||||
}
|
||||
}
|
||||
|
@ -1816,6 +1832,15 @@ bool llvm::recognizeBSwapOrBitReverseIdiom(
|
|||
return false; // Can't do vectors or integers > 128 bits.
|
||||
unsigned BW = ITy->getBitWidth();
|
||||
|
||||
unsigned DemandedBW = BW;
|
||||
IntegerType *DemandedTy = ITy;
|
||||
if (I->hasOneUse()) {
|
||||
if (TruncInst *Trunc = dyn_cast<TruncInst>(I->user_back())) {
|
||||
DemandedTy = cast<IntegerType>(Trunc->getType());
|
||||
DemandedBW = DemandedTy->getBitWidth();
|
||||
}
|
||||
}
|
||||
|
||||
// Try to find all the pieces corresponding to the bswap.
|
||||
std::map<Value *, Optional<BitPart>> BPS;
|
||||
auto Res = collectBitParts(I, MatchBSwaps, MatchBitReversals, BPS);
|
||||
|
@ -1825,11 +1850,12 @@ bool llvm::recognizeBSwapOrBitReverseIdiom(
|
|||
|
||||
// Now, is the bit permutation correct for a bswap or a bitreverse? We can
|
||||
// only byteswap values with an even number of bytes.
|
||||
bool OKForBSwap = BW % 16 == 0, OKForBitReverse = true;
|
||||
for (unsigned i = 0; i < BW; ++i) {
|
||||
OKForBSwap &= bitTransformIsCorrectForBSwap(BitProvenance[i], i, BW);
|
||||
bool OKForBSwap = DemandedBW % 16 == 0, OKForBitReverse = true;
|
||||
for (unsigned i = 0; i < DemandedBW; ++i) {
|
||||
OKForBSwap &=
|
||||
bitTransformIsCorrectForBSwap(BitProvenance[i], i, DemandedBW);
|
||||
OKForBitReverse &=
|
||||
bitTransformIsCorrectForBitReverse(BitProvenance[i], i, BW);
|
||||
bitTransformIsCorrectForBitReverse(BitProvenance[i], i, DemandedBW);
|
||||
}
|
||||
|
||||
Intrinsic::ID Intrin;
|
||||
|
@ -1840,6 +1866,24 @@ bool llvm::recognizeBSwapOrBitReverseIdiom(
|
|||
else
|
||||
return false;
|
||||
|
||||
if (ITy != DemandedTy) {
|
||||
Function *F = Intrinsic::getDeclaration(I->getModule(), Intrin, DemandedTy);
|
||||
Value *Provider = Res->Provider;
|
||||
IntegerType *ProviderTy = cast<IntegerType>(Provider->getType());
|
||||
// We may need to truncate the provider.
|
||||
if (DemandedTy != ProviderTy) {
|
||||
auto *Trunc = CastInst::Create(Instruction::Trunc, Provider, DemandedTy,
|
||||
"trunc", I);
|
||||
InsertedInsts.push_back(Trunc);
|
||||
Provider = Trunc;
|
||||
}
|
||||
auto *CI = CallInst::Create(F, Provider, "rev", I);
|
||||
InsertedInsts.push_back(CI);
|
||||
auto *ExtInst = CastInst::Create(Instruction::ZExt, CI, ITy, "zext", I);
|
||||
InsertedInsts.push_back(ExtInst);
|
||||
return true;
|
||||
}
|
||||
|
||||
Function *F = Intrinsic::getDeclaration(I->getModule(), Intrin, ITy);
|
||||
InsertedInsts.push_back(CallInst::Create(F, Res->Provider, "rev", I));
|
||||
return true;
|
||||
|
|
|
@ -97,3 +97,41 @@ define i32 @test7(i32 %x) {
|
|||
%or6 = or i32 %shl3, %shr5
|
||||
ret i32 %or6
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @test8
|
||||
; CHECK: call i16 @llvm.bswap.i16(i16 %a)
|
||||
define i16 @test8(i16 %a) {
|
||||
entry:
|
||||
%conv = zext i16 %a to i32
|
||||
%shr = lshr i16 %a, 8
|
||||
%shl = shl i32 %conv, 8
|
||||
%conv1 = zext i16 %shr to i32
|
||||
%or = or i32 %conv1, %shl
|
||||
%conv2 = trunc i32 %or to i16
|
||||
ret i16 %conv2
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @test9
|
||||
; CHECK: call i16 @llvm.bswap.i16(i16 %a)
|
||||
define i16 @test9(i16 %a) {
|
||||
entry:
|
||||
%conv = zext i16 %a to i32
|
||||
%shr = lshr i32 %conv, 8
|
||||
%shl = shl i32 %conv, 8
|
||||
%or = or i32 %shr, %shl
|
||||
%conv2 = trunc i32 %or to i16
|
||||
ret i16 %conv2
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @test10
|
||||
; CHECK: trunc i32 %a to i16
|
||||
; CHECK: call i16 @llvm.bswap.i16(i16 %trunc)
|
||||
define i16 @test10(i32 %a) {
|
||||
%shr1 = lshr i32 %a, 8
|
||||
%and1 = and i32 %shr1, 255
|
||||
%and2 = shl i32 %a, 8
|
||||
%shl1 = and i32 %and2, 65280
|
||||
%or = or i32 %and1, %shl1
|
||||
%conv = trunc i32 %or to i16
|
||||
ret i16 %conv
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue