diff --git a/include/llvm/Analysis/InstructionSimplify.h b/include/llvm/Analysis/InstructionSimplify.h index 653971377d1..7588d6b53bc 100644 --- a/include/llvm/Analysis/InstructionSimplify.h +++ b/include/llvm/Analysis/InstructionSimplify.h @@ -35,16 +35,31 @@ namespace llvm { Value *SimplifySubInst(Value *LHS, Value *RHS, bool isNSW, bool isNUW, const TargetData *TD = 0, const DominatorTree *DT = 0); - /// SimplifyAndInst - Given operands for an And, see if we can - /// fold the result. If not, this returns null. - Value *SimplifyAndInst(Value *LHS, Value *RHS, const TargetData *TD = 0, - const DominatorTree *DT = 0); - /// SimplifyMulInst - Given operands for a Mul, see if we can /// fold the result. If not, this returns null. Value *SimplifyMulInst(Value *LHS, Value *RHS, const TargetData *TD = 0, const DominatorTree *DT = 0); + /// SimplifyShlInst - Given operands for a Shl, see if we can + /// fold the result. If not, this returns null. + Value *SimplifyShlInst(Value *Op0, Value *Op1, const TargetData *TD = 0, + const DominatorTree *DT = 0); + + /// SimplifyLShrInst - Given operands for a LShr, see if we can + /// fold the result. If not, this returns null. + Value *SimplifyLShrInst(Value *Op0, Value *Op1, const TargetData *TD = 0, + const DominatorTree *DT = 0); + + /// SimplifyAShrInst - Given operands for a AShr, see if we can + /// fold the result. If not, this returns null. + Value *SimplifyAShrInst(Value *Op0, Value *Op1, const TargetData *TD = 0, + const DominatorTree *DT = 0); + + /// SimplifyAndInst - Given operands for an And, see if we can + /// fold the result. If not, this returns null. + Value *SimplifyAndInst(Value *LHS, Value *RHS, const TargetData *TD = 0, + const DominatorTree *DT = 0); + /// SimplifyOrInst - Given operands for an Or, see if we can /// fold the result. If not, this returns null. Value *SimplifyOrInst(Value *LHS, Value *RHS, const TargetData *TD = 0, diff --git a/lib/Analysis/InstructionSimplify.cpp b/lib/Analysis/InstructionSimplify.cpp index d4b89cebd59..29ce5cfd430 100644 --- a/lib/Analysis/InstructionSimplify.cpp +++ b/lib/Analysis/InstructionSimplify.cpp @@ -684,6 +684,136 @@ Value *llvm::SimplifyMulInst(Value *Op0, Value *Op1, const TargetData *TD, return ::SimplifyMulInst(Op0, Op1, TD, DT, RecursionLimit); } +/// SimplifyShlInst - Given operands for an Shl, see if we can +/// fold the result. If not, this returns null. +static Value *SimplifyShlInst(Value *Op0, Value *Op1, const TargetData *TD, + const DominatorTree *DT, unsigned MaxRecurse) { + if (Constant *C0 = dyn_cast(Op0)) { + if (Constant *C1 = dyn_cast(Op1)) { + Constant *Ops[] = { C0, C1 }; + return ConstantFoldInstOperands(Instruction::Shl, C0->getType(), Ops, 2, + TD); + } + } + + // 0 << X -> 0 + if (match(Op0, m_Zero())) + return Op0; + + // X << 0 -> X + if (match(Op1, m_Zero())) + return Op0; + + // undef << X -> 0 + if (isa(Op0)) + return Constant::getNullValue(Op0->getType()); + + // X << undef -> undef because it may shift by the bitwidth. + if (isa(Op1)) + return Op1; + + // Shifting by the bitwidth or more is undefined. + if (ConstantInt *CI = dyn_cast(Op1)) + if (CI->getValue().getLimitedValue() >= + Op0->getType()->getScalarSizeInBits()) + return UndefValue::get(Op0->getType()); + + return 0; +} + +Value *llvm::SimplifyShlInst(Value *Op0, Value *Op1, const TargetData *TD, + const DominatorTree *DT) { + return ::SimplifyShlInst(Op0, Op1, TD, DT, RecursionLimit); +} + +/// SimplifyLShrInst - Given operands for an LShr, see if we can +/// fold the result. If not, this returns null. +static Value *SimplifyLShrInst(Value *Op0, Value *Op1, const TargetData *TD, + const DominatorTree *DT, unsigned MaxRecurse) { + if (Constant *C0 = dyn_cast(Op0)) { + if (Constant *C1 = dyn_cast(Op1)) { + Constant *Ops[] = { C0, C1 }; + return ConstantFoldInstOperands(Instruction::LShr, C0->getType(), Ops, 2, + TD); + } + } + + // 0 >> X -> 0 + if (match(Op0, m_Zero())) + return Op0; + + // undef >>l X -> 0 + if (isa(Op0)) + return Constant::getNullValue(Op0->getType()); + + // X >> 0 -> X + if (match(Op1, m_Zero())) + return Op0; + + // X >> undef -> undef because it may shift by the bitwidth. + if (isa(Op1)) + return Op1; + + // Shifting by the bitwidth or more is undefined. + if (ConstantInt *CI = dyn_cast(Op1)) + if (CI->getValue().getLimitedValue() >= + Op0->getType()->getScalarSizeInBits()) + return UndefValue::get(Op0->getType()); + + return 0; +} + +Value *llvm::SimplifyLShrInst(Value *Op0, Value *Op1, const TargetData *TD, + const DominatorTree *DT) { + return ::SimplifyLShrInst(Op0, Op1, TD, DT, RecursionLimit); +} + +/// SimplifyAShrInst - Given operands for an AShr, see if we can +/// fold the result. If not, this returns null. +static Value *SimplifyAShrInst(Value *Op0, Value *Op1, const TargetData *TD, + const DominatorTree *DT, unsigned MaxRecurse) { + if (Constant *C0 = dyn_cast(Op0)) { + if (Constant *C1 = dyn_cast(Op1)) { + Constant *Ops[] = { C0, C1 }; + return ConstantFoldInstOperands(Instruction::AShr, C0->getType(), Ops, 2, + TD); + } + } + + // 0 >> X -> 0 + if (match(Op0, m_Zero())) + return Op0; + + // all ones >>a X -> all ones + if (match(Op0, m_AllOnes())) + return Op0; + + // undef >>a X -> all ones + if (isa(Op0)) + return Constant::getAllOnesValue(Op0->getType()); + + // X >> 0 -> X + if (match(Op1, m_Zero())) + return Op0; + + // X >> undef -> undef because it may shift by the bitwidth. + if (isa(Op1)) + return Op1; + + // Shifting by the bitwidth or more is undefined. + if (ConstantInt *CI = dyn_cast(Op1)) + if (CI->getValue().getLimitedValue() >= + Op0->getType()->getScalarSizeInBits()) + return UndefValue::get(Op0->getType()); + + return 0; +} + +Value *llvm::SimplifyAShrInst(Value *Op0, Value *Op1, const TargetData *TD, + const DominatorTree *DT) { + return ::SimplifyAShrInst(Op0, Op1, TD, DT, RecursionLimit); +} + /// SimplifyAndInst - Given operands for an And, see if we can /// fold the result. If not, this returns null. static Value *SimplifyAndInst(Value *Op0, Value *Op1, const TargetData *TD, @@ -1267,6 +1397,9 @@ static Value *SimplifyBinOp(unsigned Opcode, Value *LHS, Value *RHS, /* isNUW */ false, TD, DT, MaxRecurse); case Instruction::Mul: return SimplifyMulInst(LHS, RHS, TD, DT, MaxRecurse); + case Instruction::Shl: return SimplifyShlInst(LHS, RHS, TD, DT, MaxRecurse); + case Instruction::LShr: return SimplifyLShrInst(LHS, RHS, TD, DT, MaxRecurse); + case Instruction::AShr: return SimplifyAShrInst(LHS, RHS, TD, DT, MaxRecurse); case Instruction::And: return SimplifyAndInst(LHS, RHS, TD, DT, MaxRecurse); case Instruction::Or: return SimplifyOrInst(LHS, RHS, TD, DT, MaxRecurse); case Instruction::Xor: return SimplifyXorInst(LHS, RHS, TD, DT, MaxRecurse); @@ -1345,6 +1478,15 @@ Value *llvm::SimplifyInstruction(Instruction *I, const TargetData *TD, case Instruction::Mul: Result = SimplifyMulInst(I->getOperand(0), I->getOperand(1), TD, DT); break; + case Instruction::Shl: + Result = SimplifyShlInst(I->getOperand(0), I->getOperand(1), TD, DT); + break; + case Instruction::LShr: + Result = SimplifyLShrInst(I->getOperand(0), I->getOperand(1), TD, DT); + break; + case Instruction::AShr: + Result = SimplifyAShrInst(I->getOperand(0), I->getOperand(1), TD, DT); + break; case Instruction::And: Result = SimplifyAndInst(I->getOperand(0), I->getOperand(1), TD, DT); break; diff --git a/lib/Transforms/InstCombine/InstCombineShifts.cpp b/lib/Transforms/InstCombine/InstCombineShifts.cpp index a0c5ef5338f..fe791ddaf7b 100644 --- a/lib/Transforms/InstCombine/InstCombineShifts.cpp +++ b/lib/Transforms/InstCombine/InstCombineShifts.cpp @@ -13,6 +13,7 @@ #include "InstCombine.h" #include "llvm/IntrinsicInst.h" +#include "llvm/Analysis/InstructionSimplify.h" #include "llvm/Support/PatternMatch.h" using namespace llvm; using namespace PatternMatch; @@ -21,25 +22,6 @@ Instruction *InstCombiner::commonShiftTransforms(BinaryOperator &I) { assert(I.getOperand(1)->getType() == I.getOperand(0)->getType()); Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1); - // shl X, 0 == X and shr X, 0 == X - // shl 0, X == 0 and shr 0, X == 0 - if (Op1 == Constant::getNullValue(Op1->getType()) || - Op0 == Constant::getNullValue(Op0->getType())) - return ReplaceInstUsesWith(I, Op0); - - if (isa(Op0)) { - if (I.getOpcode() == Instruction::AShr) // undef >>s X -> undef - return ReplaceInstUsesWith(I, Op0); - else // undef << X -> 0, undef >>u X -> 0 - return ReplaceInstUsesWith(I, Constant::getNullValue(I.getType())); - } - if (isa(Op1)) { - if (I.getOpcode() == Instruction::AShr) // X >>s undef -> X - return ReplaceInstUsesWith(I, Op0); - else // X << undef, X >>u undef -> 0 - return ReplaceInstUsesWith(I, Constant::getNullValue(I.getType())); - } - // See if we can fold away this shift. if (SimplifyDemandedInstructionBits(I)) return &I; @@ -635,10 +617,15 @@ Instruction *InstCombiner::FoldShiftByConstant(Value *Op0, ConstantInt *Op1, } Instruction *InstCombiner::visitShl(BinaryOperator &I) { + if (Value *V = SimplifyShlInst(I.getOperand(0), I.getOperand(1), TD)) + return ReplaceInstUsesWith(I, V); return commonShiftTransforms(I); } Instruction *InstCombiner::visitLShr(BinaryOperator &I) { + if (Value *V = SimplifyLShrInst(I.getOperand(0), I.getOperand(1), TD)) + return ReplaceInstUsesWith(I, V); + if (Instruction *R = commonShiftTransforms(I)) return R; @@ -665,17 +652,14 @@ Instruction *InstCombiner::visitLShr(BinaryOperator &I) { } Instruction *InstCombiner::visitAShr(BinaryOperator &I) { + if (Value *V = SimplifyAShrInst(I.getOperand(0), I.getOperand(1), TD)) + return ReplaceInstUsesWith(I, V); + if (Instruction *R = commonShiftTransforms(I)) return R; Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1); - - if (ConstantInt *CSI = dyn_cast(Op0)) { - // ashr int -1, X = -1 (for any arithmetic shift rights of ~0) - if (CSI->isAllOnesValue()) - return ReplaceInstUsesWith(I, CSI); - } - + if (ConstantInt *Op1C = dyn_cast(Op1)) { // If the input is a SHL by the same constant (ashr (shl X, C), C), then we // have a sign-extend idiom. diff --git a/lib/VMCore/ConstantFold.cpp b/lib/VMCore/ConstantFold.cpp index 27676562d4d..3dc78470ff8 100644 --- a/lib/VMCore/ConstantFold.cpp +++ b/lib/VMCore/ConstantFold.cpp @@ -977,8 +977,8 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode, return Constant::getNullValue(C1->getType()); // X lshr undef -> 0 // undef lshr X -> 0 case Instruction::AShr: - if (!isa(C2)) - return C1; // undef ashr X --> undef + if (!isa(C2)) // undef ashr X --> all ones + return Constant::getAllOnesValue(C1->getType()); else if (isa(C1)) return C1; // undef ashr undef -> undef else diff --git a/test/Transforms/InstCombine/shift.ll b/test/Transforms/InstCombine/shift.ll index 4f6939d6323..3ae74b5dae3 100644 --- a/test/Transforms/InstCombine/shift.ll +++ b/test/Transforms/InstCombine/shift.ll @@ -35,18 +35,32 @@ define i32 @test4(i8 %A) { define i32 @test5(i32 %A) { ; CHECK: @test5 -; CHECK: ret i32 0 +; CHECK: ret i32 undef %B = lshr i32 %A, 32 ;; shift all bits out ret i32 %B } define i32 @test5a(i32 %A) { ; CHECK: @test5a -; CHECK: ret i32 0 +; CHECK: ret i32 undef %B = shl i32 %A, 32 ;; shift all bits out ret i32 %B } +define i32 @test5b() { +; CHECK: @test5b +; CHECK: ret i32 -1 + %B = ashr i32 undef, 2 ;; top two bits must be equal, so not undef + ret i32 %B +} + +define i32 @test5b2(i32 %A) { +; CHECK: @test5b2 +; CHECK: ret i32 -1 + %B = ashr i32 undef, %A ;; top %A bits must be equal, so not undef + ret i32 %B +} + define i32 @test6(i32 %A) { ; CHECK: @test6 ; CHECK-NEXT: mul i32 %A, 6