Simplify/generalize the xor+add->sign-extend instcombine.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@94943 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Eli Friedman 2010-01-31 04:29:12 +00:00
parent 694488f477
commit be7cfa6033
2 changed files with 36 additions and 41 deletions

View File

@ -121,42 +121,26 @@ Instruction *InstCombiner::visitAdd(BinaryOperator &I) {
match(LHS, m_Xor(m_Value(XorLHS), m_ConstantInt(XorRHS)))) {
uint32_t TySizeBits = I.getType()->getScalarSizeInBits();
const APInt& RHSVal = cast<ConstantInt>(RHSC)->getValue();
uint32_t Size = TySizeBits / 2;
APInt C0080Val(APInt(TySizeBits, 1ULL).shl(Size - 1));
APInt CFF80Val(-C0080Val);
do {
if (TySizeBits > Size) {
// If we have ADD(XOR(AND(X, 0xFF), 0x80), 0xF..F80), it's a sext.
// If we have ADD(XOR(AND(X, 0xFF), 0xF..F80), 0x80), it's a sext.
if ((RHSVal == CFF80Val && XorRHS->getValue() == C0080Val) ||
(RHSVal == C0080Val && XorRHS->getValue() == CFF80Val)) {
// This is a sign extend if the top bits are known zero.
if (!MaskedValueIsZero(XorLHS,
APInt::getHighBitsSet(TySizeBits, TySizeBits - Size)))
Size = 0; // Not a sign ext, but can't be any others either.
break;
}
}
Size >>= 1;
C0080Val = APIntOps::lshr(C0080Val, Size);
CFF80Val = APIntOps::ashr(CFF80Val, Size);
} while (Size >= 1);
// FIXME: This shouldn't be necessary. When the backends can handle types
// with funny bit widths then this switch statement should be removed. It
// is just here to get the size of the "middle" type back up to something
// that the back ends can handle.
const Type *MiddleType = 0;
switch (Size) {
default: break;
case 32:
case 16:
case 8: MiddleType = IntegerType::get(I.getContext(), Size); break;
unsigned ExtendAmt = 0;
// If we have ADD(XOR(AND(X, 0xFF), 0x80), 0xF..F80), it's a sext.
// If we have ADD(XOR(AND(X, 0xFF), 0xF..F80), 0x80), it's a sext.
if (XorRHS->getValue() == -RHSVal) {
if (RHSVal.isPowerOf2())
ExtendAmt = TySizeBits - RHSVal.logBase2() - 1;
else if (XorRHS->getValue().isPowerOf2())
ExtendAmt = TySizeBits - XorRHS->getValue().logBase2() - 1;
}
if (MiddleType) {
Value *NewTrunc = Builder->CreateTrunc(XorLHS, MiddleType, "sext");
return new SExtInst(NewTrunc, I.getType(), I.getName());
if (ExtendAmt) {
APInt Mask = APInt::getHighBitsSet(TySizeBits, ExtendAmt);
if (!MaskedValueIsZero(XorLHS, Mask))
ExtendAmt = 0;
}
if (ExtendAmt) {
Constant *ShAmt = ConstantInt::get(I.getType(), ExtendAmt);
Value *NewShl = Builder->CreateShl(XorLHS, ShAmt, "sext");
return BinaryOperator::CreateAShr(NewShl, ShAmt);
}
}
}

View File

@ -8,8 +8,8 @@ define i32 @test1(i32 %x) {
%tmp.3 = add i32 %tmp.2, 32768 ; <i32> [#uses=1]
ret i32 %tmp.3
; CHECK: @test1
; CHECK: %sext1 = shl i32 %x, 16
; CHECK: %tmp.3 = ashr i32 %sext1, 16
; CHECK: %sext = shl i32 %x, 16
; CHECK: %tmp.3 = ashr i32 %sext, 16
; CHECK: ret i32 %tmp.3
}
@ -19,8 +19,8 @@ define i32 @test2(i32 %x) {
%tmp.3 = add i32 %tmp.2, -32768 ; <i32> [#uses=1]
ret i32 %tmp.3
; CHECK: @test2
; CHECK: %sext1 = shl i32 %x, 16
; CHECK: %tmp.3 = ashr i32 %sext1, 16
; CHECK: %sext = shl i32 %x, 16
; CHECK: %tmp.3 = ashr i32 %sext, 16
; CHECK: ret i32 %tmp.3
}
@ -50,8 +50,8 @@ define i32 @test5(i32 %x) {
%tmp.3 = add i32 %tmp.2, -128 ; <i32> [#uses=1]
ret i32 %tmp.3
; CHECK: @test5
; CHECK: %sext1 = shl i32 %x, 24
; CHECK: %tmp.3 = ashr i32 %sext1, 24
; CHECK: %sext = shl i32 %x, 24
; CHECK: %tmp.3 = ashr i32 %sext, 24
; CHECK: ret i32 %tmp.3
}
@ -74,3 +74,14 @@ define i32 @test7(i16 %P) {
; CHECK: %tmp.5 = sext i16 %P to i32
; CHECK: ret i32 %tmp.5
}
define i32 @test8(i32 %x) nounwind readnone {
entry:
%shr = lshr i32 %x, 5 ; <i32> [#uses=1]
%xor = xor i32 %shr, 67108864 ; <i32> [#uses=1]
%sub = add i32 %xor, -67108864 ; <i32> [#uses=1]
ret i32 %sub
; CHECK: @test8
; CHECK: %sub = ashr i32 %x, 5
; CHECK: ret i32 %sub
}