diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp index 0f0c0bcb96e17..0db6b85318ddd 100644 --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -741,6 +741,42 @@ static Constant *computePointerDifference(const DataLayout &DL, Value *LHS, return Res; } +/// Test if there is a dominating equivalence condition for the +/// two operands. If there is, try to reduce the binary operation +/// between the two operands. +/// Example: Op0 - Op1 --> 0 when Op0 == Op1 +static Value *simplifyByDomEq(unsigned Opcode, Value *Op0, Value *Op1, + const SimplifyQuery &Q, unsigned MaxRecurse) { + // Recursive run it can not get any benefit + if (MaxRecurse != RecursionLimit) + return nullptr; + + Optional Imp = + isImpliedByDomCondition(CmpInst::ICMP_EQ, Op0, Op1, Q.CxtI, Q.DL); + if (Imp && *Imp) { + Type *Ty = Op0->getType(); + switch (Opcode) { + case Instruction::Sub: + case Instruction::Xor: + case Instruction::URem: + case Instruction::SRem: + return Constant::getNullValue(Ty); + + case Instruction::SDiv: + case Instruction::UDiv: + return ConstantInt::get(Ty, 1); + + case Instruction::And: + case Instruction::Or: + // Could be either one - choose Op1 since that's more likely a constant. + return Op1; + default: + break; + } + } + return nullptr; +} + /// Given operands for a Sub, see if we can fold the result. /// If not, this returns null. static Value *simplifySubInst(Value *Op0, Value *Op1, bool isNSW, bool isNUW, @@ -872,6 +908,9 @@ static Value *simplifySubInst(Value *Op0, Value *Op1, bool isNSW, bool isNUW, // "A-B" and "A-C" thus gains nothing, but costs compile time. Similarly // for threading over phi nodes. + if (Value *V = simplifyByDomEq(Instruction::Sub, Op0, Op1, Q, MaxRecurse)) + return V; + return nullptr; } @@ -947,7 +986,8 @@ Value *llvm::simplifyMulInst(Value *Op0, Value *Op1, const SimplifyQuery &Q) { /// Check for common or similar folds of integer division or integer remainder. /// This applies to all 4 opcodes (sdiv/udiv/srem/urem). static Value *simplifyDivRem(Instruction::BinaryOps Opcode, Value *Op0, - Value *Op1, const SimplifyQuery &Q) { + Value *Op1, const SimplifyQuery &Q, + unsigned MaxRecurse) { bool IsDiv = (Opcode == Instruction::SDiv || Opcode == Instruction::UDiv); bool IsSigned = (Opcode == Instruction::SDiv || Opcode == Instruction::SRem); @@ -1022,6 +1062,9 @@ static Value *simplifyDivRem(Instruction::BinaryOps Opcode, Value *Op0, } } + if (Value *V = simplifyByDomEq(Opcode, Op0, Op1, Q, MaxRecurse)) + return V; + return nullptr; } @@ -1103,7 +1146,7 @@ static Value *simplifyDiv(Instruction::BinaryOps Opcode, Value *Op0, Value *Op1, if (Constant *C = foldOrCommuteConstant(Opcode, Op0, Op1, Q)) return C; - if (Value *V = simplifyDivRem(Opcode, Op0, Op1, Q)) + if (Value *V = simplifyDivRem(Opcode, Op0, Op1, Q, MaxRecurse)) return V; bool IsSigned = Opcode == Instruction::SDiv; @@ -1147,7 +1190,7 @@ static Value *simplifyRem(Instruction::BinaryOps Opcode, Value *Op0, Value *Op1, if (Constant *C = foldOrCommuteConstant(Opcode, Op0, Op1, Q)) return C; - if (Value *V = simplifyDivRem(Opcode, Op0, Op1, Q)) + if (Value *V = simplifyDivRem(Opcode, Op0, Op1, Q, MaxRecurse)) return V; // (X % Y) % Y -> X % Y @@ -2191,6 +2234,9 @@ static Value *simplifyAndInst(Value *Op0, Value *Op1, const SimplifyQuery &Q, } } + if (Value *V = simplifyByDomEq(Instruction::And, Op0, Op1, Q, MaxRecurse)) + return V; + return nullptr; } @@ -2450,6 +2496,9 @@ static Value *simplifyOrInst(Value *Op0, Value *Op1, const SimplifyQuery &Q, } } + if (Value *V = simplifyByDomEq(Instruction::Or, Op0, Op1, Q, MaxRecurse)) + return V; + return nullptr; } @@ -2525,6 +2574,9 @@ static Value *simplifyXorInst(Value *Op0, Value *Op1, const SimplifyQuery &Q, // "A^B" and "A^C" thus gains nothing, but costs compile time. Similarly // for threading over phi nodes. + if (Value *V = simplifyByDomEq(Instruction::Xor, Op0, Op1, Q, MaxRecurse)) + return V; + return nullptr; } diff --git a/llvm/test/Transforms/InstCombine/usub-overflow-known-by-implied-cond.ll b/llvm/test/Transforms/InstCombine/usub-overflow-known-by-implied-cond.ll index eb83865e3e5cc..90ca39a70a0bb 100644 --- a/llvm/test/Transforms/InstCombine/usub-overflow-known-by-implied-cond.ll +++ b/llvm/test/Transforms/InstCombine/usub-overflow-known-by-implied-cond.ll @@ -123,8 +123,7 @@ define i32 @test5(i32 %a, i32 %b) { ; CHECK: bb1: ; CHECK-NEXT: br i1 false, label [[BB3]], label [[BB2:%.*]] ; CHECK: bb2: -; CHECK-NEXT: [[SUB1:%.*]] = sub nuw i32 [[A]], [[B]] -; CHECK-NEXT: ret i32 [[SUB1]] +; CHECK-NEXT: ret i32 0 ; CHECK: bb3: ; CHECK-NEXT: ret i32 0 ; diff --git a/llvm/test/Transforms/InstSimplify/domcondition.ll b/llvm/test/Transforms/InstSimplify/domcondition.ll index 3977cbfd98ab3..b6508c329e3c4 100644 --- a/llvm/test/Transforms/InstSimplify/domcondition.ll +++ b/llvm/test/Transforms/InstSimplify/domcondition.ll @@ -7,11 +7,9 @@ define i32 @xor_domcondition(i32 %x, i32 %y) { ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_END:%.*]] ; CHECK: cond.true: -; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X]], [[Y]] ; CHECK-NEXT: br label [[COND_END]] ; CHECK: cond.end: -; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[XOR]], [[COND_TRUE]] ], [ 0, [[ENTRY:%.*]] ] -; CHECK-NEXT: ret i32 [[COND]] +; CHECK-NEXT: ret i32 0 ; entry: %cmp = icmp eq i32 %x, %y @@ -32,11 +30,9 @@ define i32 @sub_domcondition(i32 %x, i32 %y) { ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_END:%.*]] ; CHECK: cond.true: -; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[X]], [[Y]] ; CHECK-NEXT: br label [[COND_END]] ; CHECK: cond.end: -; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[SUB]], [[COND_TRUE]] ], [ 0, [[ENTRY:%.*]] ] -; CHECK-NEXT: ret i32 [[COND]] +; CHECK-NEXT: ret i32 0 ; entry: %cmp = icmp eq i32 %x, %y @@ -57,10 +53,9 @@ define i32 @udiv_domcondition(i32 %x, i32 %y) { ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_END:%.*]] ; CHECK: cond.true: -; CHECK-NEXT: [[UDIV:%.*]] = udiv i32 [[X]], [[Y]] ; CHECK-NEXT: br label [[COND_END]] ; CHECK: cond.end: -; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[UDIV]], [[COND_TRUE]] ], [ 0, [[ENTRY:%.*]] ] +; CHECK-NEXT: [[COND:%.*]] = phi i32 [ 1, [[COND_TRUE]] ], [ 0, [[ENTRY:%.*]] ] ; CHECK-NEXT: ret i32 [[COND]] ; entry: @@ -82,10 +77,9 @@ define i32 @sdiv_domcondition(i32 %x, i32 %y) { ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_END:%.*]] ; CHECK: cond.true: -; CHECK-NEXT: [[SDIV:%.*]] = sdiv i32 [[X]], [[Y]] ; CHECK-NEXT: br label [[COND_END]] ; CHECK: cond.end: -; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[SDIV]], [[COND_TRUE]] ], [ 0, [[ENTRY:%.*]] ] +; CHECK-NEXT: [[COND:%.*]] = phi i32 [ 1, [[COND_TRUE]] ], [ 0, [[ENTRY:%.*]] ] ; CHECK-NEXT: ret i32 [[COND]] ; entry: @@ -107,11 +101,9 @@ define i32 @urem_domcondition(i32 %x, i32 %y) { ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_END:%.*]] ; CHECK: cond.true: -; CHECK-NEXT: [[UREM:%.*]] = urem i32 [[X]], [[Y]] ; CHECK-NEXT: br label [[COND_END]] ; CHECK: cond.end: -; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[UREM]], [[COND_TRUE]] ], [ 0, [[ENTRY:%.*]] ] -; CHECK-NEXT: ret i32 [[COND]] +; CHECK-NEXT: ret i32 0 ; entry: %cmp = icmp eq i32 %x, %y @@ -132,11 +124,9 @@ define i32 @srem_domcondition(i32 %x, i32 %y) { ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_END:%.*]] ; CHECK: cond.true: -; CHECK-NEXT: [[SREM:%.*]] = srem i32 [[X]], [[Y]] ; CHECK-NEXT: br label [[COND_END]] ; CHECK: cond.end: -; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[SREM]], [[COND_TRUE]] ], [ 0, [[ENTRY:%.*]] ] -; CHECK-NEXT: ret i32 [[COND]] +; CHECK-NEXT: ret i32 0 ; entry: %cmp = icmp eq i32 %x, %y @@ -158,10 +148,9 @@ define i32 @and_domcondition(i32 %x, i32 %y) { ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_END:%.*]] ; CHECK: cond.true: -; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[Y]] ; CHECK-NEXT: br label [[COND_END]] ; CHECK: cond.end: -; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[AND]], [[COND_TRUE]] ], [ 0, [[ENTRY:%.*]] ] +; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[Y]], [[COND_TRUE]] ], [ 0, [[ENTRY:%.*]] ] ; CHECK-NEXT: ret i32 [[COND]] ; entry: @@ -184,10 +173,9 @@ define i32 @or_domcondition(i32 %x, i32 %y) { ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_END:%.*]] ; CHECK: cond.true: -; CHECK-NEXT: [[OR:%.*]] = or i32 [[X]], [[Y]] ; CHECK-NEXT: br label [[COND_END]] ; CHECK: cond.end: -; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[OR]], [[COND_TRUE]] ], [ 0, [[ENTRY:%.*]] ] +; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[Y]], [[COND_TRUE]] ], [ 0, [[ENTRY:%.*]] ] ; CHECK-NEXT: ret i32 [[COND]] ; entry: