forked from OSchip/llvm-project
Simplify/generalize the xor+add->sign-extend instcombine.
llvm-svn: 94943
This commit is contained in:
parent
6276b2506d
commit
a2cc2875fc
|
@ -121,42 +121,26 @@ Instruction *InstCombiner::visitAdd(BinaryOperator &I) {
|
||||||
match(LHS, m_Xor(m_Value(XorLHS), m_ConstantInt(XorRHS)))) {
|
match(LHS, m_Xor(m_Value(XorLHS), m_ConstantInt(XorRHS)))) {
|
||||||
uint32_t TySizeBits = I.getType()->getScalarSizeInBits();
|
uint32_t TySizeBits = I.getType()->getScalarSizeInBits();
|
||||||
const APInt& RHSVal = cast<ConstantInt>(RHSC)->getValue();
|
const APInt& RHSVal = cast<ConstantInt>(RHSC)->getValue();
|
||||||
|
unsigned ExtendAmt = 0;
|
||||||
uint32_t Size = TySizeBits / 2;
|
// If we have ADD(XOR(AND(X, 0xFF), 0x80), 0xF..F80), it's a sext.
|
||||||
APInt C0080Val(APInt(TySizeBits, 1ULL).shl(Size - 1));
|
// If we have ADD(XOR(AND(X, 0xFF), 0xF..F80), 0x80), it's a sext.
|
||||||
APInt CFF80Val(-C0080Val);
|
if (XorRHS->getValue() == -RHSVal) {
|
||||||
do {
|
if (RHSVal.isPowerOf2())
|
||||||
if (TySizeBits > Size) {
|
ExtendAmt = TySizeBits - RHSVal.logBase2() - 1;
|
||||||
// If we have ADD(XOR(AND(X, 0xFF), 0x80), 0xF..F80), it's a sext.
|
else if (XorRHS->getValue().isPowerOf2())
|
||||||
// If we have ADD(XOR(AND(X, 0xFF), 0xF..F80), 0x80), it's a sext.
|
ExtendAmt = TySizeBits - XorRHS->getValue().logBase2() - 1;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
if (MiddleType) {
|
|
||||||
Value *NewTrunc = Builder->CreateTrunc(XorLHS, MiddleType, "sext");
|
if (ExtendAmt) {
|
||||||
return new SExtInst(NewTrunc, I.getType(), I.getName());
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,8 +8,8 @@ define i32 @test1(i32 %x) {
|
||||||
%tmp.3 = add i32 %tmp.2, 32768 ; <i32> [#uses=1]
|
%tmp.3 = add i32 %tmp.2, 32768 ; <i32> [#uses=1]
|
||||||
ret i32 %tmp.3
|
ret i32 %tmp.3
|
||||||
; CHECK: @test1
|
; CHECK: @test1
|
||||||
; CHECK: %sext1 = shl i32 %x, 16
|
; CHECK: %sext = shl i32 %x, 16
|
||||||
; CHECK: %tmp.3 = ashr i32 %sext1, 16
|
; CHECK: %tmp.3 = ashr i32 %sext, 16
|
||||||
; CHECK: ret i32 %tmp.3
|
; CHECK: ret i32 %tmp.3
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,8 +19,8 @@ define i32 @test2(i32 %x) {
|
||||||
%tmp.3 = add i32 %tmp.2, -32768 ; <i32> [#uses=1]
|
%tmp.3 = add i32 %tmp.2, -32768 ; <i32> [#uses=1]
|
||||||
ret i32 %tmp.3
|
ret i32 %tmp.3
|
||||||
; CHECK: @test2
|
; CHECK: @test2
|
||||||
; CHECK: %sext1 = shl i32 %x, 16
|
; CHECK: %sext = shl i32 %x, 16
|
||||||
; CHECK: %tmp.3 = ashr i32 %sext1, 16
|
; CHECK: %tmp.3 = ashr i32 %sext, 16
|
||||||
; CHECK: ret i32 %tmp.3
|
; CHECK: ret i32 %tmp.3
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,8 +50,8 @@ define i32 @test5(i32 %x) {
|
||||||
%tmp.3 = add i32 %tmp.2, -128 ; <i32> [#uses=1]
|
%tmp.3 = add i32 %tmp.2, -128 ; <i32> [#uses=1]
|
||||||
ret i32 %tmp.3
|
ret i32 %tmp.3
|
||||||
; CHECK: @test5
|
; CHECK: @test5
|
||||||
; CHECK: %sext1 = shl i32 %x, 24
|
; CHECK: %sext = shl i32 %x, 24
|
||||||
; CHECK: %tmp.3 = ashr i32 %sext1, 24
|
; CHECK: %tmp.3 = ashr i32 %sext, 24
|
||||||
; CHECK: ret i32 %tmp.3
|
; CHECK: ret i32 %tmp.3
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,3 +74,14 @@ define i32 @test7(i16 %P) {
|
||||||
; CHECK: %tmp.5 = sext i16 %P to i32
|
; CHECK: %tmp.5 = sext i16 %P to i32
|
||||||
; CHECK: ret i32 %tmp.5
|
; 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
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue