diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp --- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -4500,10 +4500,12 @@ // Sink any remaining PHI nodes directly into UnwindDest. Instruction *InsertPt = DestEHPad; - for (PHINode &PN : BB->phis()) { + for (auto I = BB->begin(), IE = BB->getFirstNonPHI()->getIterator(); + I != IE;) { // The iterator must be incremented here because the instructions are // being moved to another block. - if (PN.use_empty() || !PN.isUsedOutsideOfBlock(BB)) + PHINode *PN = cast(I++); + if (PN->use_empty() || !PN->isUsedOutsideOfBlock(BB)) // If the PHI node has no uses or all of its uses are in this basic // block (meaning they are debug or lifetime intrinsics), just leave // it. It will be erased when we erase BB below. @@ -4515,11 +4517,11 @@ // BB. In this case, the PHI value must reference itself. for (auto *pred : predecessors(UnwindDest)) if (pred != BB) - PN.addIncoming(&PN, pred); - PN.moveBefore(InsertPt); + PN->addIncoming(PN, pred); + PN->moveBefore(InsertPt); // Also, add a dummy incoming value for the original BB itself, // so that the PHI is well-formed until we drop said predecessor. - PN.addIncoming(UndefValue::get(PN.getType()), BB); + PN->addIncoming(UndefValue::get(PN->getType()), BB); } } diff --git a/llvm/test/Transforms/SimplifyCFG/cleanup-phis.ll b/llvm/test/Transforms/SimplifyCFG/cleanup-phis.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/SimplifyCFG/cleanup-phis.ll @@ -0,0 +1,43 @@ +; RUN: opt < %s -simplifycfg -S | FileCheck %s + +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown" + +; This is a regression test for a bug in which we used phis() in a for loop +; while deleting phi nodes. + +define void @cleanup_phis() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { +bb0: + invoke void @foo() + to label %bb1 unwind label %ehcleanup + +bb1: ; preds = %bb0 + invoke void @foo() + to label %invoke.cont unwind label %ehcleanup + +invoke.cont: ; preds = %bb1 + ret void + +ehcleanup: ; preds = %bb1, %bb0 + %phi0 = phi i32 [ 0, %bb0 ], [ 1, %bb1 ] + %phi1 = phi i32 [ 2, %bb0 ], [ 3, %bb1 ] + %0 = cleanuppad within none [] + cleanupret from %0 unwind label %catchswitch + +; These two phi nodes were originally in ehcleanup. Both phi nodes should be +; correctly copied to this catchswitch BB. +; CHECK: catchswitch: +; CHECK-NEXT: %phi0 = phi i32 [ 0, %bb0 ], [ 1, %bb1 ] +; CHECK-NEXT: %phi1 = phi i32 [ 2, %bb0 ], [ 3, %bb1 ] +catchswitch: ; preds = %ehcleanup + %1 = catchswitch within none [label %catch] unwind to caller + +catch: ; preds = %catchswitch + %2 = catchpad within %1 [i8* null] + call void @bar(i32 %phi0, i32 %phi1) + unreachable +} + +declare void @foo() +declare void @bar(i32, i32) +declare i32 @__gxx_wasm_personality_v0(...)