Index: llvm/lib/Transforms/Utils/DemoteRegToStack.cpp =================================================================== --- llvm/lib/Transforms/Utils/DemoteRegToStack.cpp +++ llvm/lib/Transforms/Utils/DemoteRegToStack.cpp @@ -92,8 +92,19 @@ BasicBlock::iterator InsertPt; if (!I.isTerminator()) { InsertPt = ++I.getIterator(); + // Don't insert before PHI nodes or landingpad instrs. for (; isa(InsertPt) || InsertPt->isEHPad(); ++InsertPt) - /* empty */; // Don't insert before PHI nodes or landingpad instrs. + if (isa(InsertPt)) + break; + if (CatchSwitchInst *CSI = dyn_cast(InsertPt)) { + for (BasicBlock *Handler : CSI->handlers()) { + new StoreInst(&I, Slot, &*Handler->getFirstInsertionPt()); + } + if (CSI->hasUnwindDest()) { + new StoreInst(&I, Slot, &*CSI->getUnwindDest()->getFirstInsertionPt()); + } + return Slot; + } } else { InvokeInst &II = cast(I); InsertPt = II.getNormalDest()->getFirstInsertionPt(); @@ -138,14 +149,27 @@ // Insert a load in place of the PHI and replace all uses. BasicBlock::iterator InsertPt = P->getIterator(); - + // Don't insert before PHI nodes or landingpad instrs. for (; isa(InsertPt) || InsertPt->isEHPad(); ++InsertPt) - /* empty */; // Don't insert before PHI nodes or landingpad instrs. - - Value *V = - new LoadInst(P->getType(), Slot, P->getName() + ".reload", &*InsertPt); - P->replaceAllUsesWith(V); - + if (isa(InsertPt)) + break; + if (CatchSwitchInst *CSI = dyn_cast(InsertPt)) { + // We need a separate load before each actual use of the PHI + SmallVector users; + for (User *U : P->users()) { + Instruction *User = cast(U); + users.push_back(User); + } + for (Instruction *User : users) { + Value *V = + new LoadInst(P->getType(), Slot, P->getName() + ".reload", User); + User->replaceUsesOfWith(P, V); + } + } else { + Value *V = + new LoadInst(P->getType(), Slot, P->getName() + ".reload", &*InsertPt); + P->replaceAllUsesWith(V); + } // Delete PHI. P->eraseFromParent(); return Slot; Index: llvm/test/Transforms/Reg2Mem/catchswitch-crach2.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/Reg2Mem/catchswitch-crach2.ll @@ -0,0 +1,81 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -passes=reg2mem -S < %s | FileCheck %s +%"type1" = type { i32 (...)**, i8*, i8*, i8**, i8**, i8*, i8*, i8**, i8**, i32, i32, i32*, i32*, %"type2"* } +%"type2" = type { [8 x i8], %"type3"* } +%"type3" = type { %"type4", %"type4"**, i64, i32, i8, %"type6" } +%"type4" = type { %"type5", i32 } +%"type5" = type { i32 (...)** } +%"type6" = type { i8*, i8 } + +declare i32 @__CxxFrameHandler3(...) + +define void @testreg2mem(i8* %_Val) personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { +; CHECK-LABEL: @testreg2mem( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[_STATE_3_REG2MEM:%.*]] = alloca i32, align 4 +; CHECK-NEXT: [[_STATE_3_REG2MEM1:%.*]] = alloca i32, align 4 +; CHECK-NEXT: %"reg2mem alloca point" = bitcast i32 0 to i32 +; CHECK-NEXT: store i32 0, i32* [[_STATE_3_REG2MEM1]], align 4 +; CHECK-NEXT: [[CALL_I166167:%.*]] = invoke noundef i64 undef(%type1* noundef nonnull align 8 dereferenceable(104) undef, i8* noundef [[_VAL:%.*]], i64 noundef undef) +; CHECK-NEXT: to label [[IF_END56:%.*]] unwind label [[CATCH_DISPATCH:%.*]] +; CHECK: if.end56: +; CHECK-NEXT: store i32 undef, i32* [[_STATE_3_REG2MEM1]], align 4 +; CHECK-NEXT: invoke void @extfunc1() +; CHECK-NEXT: to label [[INVOKE_CONT75:%.*]] unwind label [[CATCH_DISPATCH]] +; CHECK: invoke.cont75: +; CHECK-NEXT: unreachable +; CHECK: catch.dispatch: +; CHECK-NEXT: [[TMP0:%.*]] = catchswitch within none [label %catch] unwind label [[EHCLEANUP105:%.*]] +; CHECK: catch: +; CHECK-NEXT: [[TMP1:%.*]] = catchpad within [[TMP0]] [i8* null, i32 64, i8* null] +; CHECK-NEXT: [[_STATE_3_RELOAD3:%.*]] = load i32, i32* [[_STATE_3_REG2MEM1]], align 4 +; CHECK-NEXT: store i32 [[_STATE_3_RELOAD3]], i32* [[_STATE_3_REG2MEM]], align 4 +; CHECK-NEXT: invoke void @extfunc2() [ "funclet"(token [[TMP1]]) ] +; CHECK-NEXT: to label [[INVOKE_CONT98:%.*]] unwind label [[EHCLEANUP105]] +; CHECK: invoke.cont98: +; CHECK-NEXT: catchret from [[TMP1]] to label [[IF_END99:%.*]] +; CHECK: if.end99: +; CHECK-NEXT: [[_STATE_3_RELOAD:%.*]] = load i32, i32* [[_STATE_3_REG2MEM]], align 4 +; CHECK-NEXT: [[OR_I:%.*]] = or i32 undef, [[_STATE_3_RELOAD]] +; CHECK-NEXT: unreachable +; CHECK: ehcleanup105: +; CHECK-NEXT: [[TMP2:%.*]] = cleanuppad within none [] +; CHECK-NEXT: [[_STATE_3_RELOAD2:%.*]] = load i32, i32* [[_STATE_3_REG2MEM1]], align 4 +; CHECK-NEXT: store i32 [[_STATE_3_RELOAD2]], i32* [[_STATE_3_REG2MEM]], align 4 +; CHECK-NEXT: cleanupret from [[TMP2]] unwind to caller +; +entry: + %call.i166167 = invoke noundef i64 undef(%"type1"* noundef nonnull align 8 dereferenceable(104) undef, i8* noundef %_Val, i64 noundef undef) + to label %if.end56 unwind label %catch.dispatch + +if.end56: ; preds = %entry + invoke void @"extfunc1"() + to label %invoke.cont75 unwind label %catch.dispatch + +invoke.cont75: ; preds = %if.end56 + unreachable + +catch.dispatch: ; preds = %if.end56, %entry + %_State.3 = phi i32 [ undef, %if.end56 ], [ 0, %entry ] + %0 = catchswitch within none [label %catch] unwind label %ehcleanup105 + +catch: ; preds = %catch.dispatch + %1 = catchpad within %0 [i8* null, i32 64, i8* null] + invoke void @"extfunc2"() [ "funclet"(token %1) ] + to label %invoke.cont98 unwind label %ehcleanup105 + +invoke.cont98: ; preds = %catch + catchret from %1 to label %if.end99 + +if.end99: ; preds = %invoke.cont98 + %or.i = or i32 undef, %_State.3 + unreachable + +ehcleanup105: ; preds = %catch, %catch.dispatch + %2 = cleanuppad within none [] + cleanupret from %2 unwind to caller +} + +declare void @"extfunc1"() + +declare void @"extfunc2"()