Index: lib/Transforms/Scalar/EarlyCSE.cpp =================================================================== --- lib/Transforms/Scalar/EarlyCSE.cpp +++ lib/Transforms/Scalar/EarlyCSE.cpp @@ -461,6 +461,42 @@ if (!BB->getSinglePredecessor()) ++CurrentGeneration; + // If this node has a single predecessor which ends in a conditional branch, + // we can infer the value of the branch condition given that we took this + // path. We need the single predeccesor to ensure there's not another path + // which reaches this block where the condition might hold a different + // value. Since we're adding this to the scoped hash table (like any other + // def), it will have been popped if we encounter a future merge block. + if (BasicBlock *Pred = BB->getSinglePredecessor()) + // TODO: handle switch with case value as well + if (auto *BI = dyn_cast(Pred->getTerminator())) + if (BI->isConditional()) + if (auto *CondInst = dyn_cast(BI->getCondition())) + if (SimpleValue::canHandle(CondInst)) { + assert(BI->getSuccessor(0) == BB || BI->getSuccessor(1) == BB); + auto *ConditionalConstant = (BI->getSuccessor(0) == BB) ? + ConstantInt::getTrue(BB->getContext()) : + ConstantInt::getFalse(BB->getContext()); + AvailableValues.insert(CondInst, ConditionalConstant); + DEBUG(dbgs() << "EarlyCSE CVP: Add conditional value for '" + << CondInst->getName() << "' as " << *ConditionalConstant + << " in " << BB->getName() << "\n"); + // Replace all dominated uses with the known value + SmallVector ToUpdate; + for (User *U : CondInst->users()) + if (auto *IU = dyn_cast(U)) + if (DT.dominates(BB, IU->getParent())) + ToUpdate.push_back(IU); + for (Instruction *UserI : ToUpdate) { + DEBUG(dbgs() << "EarlyCSE CVP: Replace dominated use of '" + << CondInst->getName() << "' as " + << *ConditionalConstant << " in " << *UserI << "\n"); + UserI->replaceUsesOfWith(CondInst, ConditionalConstant); + } + // TODO: Exploit icmp eq %v, C to get value for C + // TODO: Look through and/or sequences to get more known conditions + } + /// LastStore - Keep track of the last non-volatile store that we saw... for /// as long as there in no instruction that reads memory. If we see a store /// to the same location, we delete the dead store. This zaps trivial dead Index: test/Transforms/EarlyCSE/conditional.ll =================================================================== --- /dev/null +++ test/Transforms/EarlyCSE/conditional.ll @@ -0,0 +1,101 @@ +; RUN: opt -early-cse -S < %s | FileCheck %s + +define i1 @test(i8* %p) { +; CHECK-LABEL: @test +entry: + %cnd1 = icmp eq i8* %p, null + br i1 %cnd1, label %taken, label %untaken + +taken: +; CHECK-LABEL: taken: +; CHECK-NEXT: ret i1 true + %cnd2 = icmp eq i8* %p, null + ret i1 %cnd2 + +untaken: +; CHECK-LABEL: untaken: +; CHECK-NEXT: ret i1 false + %cnd3 = icmp eq i8* %p, null + ret i1 %cnd3 +} + +define i1 @test_neg1(i8* %p) { +; CHECK-LABEL: @test_neg1 +entry: + %cnd1 = icmp eq i8* %p, null + br i1 %cnd1, label %taken, label %untaken + +taken: + br label %merge + +untaken: + br label %merge + +merge: +; CHECK-LABEL: merge: +; CHECK-NEXT: ret i1 %cnd1 + %cnd3 = icmp eq i8* %p, null + ret i1 %cnd3 +} + +define i1 @test_neg2(i8* %p) { +; CHECK-LABEL: @test_neg2 +entry: + %cnd1 = icmp eq i8* %p, null + br i1 %cnd1, label %merge, label %merge + +merge: +; CHECK-LABEL: merge: +; CHECK-NEXT: ret i1 %cnd1 + %cnd3 = icmp eq i8* %p, null + ret i1 %cnd3 +} + +; Replace a use rather than CSE +define i1 @test2(i8* %p) { +; CHECK-LABEL: @test2 +entry: + %cnd = icmp eq i8* %p, null + br i1 %cnd, label %taken, label %untaken + +taken: +; CHECK-LABEL: taken: +; CHECK-NEXT: ret i1 true + ret i1 %cnd + +untaken: +; CHECK-LABEL: untaken: +; CHECK-NEXT: ret i1 false + ret i1 %cnd +} + +define i1 @test2_neg1(i8* %p) { +; CHECK-LABEL: @test2_neg1 +entry: + %cnd1 = icmp eq i8* %p, null + br i1 %cnd1, label %taken, label %untaken + +taken: + br label %merge + +untaken: + br label %merge + +merge: +; CHECK-LABEL: merge: +; CHECK-NEXT: ret i1 %cnd1 + ret i1 %cnd1 +} + +define i1 @test2_neg2(i8* %p) { +; CHECK-LABEL: @test2_neg2 +entry: + %cnd1 = icmp eq i8* %p, null + br i1 %cnd1, label %merge, label %merge + +merge: +; CHECK-LABEL: merge: +; CHECK-NEXT: ret i1 %cnd1 + ret i1 %cnd1 +} +