diff --git a/lib/Transforms/Scalar/InstructionCombining.cpp b/lib/Transforms/Scalar/InstructionCombining.cpp index b8b64951668..c35bc49e512 100644 --- a/lib/Transforms/Scalar/InstructionCombining.cpp +++ b/lib/Transforms/Scalar/InstructionCombining.cpp @@ -2085,7 +2085,7 @@ unsigned InstCombiner::ComputeNumSignBits(Value *V, unsigned Depth) const{ case Instruction::AShr: Tmp = ComputeNumSignBits(U->getOperand(0), Depth+1); - // SRA X, C -> adds C sign bits. + // ashr X, C -> adds C sign bits. if (ConstantInt *C = dyn_cast(U->getOperand(1))) { Tmp += C->getZExtValue(); if (Tmp > TyBits) Tmp = TyBits; @@ -8195,6 +8195,33 @@ Instruction *InstCombiner::visitSExt(SExtInst &CI) { } } } + + // See if the value being truncated is already sign extended. If so, just + // eliminate the trunc/sext pair. + if (getOpcode(Src) == Instruction::Trunc) { + Value *Op = cast(Src)->getOperand(0); + unsigned OpBits = cast(Op->getType())->getBitWidth(); + unsigned MidBits = cast(Src->getType())->getBitWidth(); + unsigned DestBits = cast(CI.getType())->getBitWidth(); + unsigned NumSignBits = ComputeNumSignBits(Op); + + if (OpBits == DestBits) { + // Op is i32, Mid is i8, and Dest is i32. If Op has more than 24 sign + // bits, it is already ready. + if (NumSignBits > DestBits-MidBits) + return ReplaceInstUsesWith(CI, Op); + } else if (OpBits < DestBits) { + // Op is i32, Mid is i8, and Dest is i64. If Op has more than 24 sign + // bits, just sext from i32. + if (NumSignBits > OpBits-MidBits) + return new SExtInst(Op, CI.getType(), "tmp"); + } else { + // Op is i64, Mid is i8, and Dest is i32. If Op has more than 56 sign + // bits, just truncate to i32. + if (NumSignBits > OpBits-MidBits) + return new TruncInst(Op, CI.getType(), "tmp"); + } + } return 0; } diff --git a/test/Transforms/InstCombine/sext-misc.ll b/test/Transforms/InstCombine/sext-misc.ll index da69e85ff5f..d49c63cca6e 100644 --- a/test/Transforms/InstCombine/sext-misc.ll +++ b/test/Transforms/InstCombine/sext-misc.ll @@ -43,3 +43,10 @@ define i64 @voo(i32 %x) { %s = sext i32 %u to i64 ret i64 %s } +define i32 @woo(i8 %a, i32 %f, i1 %p, i32* %z) { + %d = ashr i32 %f, 24 + %e = select i1 %p, i32 %d, i32 0 + %s = trunc i32 %e to i16 + %n = sext i16 %s to i32 + ret i32 %n +}