From: Chris Lattner Date: Wed, 9 Feb 2011 17:15:04 +0000 (+0000) Subject: Teach instsimplify some tricks about exact/nuw/nsw shifts. X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=81a0dc911586c77421c2255aa417dc9b350b9e20;p=oota-llvm.git Teach instsimplify some tricks about exact/nuw/nsw shifts. improve interfaces to instsimplify to take this info. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@125196 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/Analysis/InstructionSimplify.h b/include/llvm/Analysis/InstructionSimplify.h index 9ad7bc6e8a5..dff1ba2f7be 100644 --- a/include/llvm/Analysis/InstructionSimplify.h +++ b/include/llvm/Analysis/InstructionSimplify.h @@ -57,17 +57,18 @@ namespace llvm { /// 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); + Value *SimplifyShlInst(Value *Op0, Value *Op1, bool isNSW, bool isNUW, + 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); + Value *SimplifyLShrInst(Value *Op0, Value *Op1, bool isExact, + 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, + Value *SimplifyAShrInst(Value *Op0, Value *Op1, bool isExact, + const TargetData *TD = 0, const DominatorTree *DT = 0); /// SimplifyAndInst - Given operands for an And, see if we can diff --git a/lib/Analysis/InstructionSimplify.cpp b/lib/Analysis/InstructionSimplify.cpp index 20489b4dca6..3f30b25c957 100644 --- a/lib/Analysis/InstructionSimplify.cpp +++ b/lib/Analysis/InstructionSimplify.cpp @@ -29,7 +29,7 @@ using namespace llvm; using namespace llvm::PatternMatch; -#define RecursionLimit 3 +enum { RecursionLimit = 3 }; STATISTIC(NumExpand, "Number of expansions"); STATISTIC(NumFactor , "Number of factorizations"); @@ -946,8 +946,9 @@ static Value *SimplifyShift(unsigned Opcode, Value *Op0, Value *Op1, /// 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) { +static Value *SimplifyShlInst(Value *Op0, Value *Op1, bool isNSW, bool isNUW, + const TargetData *TD, const DominatorTree *DT, + unsigned MaxRecurse) { if (Value *V = SimplifyShift(Instruction::Shl, Op0, Op1, TD, DT, MaxRecurse)) return V; @@ -955,18 +956,24 @@ static Value *SimplifyShlInst(Value *Op0, Value *Op1, const TargetData *TD, if (match(Op0, m_Undef())) return Constant::getNullValue(Op0->getType()); + // (X >> A) << A -> X + Value *X; + if (match(Op0, m_Shr(m_Value(X), m_Specific(Op1))) && + cast(Op0)->isExact()) + return X; return 0; } -Value *llvm::SimplifyShlInst(Value *Op0, Value *Op1, const TargetData *TD, - const DominatorTree *DT) { - return ::SimplifyShlInst(Op0, Op1, TD, DT, RecursionLimit); +Value *llvm::SimplifyShlInst(Value *Op0, Value *Op1, bool isNSW, bool isNUW, + const TargetData *TD, const DominatorTree *DT) { + return ::SimplifyShlInst(Op0, Op1, isNSW, isNUW, 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) { +static Value *SimplifyLShrInst(Value *Op0, Value *Op1, bool isExact, + const TargetData *TD, const DominatorTree *DT, + unsigned MaxRecurse) { if (Value *V = SimplifyShift(Instruction::LShr, Op0, Op1, TD, DT, MaxRecurse)) return V; @@ -974,18 +981,25 @@ static Value *SimplifyLShrInst(Value *Op0, Value *Op1, const TargetData *TD, if (match(Op0, m_Undef())) return Constant::getNullValue(Op0->getType()); + // (X << A) >> A -> X + Value *X; + if (match(Op0, m_Shl(m_Value(X), m_Specific(Op1))) && + cast(Op0)->hasNoUnsignedWrap()) + return X; + return 0; } -Value *llvm::SimplifyLShrInst(Value *Op0, Value *Op1, const TargetData *TD, - const DominatorTree *DT) { - return ::SimplifyLShrInst(Op0, Op1, TD, DT, RecursionLimit); +Value *llvm::SimplifyLShrInst(Value *Op0, Value *Op1, bool isExact, + const TargetData *TD, const DominatorTree *DT) { + return ::SimplifyLShrInst(Op0, Op1, isExact, 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) { +static Value *SimplifyAShrInst(Value *Op0, Value *Op1, bool isExact, + const TargetData *TD, const DominatorTree *DT, + unsigned MaxRecurse) { if (Value *V = SimplifyShift(Instruction::AShr, Op0, Op1, TD, DT, MaxRecurse)) return V; @@ -997,12 +1011,18 @@ static Value *SimplifyAShrInst(Value *Op0, Value *Op1, const TargetData *TD, if (match(Op0, m_Undef())) return Constant::getAllOnesValue(Op0->getType()); + // (X << A) >> A -> X + Value *X; + if (match(Op0, m_Shl(m_Value(X), m_Specific(Op1))) && + cast(Op0)->hasNoSignedWrap()) + return X; + return 0; } -Value *llvm::SimplifyAShrInst(Value *Op0, Value *Op1, const TargetData *TD, - const DominatorTree *DT) { - return ::SimplifyAShrInst(Op0, Op1, TD, DT, RecursionLimit); +Value *llvm::SimplifyAShrInst(Value *Op0, Value *Op1, bool isExact, + const TargetData *TD, const DominatorTree *DT) { + return ::SimplifyAShrInst(Op0, Op1, isExact, TD, DT, RecursionLimit); } /// SimplifyAndInst - Given operands for an And, see if we can @@ -1037,12 +1057,12 @@ static Value *SimplifyAndInst(Value *Op0, Value *Op1, const TargetData *TD, return Op0; // A & ~A = ~A & A = 0 - Value *A = 0, *B = 0; - if ((match(Op0, m_Not(m_Value(A))) && A == Op1) || - (match(Op1, m_Not(m_Value(A))) && A == Op0)) + if (match(Op0, m_Not(m_Specific(Op1))) || + match(Op1, m_Not(m_Specific(Op0)))) return Constant::getNullValue(Op0->getType()); // (A | ?) & A = A + Value *A = 0, *B = 0; if (match(Op0, m_Or(m_Value(A), m_Value(B))) && (A == Op1 || B == Op1)) return Op1; @@ -1126,12 +1146,12 @@ static Value *SimplifyOrInst(Value *Op0, Value *Op1, const TargetData *TD, return Op1; // A | ~A = ~A | A = -1 - Value *A = 0, *B = 0; - if ((match(Op0, m_Not(m_Value(A))) && A == Op1) || - (match(Op1, m_Not(m_Value(A))) && A == Op0)) + if (match(Op0, m_Not(m_Specific(Op1))) || + match(Op1, m_Not(m_Specific(Op0)))) return Constant::getAllOnesValue(Op0->getType()); // (A & ?) | A = A + Value *A = 0, *B = 0; if (match(Op0, m_And(m_Value(A), m_Value(B))) && (A == Op1 || B == Op1)) return Op1; @@ -1206,9 +1226,8 @@ static Value *SimplifyXorInst(Value *Op0, Value *Op1, const TargetData *TD, return Constant::getNullValue(Op0->getType()); // A ^ ~A = ~A ^ A = -1 - Value *A = 0; - if ((match(Op0, m_Not(m_Value(A))) && A == Op1) || - (match(Op1, m_Not(m_Value(A))) && A == Op0)) + if (match(Op0, m_Not(m_Specific(Op1))) || + match(Op1, m_Not(m_Specific(Op0)))) return Constant::getAllOnesValue(Op0->getType()); // Try some generic simplifications for associative operations. @@ -1794,21 +1813,25 @@ static Value *SimplifyBinOp(unsigned Opcode, Value *LHS, Value *RHS, const TargetData *TD, const DominatorTree *DT, unsigned MaxRecurse) { switch (Opcode) { - case Instruction::Add: return SimplifyAddInst(LHS, RHS, /* isNSW */ false, - /* isNUW */ false, TD, DT, - MaxRecurse); - case Instruction::Sub: return SimplifySubInst(LHS, RHS, /* isNSW */ false, - /* isNUW */ false, TD, DT, - MaxRecurse); - case Instruction::Mul: return SimplifyMulInst(LHS, RHS, TD, DT, MaxRecurse); + case Instruction::Add: + return SimplifyAddInst(LHS, RHS, /* isNSW */ false, /* isNUW */ false, + TD, DT, MaxRecurse); + case Instruction::Sub: + return SimplifySubInst(LHS, RHS, /* isNSW */ false, /* isNUW */ false, + TD, DT, MaxRecurse); + case Instruction::Mul: return SimplifyMulInst (LHS, RHS, TD, DT, MaxRecurse); case Instruction::SDiv: return SimplifySDivInst(LHS, RHS, TD, DT, MaxRecurse); case Instruction::UDiv: return SimplifyUDivInst(LHS, RHS, TD, DT, MaxRecurse); case Instruction::FDiv: return SimplifyFDivInst(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::Shl: + return SimplifyShlInst(LHS, RHS, /*NSW*/false, /*NUW*/false, + TD, DT, MaxRecurse); + case Instruction::LShr: + return SimplifyLShrInst(LHS, RHS, /*isexact*/ false, TD, DT, MaxRecurse); + case Instruction::AShr: + return SimplifyAShrInst(LHS, RHS, /*isexact*/false, 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::Or: return SimplifyOrInst (LHS, RHS, TD, DT, MaxRecurse); case Instruction::Xor: return SimplifyXorInst(LHS, RHS, TD, DT, MaxRecurse); default: if (Constant *CLHS = dyn_cast(LHS)) @@ -1895,13 +1918,20 @@ Value *llvm::SimplifyInstruction(Instruction *I, const TargetData *TD, Result = SimplifyFDivInst(I->getOperand(0), I->getOperand(1), TD, DT); break; case Instruction::Shl: - Result = SimplifyShlInst(I->getOperand(0), I->getOperand(1), TD, DT); + Result = SimplifyShlInst(I->getOperand(0), I->getOperand(1), + cast(I)->hasNoSignedWrap(), + cast(I)->hasNoUnsignedWrap(), + TD, DT); break; case Instruction::LShr: - Result = SimplifyLShrInst(I->getOperand(0), I->getOperand(1), TD, DT); + Result = SimplifyLShrInst(I->getOperand(0), I->getOperand(1), + cast(I)->isExact(), + TD, DT); break; case Instruction::AShr: - Result = SimplifyAShrInst(I->getOperand(0), I->getOperand(1), TD, DT); + Result = SimplifyAShrInst(I->getOperand(0), I->getOperand(1), + cast(I)->isExact(), + TD, DT); break; case Instruction::And: Result = SimplifyAndInst(I->getOperand(0), I->getOperand(1), TD, DT); diff --git a/lib/Transforms/InstCombine/InstCombineShifts.cpp b/lib/Transforms/InstCombine/InstCombineShifts.cpp index 988f29e16a4..395d79d5a74 100644 --- a/lib/Transforms/InstCombine/InstCombineShifts.cpp +++ b/lib/Transforms/InstCombine/InstCombineShifts.cpp @@ -617,13 +617,16 @@ Instruction *InstCombiner::FoldShiftByConstant(Value *Op0, ConstantInt *Op1, } Instruction *InstCombiner::visitShl(BinaryOperator &I) { - if (Value *V = SimplifyShlInst(I.getOperand(0), I.getOperand(1), TD)) + if (Value *V = SimplifyShlInst(I.getOperand(0), I.getOperand(1), + I.hasNoSignedWrap(), I.hasNoUnsignedWrap(), + TD)) return ReplaceInstUsesWith(I, V); return commonShiftTransforms(I); } Instruction *InstCombiner::visitLShr(BinaryOperator &I) { - if (Value *V = SimplifyLShrInst(I.getOperand(0), I.getOperand(1), TD)) + if (Value *V = SimplifyLShrInst(I.getOperand(0), I.getOperand(1), + I.isExact(), TD)) return ReplaceInstUsesWith(I, V); if (Instruction *R = commonShiftTransforms(I)) @@ -652,7 +655,8 @@ Instruction *InstCombiner::visitLShr(BinaryOperator &I) { } Instruction *InstCombiner::visitAShr(BinaryOperator &I) { - if (Value *V = SimplifyAShrInst(I.getOperand(0), I.getOperand(1), TD)) + if (Value *V = SimplifyAShrInst(I.getOperand(0), I.getOperand(1), + I.isExact(), TD)) return ReplaceInstUsesWith(I, V); if (Instruction *R = commonShiftTransforms(I)) diff --git a/test/Transforms/InstSimplify/exact-nsw-nuw.ll b/test/Transforms/InstSimplify/exact-nsw-nuw.ll new file mode 100644 index 00000000000..f3a804eb5b5 --- /dev/null +++ b/test/Transforms/InstSimplify/exact-nsw-nuw.ll @@ -0,0 +1,44 @@ +; RUN: opt < %s -instsimplify -S | FileCheck %s + +; PR8862 + +; CHECK: @shift1 +; CHECK: ret i32 %A +define i32 @shift1(i32 %A, i32 %B) { + %C = lshr exact i32 %A, %B + %D = shl nuw i32 %C, %B + ret i32 %D +} + +; CHECK: @shift2 +; CHECK: lshr +; CHECK: ret i32 %D +define i32 @shift2(i32 %A, i32 %B) { + %C = lshr i32 %A, %B + %D = shl nuw i32 %C, %B + ret i32 %D +} + +; CHECK: @shift3 +; CHECK: ret i32 %A +define i32 @shift3(i32 %A, i32 %B) { + %C = ashr exact i32 %A, %B + %D = shl nuw i32 %C, %B + ret i32 %D +} + +; CHECK: @shift4 +; CHECK: ret i32 %A +define i32 @shift4(i32 %A, i32 %B) { + %C = shl nuw i32 %A, %B + %D = lshr i32 %C, %B + ret i32 %D +} + +; CHECK: @shift5 +; CHECK: ret i32 %A +define i32 @shift5(i32 %A, i32 %B) { + %C = shl nsw i32 %A, %B + %D = ashr i32 %C, %B + ret i32 %D +}