Index: llvm/lib/Analysis/InstructionSimplify.cpp =================================================================== --- llvm/lib/Analysis/InstructionSimplify.cpp +++ llvm/lib/Analysis/InstructionSimplify.cpp @@ -741,6 +741,35 @@ 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) { + 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); + + // TODO: And/Or can return Op0/Op1 direct. + 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 +901,9 @@ // "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)) + return V; + return nullptr; } @@ -1022,6 +1054,9 @@ } } + if (Value *V = simplifyByDomEq(Opcode, Op0, Op1, Q)) + return V; + return nullptr; } @@ -2525,6 +2560,9 @@ // "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)) + return V; + return nullptr; } Index: llvm/test/Transforms/InstCombine/usub-overflow-known-by-implied-cond.ll =================================================================== --- llvm/test/Transforms/InstCombine/usub-overflow-known-by-implied-cond.ll +++ llvm/test/Transforms/InstCombine/usub-overflow-known-by-implied-cond.ll @@ -123,8 +123,7 @@ ; 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 ; Index: llvm/test/Transforms/InstSimplify/domcondition.ll =================================================================== --- llvm/test/Transforms/InstSimplify/domcondition.ll +++ llvm/test/Transforms/InstSimplify/domcondition.ll @@ -7,11 +7,9 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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