From 8999dd3c6862046cfd0b45b0c5101d3266975010 Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Sat, 22 Dec 2007 09:07:47 +0000 Subject: [PATCH] implement InstCombine/shift-trunc-shift.ll. This allows us to compile: #include int t1(double d) { return signbit(d); } into: _t1: movd %xmm0, %rax shrq $63, %rax ret instead of: _t1: movd %xmm0, %rax shrq $32, %rax shrl $31, %eax ret on x86-64. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@45311 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../Scalar/InstructionCombining.cpp | 44 +++++++++++++++++++ .../InstCombine/shift-trunc-shift.ll | 10 +++++ 2 files changed, 54 insertions(+) create mode 100644 test/Transforms/InstCombine/shift-trunc-shift.ll diff --git a/lib/Transforms/Scalar/InstructionCombining.cpp b/lib/Transforms/Scalar/InstructionCombining.cpp index e80f0ef8e05..d4278e3a7c7 100644 --- a/lib/Transforms/Scalar/InstructionCombining.cpp +++ b/lib/Transforms/Scalar/InstructionCombining.cpp @@ -6004,6 +6004,50 @@ Instruction *InstCombiner::FoldShiftByConstant(Value *Op0, ConstantInt *Op1, if (Instruction *NV = FoldOpIntoPhi(I)) return NV; + // Fold shift2(trunc(shift1(x,c1)), c2) -> trunc(shift2(shift1(x,c1),c2)) + if (TruncInst *TI = dyn_cast(Op0)) { + Instruction *TrOp = dyn_cast(TI->getOperand(0)); + // If 'shift2' is an ashr, we would have to get the sign bit into a funny + // place. Don't try to do this transformation in this case. Also, we + // require that the input operand is a shift-by-constant so that we have + // confidence that the shifts will get folded together. We could do this + // xform in more cases, but it is unlikely to be profitable. + if (TrOp && I.isLogicalShift() && TrOp->isShift() && + isa(TrOp->getOperand(1))) { + // Okay, we'll do this xform. Make the shift of shift. + Constant *ShAmt = ConstantExpr::getZExt(Op1, TrOp->getType()); + Instruction *NSh = BinaryOperator::create(I.getOpcode(), TrOp, ShAmt, + I.getName()); + InsertNewInstBefore(NSh, I); // (shift2 (shift1 & 0x00FF), c2) + + // For logical shifts, the truncation has the effect of making the high + // part of the register be zeros. Emulate this by inserting an AND to + // clear the top bits as needed. This 'and' will usually be zapped by + // other xforms later if dead. + unsigned SrcSize = TrOp->getType()->getPrimitiveSizeInBits(); + unsigned DstSize = TI->getType()->getPrimitiveSizeInBits(); + APInt MaskV(APInt::getLowBitsSet(SrcSize, DstSize)); + + // The mask we constructed says what the trunc would do if occurring + // between the shifts. We want to know the effect *after* the second + // shift. We know that it is a logical shift by a constant, so adjust the + // mask as appropriate. + if (I.getOpcode() == Instruction::Shl) + MaskV <<= Op1->getZExtValue(); + else { + assert(I.getOpcode() == Instruction::LShr && "Unknown logical shift"); + MaskV = MaskV.lshr(Op1->getZExtValue()); + } + + Instruction *And = BinaryOperator::createAnd(NSh, ConstantInt::get(MaskV), + TI->getName()); + InsertNewInstBefore(And, I); // shift1 & 0x00FF + + // Return the value truncated to the interesting size. + return new TruncInst(And, I.getType()); + } + } + if (Op0->hasOneUse()) { if (BinaryOperator *Op0BO = dyn_cast(Op0)) { // Turn ((X >> C) + Y) << C -> (X + (Y << C)) & (~0 << C) diff --git a/test/Transforms/InstCombine/shift-trunc-shift.ll b/test/Transforms/InstCombine/shift-trunc-shift.ll new file mode 100644 index 00000000000..bf9f4070fb9 --- /dev/null +++ b/test/Transforms/InstCombine/shift-trunc-shift.ll @@ -0,0 +1,10 @@ +; RUN: llvm-as < %s | opt -instcombine | llvm-dis | grep lshr.*63 + +define i32 @t1(i64 %d18) { +entry: + %tmp916 = lshr i64 %d18, 32 ; [#uses=1] + %tmp917 = trunc i64 %tmp916 to i32 ; [#uses=1] + %tmp10 = lshr i32 %tmp917, 31 ; [#uses=1] + ret i32 %tmp10 +} + -- 2.34.1