Index: llvm/lib/Analysis/InstructionSimplify.cpp =================================================================== --- llvm/lib/Analysis/InstructionSimplify.cpp +++ llvm/lib/Analysis/InstructionSimplify.cpp @@ -741,6 +741,33 @@ return Res; } +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); + + case Instruction::And: + case Instruction::Or: + 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 +899,11 @@ // "A-B" and "A-C" thus gains nothing, but costs compile time. Similarly // for threading over phi nodes. + // if (X == Y) + // X - Y -> 0 + if (Value *V = simplifyByDomEq(Instruction::Sub, Op0, Op1, Q)) + return V; + return nullptr; } @@ -1022,6 +1054,12 @@ } } + // if (X == Y) + // X / Y -> 1 + // X % Y -> 0 + if (Value *V = simplifyByDomEq(Opcode, Op0, Op1, Q)) + return V; + return nullptr; } @@ -2191,6 +2229,11 @@ } } + // if (X == Y) + // X & Y --> Y + if (Value *V = simplifyByDomEq(Instruction::And, Op0, Op1, Q)) + return V; + return nullptr; } @@ -2450,6 +2493,11 @@ } } + // if (X == Y) + // X | Y --> Y + if (Value *V = simplifyByDomEq(Instruction::Or, Op0, Op1, Q)) + return V; + return nullptr; } @@ -2525,6 +2573,11 @@ // "A^B" and "A^C" thus gains nothing, but costs compile time. Similarly // for threading over phi nodes. + // if (A == B) + // A ^ B -> 0 + 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 =================================================================== --- /dev/null +++ llvm/test/Transforms/InstSimplify/domcondition.ll @@ -0,0 +1,196 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -passes=instsimplify -S | FileCheck %s + +define i32 @xor_domcondition(i32 %x, i32 %y) { +; CHECK-LABEL: @xor_domcondition( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_END:%.*]] +; CHECK: cond.true: +; CHECK-NEXT: br label [[COND_END]] +; CHECK: cond.end: +; CHECK-NEXT: ret i32 0 +; +entry: + %cmp = icmp eq i32 %x, %y + br i1 %cmp, label %cond.true, label %cond.end + +cond.true: + %xor = xor i32 %x, %y + %mul = mul i32 %xor, %x + br label %cond.end + +cond.end: + %cond = phi i32 [ %mul, %cond.true ], [ 0, %entry ] + ret i32 %cond +} + +define i32 @sub_domcondition(i32 %x, i32 %y) { +; CHECK-LABEL: @sub_domcondition( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_END:%.*]] +; CHECK: cond.true: +; CHECK-NEXT: br label [[COND_END]] +; CHECK: cond.end: +; CHECK-NEXT: ret i32 0 +; +entry: + %cmp = icmp eq i32 %x, %y + br i1 %cmp, label %cond.true, label %cond.end + +cond.true: + %sub = sub i32 %x, %y + %mul = mul i32 %sub, %x + br label %cond.end + +cond.end: + %cond = phi i32 [ %mul, %cond.true ], [ 0, %entry ] + ret i32 %cond +} + +define i32 @udiv_domcondition(i32 %x, i32 %y) { +; CHECK-LABEL: @udiv_domcondition( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_END:%.*]] +; CHECK: cond.true: +; CHECK-NEXT: br label [[COND_END]] +; CHECK: cond.end: +; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[X]], [[COND_TRUE]] ], [ 0, [[ENTRY:%.*]] ] +; CHECK-NEXT: ret i32 [[COND]] +; +entry: + %cmp = icmp eq i32 %x, %y + br i1 %cmp, label %cond.true, label %cond.end + +cond.true: + %udiv = udiv i32 %x, %y + %mul = mul i32 %udiv, %x + br label %cond.end + +cond.end: + %cond = phi i32 [ %mul, %cond.true ], [ 0, %entry ] + ret i32 %cond +} + +define i32 @sdiv_domcondition(i32 %x, i32 %y) { +; CHECK-LABEL: @sdiv_domcondition( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_END:%.*]] +; CHECK: cond.true: +; CHECK-NEXT: br label [[COND_END]] +; CHECK: cond.end: +; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[X]], [[COND_TRUE]] ], [ 0, [[ENTRY:%.*]] ] +; CHECK-NEXT: ret i32 [[COND]] +; +entry: + %cmp = icmp eq i32 %x, %y + br i1 %cmp, label %cond.true, label %cond.end + +cond.true: + %sdiv = sdiv i32 %x, %y + %mul = mul i32 %sdiv, %x + br label %cond.end + +cond.end: + %cond = phi i32 [ %mul, %cond.true ], [ 0, %entry ] + ret i32 %cond +} + +define i32 @urem_domcondition(i32 %x, i32 %y) { +; CHECK-LABEL: @urem_domcondition( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_END:%.*]] +; CHECK: cond.true: +; CHECK-NEXT: br label [[COND_END]] +; CHECK: cond.end: +; CHECK-NEXT: ret i32 0 +; +entry: + %cmp = icmp eq i32 %x, %y + br i1 %cmp, label %cond.true, label %cond.end + +cond.true: + %urem = urem i32 %x, %y + %mul = mul i32 %urem, %x + br label %cond.end + +cond.end: + %cond = phi i32 [ %mul, %cond.true ], [ 0, %entry ] + ret i32 %cond +} + +define i32 @srem_domcondition(i32 %x, i32 %y) { +; CHECK-LABEL: @srem_domcondition( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_END:%.*]] +; CHECK: cond.true: +; CHECK-NEXT: br label [[COND_END]] +; CHECK: cond.end: +; CHECK-NEXT: ret i32 0 +; +entry: + %cmp = icmp eq i32 %x, %y + br i1 %cmp, label %cond.true, label %cond.end + +cond.true: + %srem = srem i32 %x, %y + %mul = mul i32 %srem, %x + br label %cond.end + +cond.end: + %cond = phi i32 [ %mul, %cond.true ], [ 0, %entry ] + ret i32 %cond +} + +define i32 @and_domcondition(i32 %x, i32 %y) { +; CHECK-LABEL: @and_domcondition( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_END:%.*]] +; CHECK: cond.true: +; CHECK-NEXT: br label [[COND_END]] +; CHECK: cond.end: +; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[Y]], [[COND_TRUE]] ], [ 0, [[ENTRY:%.*]] ] +; CHECK-NEXT: ret i32 [[COND]] +; +entry: + %cmp = icmp eq i32 %x, %y + br i1 %cmp, label %cond.true, label %cond.end + +cond.true: + %and = and i32 %x, %y + br label %cond.end + +cond.end: + %cond = phi i32 [ %and, %cond.true ], [ 0, %entry ] + ret i32 %cond +} + +define i32 @or_domcondition(i32 %x, i32 %y) { +; CHECK-LABEL: @or_domcondition( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_END:%.*]] +; CHECK: cond.true: +; CHECK-NEXT: br label [[COND_END]] +; CHECK: cond.end: +; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[Y]], [[COND_TRUE]] ], [ 0, [[ENTRY:%.*]] ] +; CHECK-NEXT: ret i32 [[COND]] +; +entry: + %cmp = icmp eq i32 %x, %y + br i1 %cmp, label %cond.true, label %cond.end + +cond.true: + %or = or i32 %x, %y + br label %cond.end + +cond.end: + %cond = phi i32 [ %or, %cond.true ], [ 0, %entry ] + ret i32 %cond +}