Index: llvm/trunk/lib/Transforms/Utils/SimplifyCFG.cpp =================================================================== --- llvm/trunk/lib/Transforms/Utils/SimplifyCFG.cpp +++ llvm/trunk/lib/Transforms/Utils/SimplifyCFG.cpp @@ -3371,7 +3371,7 @@ return true; } -bool SimplifyCFGOpt::SimplifyCleanupReturn(CleanupReturnInst *RI) { +static bool removeEmptyCleanup(CleanupReturnInst *RI) { // If this is a trivial cleanup pad that executes no instructions, it can be // eliminated. If the cleanup pad continues to the caller, any predecessor // that is an EH pad will be updated to continue to the caller and any @@ -3489,6 +3489,49 @@ return true; } +// Try to merge two cleanuppads together. +static bool mergeCleanupPad(CleanupReturnInst *RI) { + // Skip any cleanuprets which unwind to caller, there is nothing to merge + // with. + BasicBlock *UnwindDest = RI->getUnwindDest(); + if (!UnwindDest) + return false; + + // This cleanupret isn't the only predecessor of this cleanuppad, it wouldn't + // be safe to merge without code duplication. + if (UnwindDest->getSinglePredecessor() != RI->getParent()) + return false; + + // Verify that our cleanuppad's unwind destination is another cleanuppad. + auto *SuccessorCleanupPad = dyn_cast(&UnwindDest->front()); + if (!SuccessorCleanupPad) + return false; + + CleanupPadInst *PredecessorCleanupPad = RI->getCleanupPad(); + // Replace any uses of the successor cleanupad with the predecessor pad + // The only cleanuppad uses should be this cleanupret, it's cleanupret and + // funclet bundle operands. + SuccessorCleanupPad->replaceAllUsesWith(PredecessorCleanupPad); + // Remove the old cleanuppad. + SuccessorCleanupPad->eraseFromParent(); + // Now, we simply replace the cleanupret with a branch to the unwind + // destination. + BranchInst::Create(UnwindDest, RI->getParent()); + RI->eraseFromParent(); + + return true; +} + +bool SimplifyCFGOpt::SimplifyCleanupReturn(CleanupReturnInst *RI) { + if (removeEmptyCleanup(RI)) + return true; + + if (mergeCleanupPad(RI)) + return true; + + return false; +} + bool SimplifyCFGOpt::SimplifyReturn(ReturnInst *RI, IRBuilder<> &Builder) { BasicBlock *BB = RI->getParent(); if (!BB->getFirstNonPHIOrDbg()->isTerminator()) return false; @@ -4978,7 +5021,7 @@ if (!BI2 || !BI2->isIdenticalTo(BI)) continue; - // We've found an identical block. Update our predeccessors to take that + // We've found an identical block. Update our predecessors to take that // path instead and make ourselves dead. SmallSet Preds; Preds.insert(pred_begin(BB), pred_end(BB)); Index: llvm/trunk/test/Transforms/SimplifyCFG/merge-cleanuppads.ll =================================================================== --- llvm/trunk/test/Transforms/SimplifyCFG/merge-cleanuppads.ll +++ llvm/trunk/test/Transforms/SimplifyCFG/merge-cleanuppads.ll @@ -0,0 +1,39 @@ +; RUN: opt -S -simplifycfg < %s | FileCheck %s +target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-windows-msvc18.0.0" + +; Function Attrs: uwtable +define void @test1() #0 personality i32 (...)* @__CxxFrameHandler3 { +entry: + invoke void @may_throw(i32 3) + to label %invoke.cont unwind label %ehcleanup + +invoke.cont: ; preds = %entry + tail call void @may_throw(i32 2) #2 + tail call void @may_throw(i32 1) #2 + ret void + +ehcleanup: ; preds = %entry + %cp = cleanuppad within none [] + tail call void @may_throw(i32 2) #2 [ "funclet"(token %cp) ] + cleanupret from %cp unwind label %ehcleanup2 + +ehcleanup2: + %cp2 = cleanuppad within none [] + tail call void @may_throw(i32 1) #2 [ "funclet"(token %cp2) ] + cleanupret from %cp2 unwind to caller +} + +; CHECK-LABEL: define void @test1( +; CHECK: %[[cp:.*]] = cleanuppad within none [] +; CHECK: tail call void @may_throw(i32 2) #2 [ "funclet"(token %[[cp]]) ] +; CHECK: tail call void @may_throw(i32 1) #2 [ "funclet"(token %[[cp]]) ] +; CHECK: cleanupret from %[[cp]] unwind to caller + +declare void @may_throw(i32) #1 + +declare i32 @__CxxFrameHandler3(...) + +attributes #0 = { uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind }