Index: lib/CodeGen/WinEHPrepare.cpp =================================================================== --- lib/CodeGen/WinEHPrepare.cpp +++ lib/CodeGen/WinEHPrepare.cpp @@ -65,8 +65,7 @@ class WinEHPrepare : public FunctionPass { public: static char ID; // Pass identification, replacement for typeid. - WinEHPrepare(const TargetMachine *TM = nullptr) - : FunctionPass(ID) {} + WinEHPrepare(const TargetMachine *TM = nullptr) : FunctionPass(ID) {} bool runOnFunction(Function &Fn) override; @@ -96,7 +95,9 @@ EHPersonality Personality; CatchHandlerMapTy CatchHandlerMap; CleanupHandlerMapTy CleanupHandlerMap; - DenseMap LPadMaps; + DenseMap LPadMaps; + DenseMap NestedLandingPads; + DenseMap LPadTargetBlocks; }; class WinEHFrameVariableMaterializer : public ValueMaterializer { @@ -153,8 +154,7 @@ class WinEHCloningDirectorBase : public CloningDirector { public: - WinEHCloningDirectorBase(Function *HandlerFn, - FrameVarInfoMap &VarInfo, + WinEHCloningDirectorBase(Function *HandlerFn, FrameVarInfoMap &VarInfo, LandingPadMap &LPadMap) : Materializer(HandlerFn, VarInfo), SelectorIDType(Type::getInt32Ty(HandlerFn->getContext())), @@ -180,6 +180,9 @@ virtual CloningAction handleResume(ValueToValueMapTy &VMap, const ResumeInst *Resume, BasicBlock *NewBB) = 0; + virtual CloningAction handleLandingPad(ValueToValueMapTy &VMap, + const LandingPadInst *LPad, + BasicBlock *NewBB) = 0; ValueMaterializer *getValueMaterializer() override { return &Materializer; } @@ -192,11 +195,13 @@ class WinEHCatchDirector : public WinEHCloningDirectorBase { public: - WinEHCatchDirector(Function *CatchFn, Value *Selector, - FrameVarInfoMap &VarInfo, LandingPadMap &LPadMap) + WinEHCatchDirector( + Function *CatchFn, Value *Selector, FrameVarInfoMap &VarInfo, + LandingPadMap &LPadMap, + DenseMap &NestedLPads) : WinEHCloningDirectorBase(CatchFn, VarInfo, LPadMap), CurrentSelector(Selector->stripPointerCasts()), - ExceptionObjectVar(nullptr) {} + ExceptionObjectVar(nullptr), NestedLandingPads(NestedLPads) {} CloningAction handleBeginCatch(ValueToValueMapTy &VMap, const Instruction *Inst, @@ -210,6 +215,9 @@ BasicBlock *NewBB) override; CloningAction handleResume(ValueToValueMapTy &VMap, const ResumeInst *Resume, BasicBlock *NewBB) override; + CloningAction handleLandingPad(ValueToValueMapTy &VMap, + const LandingPadInst *LPad, + BasicBlock *NewBB) override; const Value *getExceptionVar() { return ExceptionObjectVar; } TinyPtrVector &getReturnTargets() { return ReturnTargets; } @@ -219,12 +227,13 @@ const Value *ExceptionObjectVar; TinyPtrVector ReturnTargets; + DenseMap &NestedLandingPads; }; class WinEHCleanupDirector : public WinEHCloningDirectorBase { public: - WinEHCleanupDirector(Function *CleanupFn, - FrameVarInfoMap &VarInfo, LandingPadMap &LPadMap) + WinEHCleanupDirector(Function *CleanupFn, FrameVarInfoMap &VarInfo, + LandingPadMap &LPadMap) : WinEHCloningDirectorBase(CleanupFn, VarInfo, LPadMap) {} CloningAction handleBeginCatch(ValueToValueMapTy &VMap, @@ -239,6 +248,9 @@ BasicBlock *NewBB) override; CloningAction handleResume(ValueToValueMapTy &VMap, const ResumeInst *Resume, BasicBlock *NewBB) override; + CloningAction handleLandingPad(ValueToValueMapTy &VMap, + const LandingPadInst *LPad, + BasicBlock *NewBB) override; }; class ActionHandler { @@ -336,8 +348,8 @@ // FIXME: Remove this once the backend can handle the prepared IR. static cl::opt -SEHPrepare("sehprepare", cl::Hidden, - cl::desc("Prepare functions with SEH personalities")); + SEHPrepare("sehprepare", cl::Hidden, + cl::desc("Prepare functions with SEH personalities")); bool WinEHPrepare::runOnFunction(Function &Fn) { SmallVector LPads; @@ -375,9 +387,7 @@ return true; } -bool WinEHPrepare::doFinalization(Module &M) { - return false; -} +bool WinEHPrepare::doFinalization(Module &M) { return false; } void WinEHPrepare::getAnalysisUsage(AnalysisUsage &AU) const {} @@ -461,6 +471,15 @@ Invoke->setUnwindDest(NewLPadBB); } + // Replace the mapping of any nested landing pad that previously mapped + // to this landing pad with a referenced to the cloned version. + for (auto &LPadPair : NestedLandingPads) { + const LandingPadInst *OriginalLPad = LPadPair.second; + if (OriginalLPad == LPad) { + NestedLandingPads[LPadPair.first] = cast(NewLPad); + } + } + // Replace uses of the old lpad in phis with this block and delete the old // block. LPadBB->replaceSuccessorsPhiUsesWith(NewLPadBB); @@ -502,6 +521,119 @@ if (!HandlersOutlined) return false; + // Replace any nested landing pad stubs with the correct action handler. + // This must be done before we remove unreachable blocks because it + // cleans up references to outlined blocks that will be deleted. + for (auto &LPadPair : NestedLandingPads) { + const LandingPadInst *OriginalLPad = LPadPair.second; + LandingPadInst *OutlinedLPad = LPadPair.first; + + // Get the nested block and erase the unreachable instruction that was + // temporarily inserted as its terminator. + BasicBlock *OutlinedBB = OutlinedLPad->getParent(); + assert(isa(OutlinedBB->getTerminator())); + OutlinedBB->getTerminator()->eraseFromParent(); + // That should leave OutlinedLPad as the last instruction in its block. + assert(&(OutlinedBB->getInstList().back()) == OutlinedLPad); + + // The original landing pad will have already had its action intrinsic + // built by the outlining loop. We need to clone that into the outlined + // location. It may also be necessary to add references to the exception + // variables to the outlined handler in which this landing pad is nested + // and remap return instructions in the nested handlers that should return + // to an address in the outlined handler. + Function *OutlinedHandlerFn = OutlinedBB->getParent(); + const BasicBlock *OriginalBB = OriginalLPad->getParent(); + BasicBlock::const_iterator II = OriginalLPad; + ++II; + // The instruction after the landing pad should now be a call to eh.actions. + const Instruction *Recover = II; + assert(match(Recover, m_Intrinsic())); + Value *ClonedRecover = Recover->clone(); + + // Remap the exception variables into the outlined function. + WinEHFrameVariableMaterializer Materializer(OutlinedHandlerFn, + FrameVarInfo); + SmallVector ActionTargets; + CallInst *EHActions = cast(ClonedRecover); + unsigned NumArgs = EHActions->getNumArgOperands(); + for (unsigned i = 0; i < NumArgs; ++i) { + Value *V = EHActions->getArgOperand(i); + // Find the exception variable operands and remap them into the + // outlined function. Exception variables should always have an alloca. + if (auto *AV = dyn_cast(V)) { + // See if this handler already has a copy of the needed value. + bool Found = false; + if (FrameVarInfo.count(AV)) { + // The FrameVarInfo map may contain references to this variable in + // multiple handler functions. We need to iterate through them to + // see if one is in OutlinedHandlerFn. If so, use that value in the + // eh.actions call. + for (auto *MappedAV : FrameVarInfo[AV]) { + if (MappedAV->getParent()->getParent() == OutlinedHandlerFn) { + EHActions->setArgOperand(i, MappedAV); + Found = true; + } + } + } + // If the value isn't already mapped into OutlinedHandlerFn, add it now + // and use the new value in the eh.actions call. + if (!Found) { + Value *NewVal = Materializer.materializeValueFor(V); + EHActions->setArgOperand(i, NewVal); + } + } else if (auto *HandlerArg = dyn_cast(V)) { + // This is checking for catch handler arguments. Cleanup handlers will + // have a void return type and filter functions will be bitcast to i8*. + // The return value alone is enough to identify an argument as a catch + // handler. We could also pay attention to the sentinel value but that + // seems like more work than is necessary. + FunctionType *FnType = HandlerArg->getFunctionType(); + if (FnType->getReturnType() == Int8PtrType) { + // Verify the rest of the function signature. + assert(FnType->getNumParams() == 2 && + FnType->getParamType(0) == Int8PtrType && + FnType->getParamType(1) == Int8PtrType); + // Visit all the return instructions, looking for places that return + // to a location within OutlinedHandlerFn. + for (BasicBlock &NestedHandlerBB : *HandlerArg) { + if (auto *Ret = + dyn_cast(NestedHandlerBB.getTerminator())) { + // Handler functions must always return a block address. + BlockAddress *BA = cast(Ret->getReturnValue()); + // The original target will have been in the main parent function, + // but if it is the address of a block that has been outlined, it + // should be a block that was outlined into OutlinedHandlerFn. + assert(BA->getFunction() == &F); + if (LPadTargetBlocks.count(BA->getBasicBlock())) { + // If the return value is the address of a block that we + // previously outlined into the parent handler function, replace + // the return instruction and add the mapped target to the list + // of possible return addresses. + BasicBlock *MappedBB = LPadTargetBlocks[BA->getBasicBlock()]; + assert(MappedBB->getParent() == OutlinedHandlerFn); + BlockAddress *NewBA = + BlockAddress::get(OutlinedHandlerFn, MappedBB); + Ret->eraseFromParent(); + ReturnInst::Create(Context, NewBA, &NestedHandlerBB); + ActionTargets.push_back(NewBA); + } + // Ignore targets that aren't part of OutlinedHandlerFn. + } // End if terminator is ReturnInst + } // End for (BasicBlock &NestedHandlerBB : *HandlerArg) + } // End if HandlerArg is catch + } // End else if arg is Function* + } // End for EHActions args + OutlinedBB->getInstList().push_back(EHActions); + + // Insert an indirect branch into the outlined landing pad BB. + IndirectBrInst *IndirectBr = + IndirectBrInst::Create(ClonedRecover, 0, OutlinedBB); + // Add the previously collected action targets. + for (auto *Target : ActionTargets) + IndirectBr->addDestination(Target->getBasicBlock()); + } + // Delete any blocks that were only used by handlers that were outlined above. removeUnreachableBlocks(F); @@ -683,7 +815,8 @@ LPadMap.mapLandingPad(LPad); if (auto *CatchAction = dyn_cast(Action)) { Constant *Sel = CatchAction->getSelector(); - Director.reset(new WinEHCatchDirector(Handler, Sel, VarInfo, LPadMap)); + Director.reset(new WinEHCatchDirector(Handler, Sel, VarInfo, LPadMap, + NestedLandingPads)); LPadMap.remapSelector(VMap, ConstantInt::get(Type::getInt32Ty(Context), 1)); } else { Director.reset(new WinEHCleanupDirector(Handler, VarInfo, LPadMap)); @@ -727,7 +860,37 @@ reinterpret_cast(Director.get()); CatchAction->setExceptionVar(CatchDirector->getExceptionVar()); CatchAction->setReturnTargets(CatchDirector->getReturnTargets()); - } + + // Look for blocks that are not part of the landing pad that we just + // outlined but terminate with a call to llvm.eh.endcatch and a + // branch to a block that is in the handler we just outlined. + // These blocks will be part of a nested landing pad that intends to + // return to an address in this handler. This case is best handled + // after both landing pads have been outlined, so for now we'll just + // save the association of the blocks in LPadTargetBlocks. The + // return instructions which are created from these branches will be + // replaced after all landing pads have been outlined. + for (auto &MapEntry : VMap) { + // VMap maps all values and blocks that were just cloned, but dead + // blocks which were pruned will map to nullptr. + if (isa(MapEntry.first) && MapEntry.second != nullptr) { + const BasicBlock *MappedBB = cast(MapEntry.first); + for (auto *Pred : predecessors(const_cast(MappedBB))) { + auto *Branch = dyn_cast(Pred->getTerminator()); + if (Branch && Branch->isUnconditional() && Pred->size() > 1) { + BasicBlock::iterator II = const_cast(Branch); + --II; + if (match(cast(II), m_Intrinsic())) { + // This would indicate that a nested landing pad wants to return + // to a block that is outlined into two different handlers. + assert(!LPadTargetBlocks.count(MappedBB)); + LPadTargetBlocks[MappedBB] = cast(MapEntry.second); + } // End if (match(II, eh_endcatch)) + } // End if (UnconditionalBr) + } // End for (predecessors) + } // End if (MapEntry is a BB in the handler) + } // End for VMap entries + } // End if (CatchAction) Action->setHandlerBlockOrFunc(Handler); @@ -841,15 +1004,15 @@ } void LandingPadMap::remapSelector(ValueToValueMapTy &VMap, - Value *MappedValue) const { + Value *MappedValue) const { // Remap all selector extract instructions to the specified value. for (auto *Extract : ExtractedSelectors) VMap[Extract] = MappedValue; } bool LandingPadMap::mapIfEHLoad(const LoadInst *Load, - SmallVectorImpl &Stores, - SmallVectorImpl &StoreAddrs) { + SmallVectorImpl &Stores, + SmallVectorImpl &StoreAddrs) { // This makes the assumption that a store we've previously seen dominates // this load instruction. That might seem like a rather huge assumption, // but given the way that landingpads are constructed its fairly safe. @@ -903,15 +1066,7 @@ // llvm.eh.actions call and indirect branch created when the // landing pad was outlined. if (auto *NestedLPad = dyn_cast(Inst)) { - Instruction *NewInst = NestedLPad->clone(); - if (NestedLPad->hasName()) - NewInst->setName(NestedLPad->getName()); - // FIXME: Store this mapping somewhere else also. - VMap[NestedLPad] = NewInst; - BasicBlock::InstListType &InstList = NewBB->getInstList(); - InstList.push_back(NewInst); - InstList.push_back(new UnreachableInst(NewBB->getContext())); - return CloningDirector::StopCloningBB; + return handleLandingPad(VMap, NestedLPad, NewBB); } if (auto *Invoke = dyn_cast(Inst)) @@ -931,6 +1086,22 @@ return CloningDirector::CloneInstruction; } +CloningDirector::CloningAction +WinEHCatchDirector::handleLandingPad(ValueToValueMapTy &VMap, + const LandingPadInst *NestedLPad, + BasicBlock *NewBB) { + Instruction *NewInst = NestedLPad->clone(); + if (NestedLPad->hasName()) + NewInst->setName(NestedLPad->getName()); + // Save this correlation for later processing. + NestedLandingPads[cast(NewInst)] = NestedLPad; + VMap[NestedLPad] = NewInst; + BasicBlock::InstListType &InstList = NewBB->getInstList(); + InstList.push_back(NewInst); + InstList.push_back(new UnreachableInst(NewBB->getContext())); + return CloningDirector::StopCloningBB; +} + CloningDirector::CloningAction WinEHCatchDirector::handleBeginCatch( ValueToValueMapTy &VMap, const Instruction *Inst, BasicBlock *NewBB) { // The argument to the call is some form of the first element of the @@ -966,8 +1137,10 @@ return CloningDirector::SkipInstruction; // If an end catch occurs anywhere else the next instruction should be an - // unconditional branch instruction that we want to replace with a return - // to the the address of the branch target. + // unconditional branch instruction that we want to replace it with a return + // to the the address of the branch target. If at any point the target block + // is outlined into another handler function, the return value will be + // corrected after all landing pads have been outlined. const BasicBlock *EndCatchBB = IntrinCall->getParent(); const TerminatorInst *Terminator = EndCatchBB->getTerminator(); const BranchInst *Branch = dyn_cast(Terminator); @@ -1016,6 +1189,20 @@ return CloningDirector::StopCloningBB; } +CloningDirector::CloningAction +WinEHCleanupDirector::handleLandingPad(ValueToValueMapTy &VMap, + const LandingPadInst *NestedLPad, + BasicBlock *NewBB) { + // We shouldn't encounter landing pads in the actual cleanup code, but they + // will appear in catch blocks. Depending on where we started cloning, we may + // see one, but it will get dropped during dead block pruning. + Instruction *NewInst = new UnreachableInst(NewBB->getContext()); + VMap[NestedLPad] = NewInst; + BasicBlock::InstListType &InstList = NewBB->getInstList(); + InstList.push_back(NewInst); + return CloningDirector::StopCloningBB; +} + CloningDirector::CloningAction WinEHCleanupDirector::handleBeginCatch( ValueToValueMapTy &VMap, const Instruction *Inst, BasicBlock *NewBB) { // Catch blocks within cleanup handlers will always be unreachable. @@ -1091,7 +1278,8 @@ WinEHFrameVariableMaterializer::WinEHFrameVariableMaterializer( Function *OutlinedFn, FrameVarInfoMap &FrameVarInfo) : FrameVarInfo(FrameVarInfo), Builder(OutlinedFn->getContext()) { - Builder.SetInsertPoint(&OutlinedFn->getEntryBlock()); + BasicBlock *EntryBB = &OutlinedFn->getEntryBlock(); + Builder.SetInsertPoint(EntryBB, EntryBB->getFirstInsertionPt()); } Value *WinEHFrameVariableMaterializer::materializeValueFor(Value *V) { @@ -1301,8 +1489,8 @@ } // These are helper functions to combine repeated code from findCleanupHandler. -static CleanupHandler *createCleanupHandler(CleanupHandlerMapTy &CleanupHandlerMap, - BasicBlock *BB) { +static CleanupHandler * +createCleanupHandler(CleanupHandlerMapTy &CleanupHandlerMap, BasicBlock *BB) { CleanupHandler *Action = new CleanupHandler(BB); CleanupHandlerMap[BB] = Action; return Action; Index: test/CodeGen/WinEH/cppeh-catch-unwind.ll =================================================================== --- test/CodeGen/WinEH/cppeh-catch-unwind.ll +++ test/CodeGen/WinEH/cppeh-catch-unwind.ll @@ -205,7 +205,6 @@ ; CHECK: [[LPAD5_VAL:\%.+]] = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) ; CHECK: cleanup ; CHECK: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*) -; CHECK: unreachable ; CHECK: } declare %class.SomeClass* @"\01??0SomeClass@@QEAA@XZ"(%class.SomeClass* returned) #1 Index: test/CodeGen/WinEH/cppeh-nested-1.ll =================================================================== --- test/CodeGen/WinEH/cppeh-nested-1.ll +++ test/CodeGen/WinEH/cppeh-nested-1.ll @@ -1,5 +1,4 @@ ; RUN: opt -mtriple=x86_64-pc-windows-msvc -winehprepare -S -o - < %s | FileCheck %s -; XFAIL: * ; This test is based on the following code: ; @@ -56,7 +55,7 @@ ; CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) ; CHECK: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*) ; CHECK: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*) -; CHECK: [[RECOVER:\%.+]] = call i8* (...)* @llvm.eh.actions(i32 0, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*), i32* %i, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch" to i8*), i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*), float* %f, i8* bitcast (i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch1") +; CHECK: [[RECOVER:\%.+]] = call i8* (...)* @llvm.eh.actions(i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*), i32* %i, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch", i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*), float* %f, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch1") ; CHECK: indirectbr i8* [[RECOVER]], [label %try.cont, label %try.cont10] lpad: ; preds = %entry @@ -137,11 +136,10 @@ ; CHECK: define internal i8* @"\01?test@@YAXXZ.catch"(i8*, i8*) { ; CHECK: entry: -; CHECK: [[RECOVER_I:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 0) -; CHECK: [[I_PTR:\%.+]] = bitcast i8* [[RECOVER_I]] to i32* -; ------------================= FAIL here =================------------ ; CHECK: [[RECOVER_F:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 1) ; CHECK: [[F_PTR:\%.+]] = bitcast i8* [[RECOVER_F]] to float* +; CHECK: [[RECOVER_I:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 0) +; CHECK: [[I_PTR:\%.+]] = bitcast i8* [[RECOVER_I]] to i32* ; CHECK: [[TMP1:\%.+]] = load i32, i32* [[I_PTR]], align 4 ; CHECK: invoke void @"\01?handle_int@@YAXH@Z"(i32 [[TMP1]]) ; CHECK: to label %invoke.cont2 unwind label %[[LPAD1_LABEL:lpad[0-9]*]] @@ -152,8 +150,7 @@ ; CHECK: [[LPAD1_LABEL]]:{{[ ]+}}; preds = %entry ; CHECK: [[LPAD1_VAL:\%.+]] = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) ; CHECK: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*) -; ------------================= FAIL here =================------------ -; CHECK: [[RECOVER1:\%.+]] = call i8* (...)* @llvm.eh.actions({ i8*, i32 } [[LPAD1_VAL]], i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*), float* [[F_PTR]], i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch1") +; CHECK: [[RECOVER1:\%.+]] = call i8* (...)* @llvm.eh.actions(i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*), float* [[F_PTR]], i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch1") ; CHECK: indirectbr i8* [[RECOVER1]], [] ; ; CHECK: } Index: test/CodeGen/WinEH/cppeh-nested-3.ll =================================================================== --- test/CodeGen/WinEH/cppeh-nested-3.ll +++ test/CodeGen/WinEH/cppeh-nested-3.ll @@ -1,5 +1,4 @@ ; RUN: opt -mtriple=x86_64-pc-windows-msvc -winehprepare -S -o - < %s | FileCheck %s -; XFAIL: * ; This test is based on the following code: ; @@ -40,11 +39,9 @@ ; CHECK: define void @"\01?test@@YAXXZ"() #0 { ; CHECK: entry: ; CHECK: %i = alloca i32, align 4 -; ------------================= FAIL here =================------------ ; CHECK: %j = alloca i32, align 4 ; CHECK: %f = alloca float, align 4 -; ------------================= FAIL here =================------------ -; CHECK: call void (...)* @llvm.frameescape(i32* %i, float* %f, int32* %j) +; CHECK: call void (...)* @llvm.frameescape(i32* %i, float* %f, i32* %j) ; CHECK: invoke void @"\01?may_throw@@YAXXZ"() ; CHECK: to label %invoke.cont unwind label %[[LPAD_LABEL:lpad[0-9]*]] @@ -66,7 +63,7 @@ ; CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) ; CHECK: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*) ; CHECK: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*) -; CHECK: [[RECOVER:\%.+]] = call i8* (...)* @llvm.eh.actions(i32 0, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*), i32* %i, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch" to i8*), i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*), float* %f, i8* bitcast (i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch1") +; CHECK: [[RECOVER:\%.+]] = call i8* (...)* @llvm.eh.actions(i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*), i32* %i, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch", i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*), float* %f, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch1") ; CHECK: indirectbr i8* [[RECOVER]], [label %try.cont10, label %try.cont19] lpad: ; preds = %entry @@ -184,18 +181,16 @@ ; CHECK: define internal i8* @"\01?test@@YAXXZ.catch"(i8*, i8*) { ; CHECK: entry: -; CHECK: [[RECOVER_I:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 0) -; CHECK: [[I_PTR:\%.+]] = bitcast i8* [[RECOVER_I]] to i32* -; ------------================= FAIL here =================------------ +; CHECK: [[RECOVER_J:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 2) +; CHECK: [[J_PTR:\%.+]] = bitcast i8* [[RECOVER_J]] to i32* ; CHECK: [[RECOVER_F:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 1) ; CHECK: [[F_PTR:\%.+]] = bitcast i8* [[RECOVER_F]] to float* -; ------------================= FAIL here =================------------ -; CHECK: [[RECOVER_J:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 2) -; CHECK: [[J_PTR:\%.+]] = bitcast i8* [[RECOVER_I]] to i32* +; CHECK: [[RECOVER_I:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 0) +; CHECK: [[I_PTR:\%.+]] = bitcast i8* [[RECOVER_I]] to i32* ; CHECK: invoke void @"\01?may_throw@@YAXXZ"() ; CHECK: to label %invoke.cont2 unwind label %[[LPAD1_LABEL:lpad[0-9]*]] ; -; CHECK: invoke.cont2: ; preds = %entry +; CHECK: invoke.cont2: ; preds = %[[LPAD1_LABEL]], %entry ; CHECK: [[TMP1:\%.+]] = load i32, i32* [[I_PTR]], align 4 ; CHECK: invoke void @"\01?handle_int@@YAXH@Z"(i32 [[TMP1]]) ; CHECK: to label %invoke.cont9 unwind label %[[LPAD8_LABEL:lpad[0-9]*]] @@ -204,9 +199,8 @@ ; CHECK: [[LPAD1_VAL:\%.+]] = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) ; CHECK: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*) ; CHECK: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*) -; ------------================= FAIL here =================------------ -; CHECK: [[RECOVER1:\%.+]] = call i8* (...)* @llvm.eh.actions({ i8*, i32 } [[LPAD1_VAL]], i32 0, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*), i32* [[J_PTR]], i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch2" to i8*), i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*), float* [[F_PTR1]], i8* bitcast (i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch1") -; CHECK: indirectbr i8* [[RECOVER1]], [] +; CHECK: [[RECOVER1:\%.+]] = call i8* (...)* @llvm.eh.actions(i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*), i32* [[J_PTR]], i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch2", i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*), float* [[F_PTR]], i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch1") +; CHECK: indirectbr i8* [[RECOVER1]], [label %invoke.cont2] ; ; CHECK: invoke.cont9: ; CHECK: ret i8* blockaddress(@"\01?test@@YAXXZ", %try.cont10) @@ -214,8 +208,7 @@ ; CHECK: [[LPAD8_LABEL]]:{{[ ]+}}; preds = %invoke.cont2 ; CHECK: [[LPAD8_VAL:\%.+]] = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) ; CHECK: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*) -; ------------================= FAIL here =================------------ -; CHECK: [[RECOVER2:\%.+]] = call i8* (...)* @llvm.eh.actions({ i8*, i32 } [[LPAD8_VAL]], i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*), float* [[F_PTR1]], i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch1") +; CHECK: [[RECOVER2:\%.+]] = call i8* (...)* @llvm.eh.actions(i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*), float* [[F_PTR]], i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch1") ; CHECK: indirectbr i8* [[RECOVER2]], [] ; ; CHECK: } @@ -231,13 +224,12 @@ ; CHECK: define internal i8* @"\01?test@@YAXXZ.catch2"(i8*, i8*) { ; CHECK: entry: -; ------------================= FAIL here =================------------ -; SHOULD-CHECK: [[J_PTR1:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 2) +; CHECK: [[RECOVER_J1:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 2) +; CHECK: [[J_PTR1:\%.+]] = bitcast i8* [[RECOVER_J1]] to i32* ; CHECK: [[RECOVER_I1:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 0) ; CHECK: [[I_PTR1:\%.+]] = bitcast i8* [[RECOVER_I1]] to i32* ; CHECK: [[TMP3:\%.+]] = load i32, i32* [[J_PTR1]], align 4 ; CHECK: store i32 [[TMP3]], i32* [[I_PTR1]] -; ------------================= FAIL here =================------------ ; CHECK: ret i8* blockaddress(@"\01?test@@YAXXZ.catch", %invoke.cont2) ; CHECK: }