Index: lib/Transforms/Scalar/JumpThreading.cpp =================================================================== --- lib/Transforms/Scalar/JumpThreading.cpp +++ lib/Transforms/Scalar/JumpThreading.cpp @@ -805,43 +805,78 @@ // If we're branching on a conditional, LVI might be able to determine // it's value at the branch instruction. We only handle comparisons // against a constant at this time. - // TODO: This should be extended to handle switches as well. - BranchInst *CondBr = dyn_cast(BB->getTerminator()); Constant *CondConst = dyn_cast(CondCmp->getOperand(1)); - if (CondBr && CondConst) { - // We should have returned as soon as we turn a conditional branch to - // unconditional. Because its no longer interesting as far as jump - // threading is concerned. - assert(CondBr->isConditional() && "Threading on unconditional terminator"); - + if (CondConst) { + // Figure out what the comparison result in. LazyValueInfo::Tristate Ret = - LVI->getPredicateAt(CondCmp->getPredicate(), CondCmp->getOperand(0), - CondConst, CondBr); + LVI->getPredicateAt(CondCmp->getPredicate(), CondCmp->getOperand(0), + CondConst, BB->getTerminator()); + + // We may be able to simplify the terminator instruction. if (Ret != LazyValueInfo::Unknown) { - unsigned ToRemove = Ret == LazyValueInfo::True ? 1 : 0; - unsigned ToKeep = Ret == LazyValueInfo::True ? 0 : 1; - CondBr->getSuccessor(ToRemove)->removePredecessor(BB, true); - BranchInst::Create(CondBr->getSuccessor(ToKeep), CondBr); - CondBr->eraseFromParent(); - if (CondCmp->use_empty()) - CondCmp->eraseFromParent(); - else if (CondCmp->getParent() == BB) { - // If the fact we just learned is true for all uses of the - // condition, replace it with a constant value - auto *CI = Ret == LazyValueInfo::True ? - ConstantInt::getTrue(CondCmp->getType()) : - ConstantInt::getFalse(CondCmp->getType()); - CondCmp->replaceAllUsesWith(CI); - CondCmp->eraseFromParent(); + bool TermFolded = false; + // Simplify BranchInst. + BranchInst *CondBr = dyn_cast(BB->getTerminator()); + if (CondBr) { + // We should have returned as soon as we turn a conditional branch to + // unconditional. Because its no longer interesting as far as jump + // threading is concerned. + assert(CondBr->isConditional() && + "Threading on unconditional terminator"); + + unsigned ToRemove = Ret == LazyValueInfo::True ? 1 : 0; + unsigned ToKeep = Ret == LazyValueInfo::True ? 0 : 1; + CondBr->getSuccessor(ToRemove)->removePredecessor(BB, true); + BranchInst::Create(CondBr->getSuccessor(ToKeep), CondBr); + CondBr->eraseFromParent(); + TermFolded = true; + } + + // Simplify SwitchInst. + SwitchInst *SI = dyn_cast(BB->getTerminator()); + if (SI) { + LLVMContext &Ctx = SI->getContext(); + SwitchInst::CaseIt Target = SI->findCaseValue( + LazyValueInfo::True ? ConstantInt::getTrue(Ctx) + : ConstantInt::getFalse(Ctx)); + // Remove the unexecutable edges. + for (SwitchInst::CaseIt i = SI->case_begin(), e = SI->case_end(); + i != e; ++i) { + if (i == Target) + continue; + i.getCaseSuccessor()->removePredecessor(BB, true); + } + + BranchInst::Create(Target.getCaseSuccessor(), SI); + SI->eraseFromParent(); + TermFolded = true; + } + + // The terminator instruction has been simplified, try to simplify the + // cond's users and delete it if it has no user. + if (TermFolded) { + if (CondCmp->use_empty()) + CondCmp->eraseFromParent(); + else if (CondCmp->getParent() == BB) { + // If the fact we just learned is true for all uses of the + // condition, replace it with a constant value + auto *CI = Ret == LazyValueInfo::True + ? ConstantInt::getTrue(CondCmp->getType()) + : ConstantInt::getFalse(CondCmp->getType()); + CondCmp->replaceAllUsesWith(CI); + CondCmp->eraseFromParent(); + } + return true; } - return true; } + } - // We did not manage to simplify this branch, try to see whether - // CondCmp depends on a known phi-select pattern. + // We did not manage to simplify this branch, try to see whether + // CondCmp depends on a known select-phi-br pattern. + // FIXME: TryToUnfoldSelect should also handle switch(i1) as well. + if (CondConst && isa(BB->getTerminator())) if (TryToUnfoldSelect(CondCmp, BB)) return true; - } } // Check for some cases that are worth simplifying. Right now we want to look Index: test/Transforms/JumpThreading/basic.ll =================================================================== --- test/Transforms/JumpThreading/basic.ll +++ test/Transforms/JumpThreading/basic.ll @@ -4,6 +4,44 @@ declare i32 @f2() declare void @f3() +; Make sure this switch is folded to a unconditional branch to %rf. +; CHECK-LABEL: define i32 @fold_switch( +; CHECK-NOT: switch +; CHECK-NOT: rt: +; CHECK-NOT: rg: +; CHECK: ret +define i32 @fold_switch(i8* %b) { +entry: + %retval = alloca i32, align 4 + %a = load i8, i8* %b, !range !5 + %A = icmp ult i8 %a, 5 + switch i1 %A, label %sw.default [ + i1 0, label %rt + i1 1, label %rf + ] + +rt: + store i32 11, i32* %retval, align 4 + br label %return + +rf: + store i32 22, i32* %retval, align 4 + br label %return + +sw.default: + br label %sw.epilog + +sw.epilog: + store i32 33, i32* %retval, align 4 + br label %return + +return: + %ret = load i32, i32* %retval, align 4 + ret i32 %ret +} + +!5 = !{ i8 2, i8 3 } + define i32 @test1(i1 %cond) { ; CHECK-LABEL: @test1( @@ -580,3 +618,4 @@ ; CHECK: attributes [[NOD]] = { noduplicate } ; CHECK: attributes [[CON]] = { convergent } +