Index: include/llvm/CodeGen/WinEHFuncInfo.h =================================================================== --- include/llvm/CodeGen/WinEHFuncInfo.h +++ include/llvm/CodeGen/WinEHFuncInfo.h @@ -23,6 +23,7 @@ class Constant; class Function; class GlobalValue; +class IntrinsicInst; class LandingPadInst; class MCSymbol; class Value; @@ -58,7 +59,8 @@ public: CatchHandler(BasicBlock *BB, Constant *Selector, BasicBlock *NextBB) : ActionHandler(BB, ActionType::Catch), Selector(Selector), - NextBB(NextBB), ExceptionObjectVar(nullptr) {} + NextBB(NextBB), ExceptionObjectVar(nullptr), + ExceptionObjectIndex(-1) {} // Method for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const ActionHandler *H) { @@ -72,6 +74,7 @@ TinyPtrVector &getReturnTargets() { return ReturnTargets; } void setExceptionVar(const Value *Val) { ExceptionObjectVar = Val; } + void setExceptionVarIndex(int Index) { ExceptionObjectIndex = Index; } void setReturnTargets(TinyPtrVector &Targets) { ReturnTargets = Targets; } @@ -79,7 +82,16 @@ private: Constant *Selector; BasicBlock *NextBB; + // While catch handlers are being outlined the ExceptionObjectVar field will + // be populated with the instruction in the parent frame that corresponds + // to the exception object (or nullptr if the catch does not use an + // exception object) and the ExceptionObjectIndex field will be -1. + // When the parseEHActions function is called to populate a vector of + // instances of this class, the ExceptionObjectVar field will be nullptr + // and the ExceptionObjectIndex will be the index of the exception object in + // the parent function's frameescape block. const Value *ExceptionObjectVar; + int ExceptionObjectIndex; TinyPtrVector ReturnTargets; }; @@ -93,6 +105,10 @@ } }; +void parseEHActions(const IntrinsicInst *II, + SmallVectorImpl &Actions); + + // The following structs respresent the .xdata for functions using C++ // exceptions on Windows. Index: lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp =================================================================== --- lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp +++ lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp @@ -94,8 +94,6 @@ return HandlerStack.empty() ? -1 : HandlerStack.back()->getEHState(); } - void parseEHActions(const IntrinsicInst *II, - SmallVectorImpl &Actions); void createUnwindMapEntry(int ToState, ActionHandler *AH); void createTryBlockMapEntry(int TryLow, int TryHigh, ArrayRef Handlers); @@ -287,32 +285,6 @@ } } -void WinEHNumbering::parseEHActions(const IntrinsicInst *II, - SmallVectorImpl &Actions) { - for (unsigned I = 0, E = II->getNumArgOperands(); I != E;) { - uint64_t ActionKind = - cast(II->getArgOperand(I))->getZExtValue(); - if (ActionKind == /*catch=*/1) { - auto *Selector = cast(II->getArgOperand(I + 1)); - Value *CatchObject = II->getArgOperand(I + 2); - Constant *Handler = cast(II->getArgOperand(I + 3)); - I += 4; - auto *CH = new CatchHandler(/*BB=*/nullptr, Selector, /*NextBB=*/nullptr); - CH->setExceptionVar(CatchObject); - CH->setHandlerBlockOrFunc(Handler); - Actions.push_back(CH); - } else { - assert(ActionKind == 0 && "expected a cleanup or a catch action!"); - Constant *Handler = cast(II->getArgOperand(I + 1)); - I += 2; - auto *CH = new CleanupHandler(/*BB=*/nullptr); - CH->setHandlerBlockOrFunc(Handler); - Actions.push_back(CH); - } - } - std::reverse(Actions.begin(), Actions.end()); -} - void WinEHNumbering::createUnwindMapEntry(int ToState, ActionHandler *AH) { WinEHUnwindMapEntry UME; UME.ToState = ToState; Index: lib/CodeGen/WinEHPrepare.cpp =================================================================== --- lib/CodeGen/WinEHPrepare.cpp +++ lib/CodeGen/WinEHPrepare.cpp @@ -86,6 +86,10 @@ bool prepareExceptionHandlers(Function &F, SmallVectorImpl &LPads); void promoteLandingPadValues(LandingPadInst *LPad); + void completeNestedLandingPad(Function *ParentFn, + LandingPadInst *OutlinedLPad, + const LandingPadInst *OriginalLPad, + FrameVarInfoMap &VarInfo); bool outlineHandler(ActionHandler *Action, Function *SrcFn, LandingPadInst *LPad, BasicBlock *StartBB, FrameVarInfoMap &VarInfo); @@ -103,6 +107,27 @@ CatchHandlerMapTy CatchHandlerMap; CleanupHandlerMapTy CleanupHandlerMap; DenseMap LPadMaps; + + // This maps landing pad instructions found in outlined handlers to + // the landing pad instruction in the parent function from which they + // were cloned. The cloned/nested landing pad is used as the key + // because the landing pad may be cloned into multiple handlers. + // This map will be used to add the llvm.eh.actions call to the nested + // landing pads after all handlers have been outlined. + DenseMap NestedLPtoOriginalLP; + + // This maps blocks in the parent function which are destinations of + // catch handlers to cloned blocks in (other) outlined handlers. This + // handles the case where a nested landing pads has a catch handler that + // returns to a handler function rather than the parent function. + // The original block is used as the key here because there should only + // ever be one handler function from which the cloned block is not pruned. + // The original block will be pruned from the parent function after all + // handlers have been outlined. This map will be used to adjust the + // return instructions of handlers which return to the block that was + // outlined into a handler. This is done after all handlers have been + // outlined but before the outlined code is pruned from the parent function. + DenseMap LPadTargetBlocks; }; class WinEHFrameVariableMaterializer : public ValueMaterializer { @@ -143,8 +168,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())), @@ -170,6 +194,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; } @@ -182,11 +209,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), NestedLPtoOriginalLP(NestedLPads) {} CloningAction handleBeginCatch(ValueToValueMapTy &VMap, const Instruction *Inst, @@ -200,6 +229,9 @@ BasicBlock *NewBB) override; CloningAction handleResume(ValueToValueMapTy &VMap, const ResumeInst *Resume, BasicBlock *NewBB) override; + CloningAction handleLandingPad(ValueToValueMapTy &VMap, + const LandingPadInst *LPad, + BasicBlock *NewBB) override; Value *getExceptionVar() { return ExceptionObjectVar; } TinyPtrVector &getReturnTargets() { return ReturnTargets; } @@ -209,12 +241,16 @@ Value *ExceptionObjectVar; TinyPtrVector ReturnTargets; + + // This will be a reference to the field of the same name in the WinEHPrepare + // object which instantiates this WinEHCatchDirector object. + DenseMap &NestedLPtoOriginalLP; }; 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, @@ -229,6 +265,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 LandingPadActions { @@ -267,8 +306,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; @@ -308,9 +347,7 @@ return true; } -bool WinEHPrepare::doFinalization(Module &M) { - return false; -} +bool WinEHPrepare::doFinalization(Module &M) { return false; } void WinEHPrepare::getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired(); @@ -400,6 +437,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 : NestedLPtoOriginalLP) { + const LandingPadInst *OriginalLPad = LPadPair.second; + if (OriginalLPad == LPad) { + LPadPair.second = NewLPad; + } + } + // Replace uses of the old lpad in phis with this block and delete the old // block. LPadBB->replaceSuccessorsPhiUsesWith(NewLPadBB); @@ -447,6 +493,12 @@ 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 : NestedLPtoOriginalLP) + completeNestedLandingPad(&F, LPadPair.first, LPadPair.second, FrameVarInfo); + F.addFnAttr("wineh-parent", F.getName()); // Delete any blocks that were only used by handlers that were outlined above. @@ -610,6 +662,87 @@ } } +void WinEHPrepare::completeNestedLandingPad(Function *ParentFn, + LandingPadInst *OutlinedLPad, + const LandingPadInst *OriginalLPad, + FrameVarInfoMap &FrameVarInfo) { + // Get the nested block and erase the unreachable instruction that was + // temporarily inserted as its terminator. + LLVMContext &Context = ParentFn->getContext(); + BasicBlock *OutlinedBB = OutlinedLPad->getParent(); + assert(isa(OutlinedBB->getTerminator())); + OutlinedBB->getTerminator()->eraseFromParent(); + // That should leave OutlinedLPad as the last instruction in its block. + assert(&OutlinedBB->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())); + IntrinsicInst *EHActions = cast(Recover->clone()); + + // Remap the exception variables into the outlined function. + WinEHFrameVariableMaterializer Materializer(OutlinedHandlerFn, FrameVarInfo); + SmallVector ActionTargets; + unsigned NumArgs = EHActions->getNumArgOperands(); + SmallVector ActionList; + parseEHActions(EHActions, ActionList); + for (auto *Action : ActionList) { + auto *Catch = dyn_cast(Action); + if (!Catch) + continue; + // The dyn_cast to function here selects C++ catch handlers and skips + // SEH catch handlers. + if (auto *Handler = dyn_cast(Catch->getHandlerBlockOrFunc())) { + // Visit all the return instructions, looking for places that return + // to a location within OutlinedHandlerFn. + for (BasicBlock &NestedHandlerBB : *Handler) { + auto *Ret = dyn_cast(NestedHandlerBB.getTerminator()); + if (!Ret) + continue; + + // 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() == ParentFn); + + // Ignore targets that aren't part of OutlinedHandlerFn. + if (!LPadTargetBlocks.count(BA->getBasicBlock())) + continue; + + // If the return value is the address ofF 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); + } + } + } + OutlinedBB->getInstList().push_back(EHActions); + + // Insert an indirect branch into the outlined landing pad BB. + IndirectBrInst *IBr = IndirectBrInst::Create(EHActions, 0, OutlinedBB); + // Add the previously collected action targets. + for (auto *Target : ActionTargets) + IBr->addDestination(Target->getBasicBlock()); +} + // This function examines a block to determine whether the block ends with a // conditional branch to a catch handler based on a selector comparison. // This function is used both by the WinEHPrepare::findSelectorComparison() and @@ -685,7 +818,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, + NestedLPtoOriginalLP)); LPadMap.remapEHValues(VMap, UndefValue::get(Int8PtrType), ConstantInt::get(Type::getInt32Ty(Context), 1)); } else { @@ -732,7 +866,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) + continue; + 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) + continue; + 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 (CatchAction) Action->setHandlerBlockOrFunc(Handler); @@ -837,16 +1001,8 @@ // all landingpads have been outlined, we'll replace this with the // 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; + if (auto *LPad = dyn_cast(Inst)) { + return handleLandingPad(VMap, LPad, NewBB); } if (auto *Invoke = dyn_cast(Inst)) @@ -866,6 +1022,20 @@ return CloningDirector::CloneInstruction; } +CloningDirector::CloningAction WinEHCatchDirector::handleLandingPad( + ValueToValueMapTy &VMap, const LandingPadInst *LPad, BasicBlock *NewBB) { + Instruction *NewInst = LPad->clone(); + if (LPad->hasName()) + NewInst->setName(LPad->getName()); + // Save this correlation for later processing. + NestedLPtoOriginalLP[cast(NewInst)] = LPad; + VMap[LPad] = 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 @@ -961,6 +1131,20 @@ return CloningDirector::StopCloningBB; } +CloningDirector::CloningAction WinEHCleanupDirector::handleLandingPad( + ValueToValueMapTy &VMap, const LandingPadInst *LPad, BasicBlock *NewBB) { + // The MS runtime will terminate the process if an exception occurs in a + // cleanup handler, so we shouldn't encounter landing pads in the actual + // cleanup code, but they may 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[LPad] = 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. @@ -1036,7 +1220,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) { @@ -1255,8 +1440,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; @@ -1404,6 +1589,9 @@ // If this is a catch block, there is no cleanup code to be found. if (match(Inst, m_Intrinsic())) return nullptr; + // If this a nested landing pad, it may contain an endcatch call. + if (match(Inst, m_Intrinsic())) + return nullptr; // Anything else makes this interesting cleanup code. return createCleanupHandler(CleanupHandlerMap, BB); } @@ -1416,3 +1604,34 @@ } return nullptr; } + +// This is a public function, declared in WinEHFuncInfo.h and is also +// referenced by WinEHNumbering in FunctionLoweringInfo.cpp. +void llvm::parseEHActions(const IntrinsicInst *II, + SmallVectorImpl &Actions) { + for (unsigned I = 0, E = II->getNumArgOperands(); I != E;) { + uint64_t ActionKind = + cast(II->getArgOperand(I))->getZExtValue(); + if (ActionKind == /*catch=*/1) { + auto *Selector = cast(II->getArgOperand(I + 1)); + ConstantInt *EHObjIndex = cast(II->getArgOperand(I + 2)); + int64_t EHObjIndexVal = EHObjIndex->getSExtValue(); + Constant *Handler = cast(II->getArgOperand(I + 3)); + I += 4; + auto *CH = new CatchHandler(/*BB=*/nullptr, Selector, /*NextBB=*/nullptr); + CH->setHandlerBlockOrFunc(Handler); + CH->setExceptionVarIndex(EHObjIndexVal); + Actions.push_back(CH); + } + else { + assert(ActionKind == 0 && "expected a cleanup or a catch action!"); + Constant *Handler = cast(II->getArgOperand(I + 1)); + I += 2; + auto *CH = new CleanupHandler(/*BB=*/nullptr); + CH->setHandlerBlockOrFunc(Handler); + Actions.push_back(CH); + } + } + std::reverse(Actions.begin(), Actions.end()); +} + Index: test/CodeGen/WinEH/cppeh-catch-unwind.ll =================================================================== --- test/CodeGen/WinEH/cppeh-catch-unwind.ll +++ test/CodeGen/WinEH/cppeh-catch-unwind.ll @@ -208,7 +208,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 0, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch", i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*), i32 1, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch1") ; CHECK: indirectbr i8* [[RECOVER]], [label %try.cont, label %try.cont10] lpad: ; preds = %entry @@ -139,9 +138,6 @@ ; 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: [[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 +148,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*), i32 1, 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"() ; 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 0, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch", i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*), i32 1, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch1") ; CHECK: indirectbr i8* [[RECOVER]], [label %try.cont10, label %try.cont19] lpad: ; preds = %entry @@ -186,16 +183,10 @@ ; 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* -; ------------================= 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: 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 +195,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 2, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch2", i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*), i32 1, 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,30 +204,28 @@ ; 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*), i32 1, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch1") ; CHECK: indirectbr i8* [[RECOVER2]], [] ; ; CHECK: } ; CHECK: define internal i8* @"\01?test@@YAXXZ.catch1"(i8*, i8*) ; CHECK: entry: -; CHECK: [[RECOVER_F1:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 1) -; CHECK: [[F_PTR1:\%.+]] = bitcast i8* [[RECOVER_F1]] to float* -; CHECK: [[TMP2:\%.+]] = load float, float* [[F_PTR1]], align 4 +; 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: [[TMP2:\%.+]] = load float, float* [[F_PTR]], align 4 ; CHECK: call void @"\01?handle_float@@YAXM@Z"(float [[TMP2]]) ; CHECK: ret i8* blockaddress(@"\01?test@@YAXXZ", %try.cont19) ; CHECK: } ; 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_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_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: [[TMP3:\%.+]] = load i32, i32* [[J_PTR]], align 4 ; CHECK: store i32 [[TMP3]], i32* [[I_PTR1]] -; ------------================= FAIL here =================------------ ; CHECK: ret i8* blockaddress(@"\01?test@@YAXXZ.catch", %invoke.cont2) ; CHECK: } Index: test/CodeGen/WinEH/cppeh-prepared-catch.ll =================================================================== --- test/CodeGen/WinEH/cppeh-prepared-catch.ll +++ test/CodeGen/WinEH/cppeh-prepared-catch.ll @@ -45,7 +45,7 @@ %4 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) cleanup catch %eh.CatchHandlerType* @llvm.eh.handlertype.N.0 - %recover = call i8* (...)* @llvm.eh.actions(i32 1, i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.N.0 to i8*), double* null, i8* (i8*, i8*)* @"\01?f@@YAXXZ.catch1") + %recover = call i8* (...)* @llvm.eh.actions(i32 1, i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.N.0 to i8*), i32 1, i8* (i8*, i8*)* @"\01?f@@YAXXZ.catch1") indirectbr i8* %recover, [label %invoke.cont2] } @@ -100,7 +100,7 @@ %3 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) catch %eh.CatchHandlerType* @llvm.eh.handlertype.H.8 catch %eh.CatchHandlerType* @llvm.eh.handlertype.N.0 - %recover = call i8* (...)* @llvm.eh.actions(i32 1, i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.H.8 to i8*), i32** %0, i8* (i8*, i8*)* @"\01?f@@YAXXZ.catch", i32 1, i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.N.0 to i8*), double* %1, i8* (i8*, i8*)* @"\01?f@@YAXXZ.catch1") + %recover = call i8* (...)* @llvm.eh.actions(i32 1, i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.H.8 to i8*), i32 0, i8* (i8*, i8*)* @"\01?f@@YAXXZ.catch", i32 1, i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.N.0 to i8*), i32 1, i8* (i8*, i8*)* @"\01?f@@YAXXZ.catch1") indirectbr i8* %recover, [label %try.cont, label %try.cont8] try.cont: ; preds = %lpad2, %invoke.cont @@ -110,7 +110,7 @@ lpad1: %4 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) catch %eh.CatchHandlerType* @llvm.eh.handlertype.N.0 - %recover2 = call i8* (...)* @llvm.eh.actions(i32 1, i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.N.0 to i8*), double* null, i8* (i8*, i8*)* @"\01?f@@YAXXZ.catch1") + %recover2 = call i8* (...)* @llvm.eh.actions(i32 1, i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.N.0 to i8*), i32 1, i8* (i8*, i8*)* @"\01?f@@YAXXZ.catch1") indirectbr i8* %recover2, [label %try.cont8] try.cont8: ; preds = %lpad2, %try.cont