[llvm] r270853 - [InstCombine] Catch more bswap cases missed due to zext and truncs.
Chad Rosier via llvm-commits
llvm-commits at lists.llvm.org
Thu May 26 07:58:52 PDT 2016
Author: mcrosier
Date: Thu May 26 09:58:51 2016
New Revision: 270853
URL: http://llvm.org/viewvc/llvm-project?rev=270853&view=rev
Log:
[InstCombine] Catch more bswap cases missed due to zext and truncs.
Fixes PR27824.
Differential Revision: http://reviews.llvm.org/D20591.
Modified:
llvm/trunk/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
llvm/trunk/lib/Transforms/Utils/Local.cpp
llvm/trunk/test/Transforms/InstCombine/bswap.ll
Modified: llvm/trunk/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp?rev=270853&r1=270852&r2=270853&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp (original)
+++ llvm/trunk/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp Thu May 26 09:58:51 2016
@@ -1620,6 +1620,30 @@ Instruction *InstCombiner::visitAnd(Bina
/// 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(Binar
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))) &&
Modified: llvm/trunk/lib/Transforms/Utils/Local.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Utils/Local.cpp?rev=270853&r1=270852&r2=270853&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Utils/Local.cpp (original)
+++ llvm/trunk/lib/Transforms/Utils/Local.cpp Thu May 26 09:58:51 2016
@@ -1773,7 +1773,23 @@ collectBitParts(Value *V, bool MatchBSwa
// 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::recognizeBSwapOrBitReverseIdi
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::recognizeBSwapOrBitReverseIdi
// 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::recognizeBSwapOrBitReverseIdi
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;
Modified: llvm/trunk/test/Transforms/InstCombine/bswap.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/bswap.ll?rev=270853&r1=270852&r2=270853&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/bswap.ll (original)
+++ llvm/trunk/test/Transforms/InstCombine/bswap.ll Thu May 26 09:58:51 2016
@@ -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
+}
More information about the llvm-commits
mailing list