diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp index 119b1cad632a..c2924abba17e 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp @@ -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(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); } } } diff --git a/llvm/test/Transforms/InstCombine/signext.ll b/llvm/test/Transforms/InstCombine/signext.ll index 1c52b62df4e0..49384d6275e8 100644 --- a/llvm/test/Transforms/InstCombine/signext.ll +++ b/llvm/test/Transforms/InstCombine/signext.ll @@ -8,8 +8,8 @@ define i32 @test1(i32 %x) { %tmp.3 = add i32 %tmp.2, 32768 ; [#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 ; [#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 ; [#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 ; [#uses=1] + %xor = xor i32 %shr, 67108864 ; [#uses=1] + %sub = add i32 %xor, -67108864 ; [#uses=1] + ret i32 %sub +; CHECK: @test8 +; CHECK: %sub = ashr i32 %x, 5 +; CHECK: ret i32 %sub +}