From: David Majnemer Date: Mon, 30 Mar 2015 22:58:10 +0000 (+0000) Subject: [WinEH] Run cleanup handlers when an exception is thrown X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=0a8ff297adf36a0a01d1e2dce80857e6b258a023;p=oota-llvm.git [WinEH] Run cleanup handlers when an exception is thrown Generate tables in the .xdata section representing what actions to take when an exception is thrown. This currently fills in state for cleanups, catch handlers are still unfinished. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@233636 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/CodeGen/MachineModuleInfo.h b/include/llvm/CodeGen/MachineModuleInfo.h index f171df20e76..ce1943bff57 100644 --- a/include/llvm/CodeGen/MachineModuleInfo.h +++ b/include/llvm/CodeGen/MachineModuleInfo.h @@ -58,22 +58,25 @@ class MachineFunction; class Module; class PointerType; class StructType; +struct WinEHFuncInfo; //===----------------------------------------------------------------------===// /// LandingPadInfo - This structure is used to retain landing pad info for /// the current function. /// struct LandingPadInfo { - MachineBasicBlock *LandingPadBlock; // Landing pad block. - SmallVector BeginLabels; // Labels prior to invoke. - SmallVector EndLabels; // Labels after invoke. - SmallVector ClauseLabels; // Labels for each clause. - MCSymbol *LandingPadLabel; // Label at beginning of landing pad. - const Function *Personality; // Personality function. - std::vector TypeIds; // List of type ids (filters negative) + MachineBasicBlock *LandingPadBlock; // Landing pad block. + SmallVector BeginLabels; // Labels prior to invoke. + SmallVector EndLabels; // Labels after invoke. + SmallVector ClauseLabels; // Labels for each clause. + MCSymbol *LandingPadLabel; // Label at beginning of landing pad. + const Function *Personality; // Personality function. + std::vector TypeIds; // List of type ids (filters negative). + int WinEHState; // WinEH specific state number. explicit LandingPadInfo(MachineBasicBlock *MBB) - : LandingPadBlock(MBB), LandingPadLabel(nullptr), Personality(nullptr) {} + : LandingPadBlock(MBB), LandingPadLabel(nullptr), Personality(nullptr), + WinEHState(-1) {} }; //===----------------------------------------------------------------------===// @@ -172,6 +175,8 @@ class MachineModuleInfo : public ImmutablePass { EHPersonality PersonalityTypeCache; + DenseMap> FuncInfoMap; + public: static char ID; // Pass identification, replacement for typeid @@ -207,6 +212,12 @@ public: void setModule(const Module *M) { TheModule = M; } const Module *getModule() const { return TheModule; } + const Function *getWinEHParent(const Function *F) const; + WinEHFuncInfo &getWinEHFuncInfo(const Function *F); + bool hasWinEHFuncInfo(const Function *F) const { + return FuncInfoMap.count(getWinEHParent(F)) > 0; + } + /// getInfo - Keep track of various per-function pieces of information for /// backends that would like to do so. /// @@ -304,6 +315,8 @@ public: void addPersonality(MachineBasicBlock *LandingPad, const Function *Personality); + void addWinEHState(MachineBasicBlock *LandingPad, int State); + /// getPersonalityIndex - Get index of the current personality function inside /// Personalitites array unsigned getPersonalityIndex() const; diff --git a/include/llvm/CodeGen/WinEHFuncInfo.h b/include/llvm/CodeGen/WinEHFuncInfo.h new file mode 100644 index 00000000000..807afe6f8ae --- /dev/null +++ b/include/llvm/CodeGen/WinEHFuncInfo.h @@ -0,0 +1,131 @@ +//===-- llvm/CodeGen/WinEHFuncInfo.h ----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Data structures and associated state for Windows exception handling schemes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_WINEHFUNCINFO_H +#define LLVM_CODEGEN_WINEHFUNCINFO_H + +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/TinyPtrVector.h" +#include "llvm/ADT/DenseMap.h" + +namespace llvm { +class BasicBlock; +class Constant; +class Function; +class GlobalValue; +class LandingPadInst; +class MCSymbol; +class Value; + +enum ActionType { Catch, Cleanup }; + +class ActionHandler { +public: + ActionHandler(BasicBlock *BB, ActionType Type) + : StartBB(BB), Type(Type), EHState(-1), HandlerBlockOrFunc(nullptr) {} + + ActionType getType() const { return Type; } + BasicBlock *getStartBlock() const { return StartBB; } + + bool hasBeenProcessed() { return HandlerBlockOrFunc != nullptr; } + + void setHandlerBlockOrFunc(Constant *F) { HandlerBlockOrFunc = F; } + Constant *getHandlerBlockOrFunc() { return HandlerBlockOrFunc; } + + void setEHState(int State) { EHState = State; } + int getEHState() const { return EHState; } + +private: + BasicBlock *StartBB; + ActionType Type; + int EHState; + + // Can be either a BlockAddress or a Function depending on the EH personality. + Constant *HandlerBlockOrFunc; +}; + +class CatchHandler : public ActionHandler { +public: + CatchHandler(BasicBlock *BB, Constant *Selector, BasicBlock *NextBB) + : ActionHandler(BB, ActionType::Catch), Selector(Selector), + NextBB(NextBB), ExceptionObjectVar(nullptr) {} + + // Method for support type inquiry through isa, cast, and dyn_cast: + static inline bool classof(const ActionHandler *H) { + return H->getType() == ActionType::Catch; + } + + Constant *getSelector() const { return Selector; } + BasicBlock *getNextBB() const { return NextBB; } + + const Value *getExceptionVar() { return ExceptionObjectVar; } + TinyPtrVector &getReturnTargets() { return ReturnTargets; } + + void setExceptionVar(const Value *Val) { ExceptionObjectVar = Val; } + void setReturnTargets(TinyPtrVector &Targets) { + ReturnTargets = Targets; + } + +private: + Constant *Selector; + BasicBlock *NextBB; + const Value *ExceptionObjectVar; + TinyPtrVector ReturnTargets; +}; + +class CleanupHandler : public ActionHandler { +public: + CleanupHandler(BasicBlock *BB) : ActionHandler(BB, ActionType::Cleanup) {} + + // Method for support type inquiry through isa, cast, and dyn_cast: + static inline bool classof(const ActionHandler *H) { + return H->getType() == ActionType::Cleanup; + } +}; + +// The following structs respresent the .xdata for functions using C++ +// exceptions on Windows. + +struct WinEHUnwindMapEntry { + int ToState; + Function *Cleanup; +}; + +struct WinEHHandlerType { + int Adjectives; + GlobalValue *TypeDescriptor; + Function *Handler; +}; + +struct WinEHTryBlockMapEntry { + int TryLow; + int TryHigh; + int CatchHigh; + SmallVector HandlerArray; +}; + +struct WinEHFuncInfo { + DenseMap LandingPadStateMap; + DenseMap CatchHandlerParentFrameObjIdx; + DenseMap CatchHandlerParentFrameObjOffset; + SmallVector UnwindMap; + SmallVector TryBlockMap; + SmallVector, 4> IPToStateList; + int UnwindHelpFrameIdx; + int UnwindHelpFrameOffset; + + WinEHFuncInfo() : UnwindHelpFrameIdx(INT_MAX), UnwindHelpFrameOffset(-1) {} +}; + +} +#endif // LLVM_CODEGEN_WINEHFUNCINFO_H diff --git a/include/llvm/IR/CallSite.h b/include/llvm/IR/CallSite.h index 9c87936dd21..b2f545ac2a1 100644 --- a/include/llvm/IR/CallSite.h +++ b/include/llvm/IR/CallSite.h @@ -373,6 +373,7 @@ private: class ImmutableCallSite : public CallSiteBase<> { typedef CallSiteBase<> Base; public: + ImmutableCallSite() {} ImmutableCallSite(const Value* V) : Base(V) {} ImmutableCallSite(const CallInst *CI) : Base(CI) {} ImmutableCallSite(const InvokeInst *II) : Base(II) {} diff --git a/lib/Analysis/TargetLibraryInfo.cpp b/lib/Analysis/TargetLibraryInfo.cpp index 7e574d55c83..8b378a340fd 100644 --- a/lib/Analysis/TargetLibraryInfo.cpp +++ b/lib/Analysis/TargetLibraryInfo.cpp @@ -409,9 +409,7 @@ static StringRef sanitizeFunctionName(StringRef funcName) { // Check for \01 prefix that is used to mangle __asm declarations and // strip it if present. - if (funcName.front() == '\01') - funcName = funcName.substr(1); - return funcName; + return GlobalValue::getRealLinkageName(funcName); } bool TargetLibraryInfoImpl::getLibFunc(StringRef funcName, diff --git a/lib/CodeGen/AsmPrinter/EHStreamer.cpp b/lib/CodeGen/AsmPrinter/EHStreamer.cpp index 14df4c91625..6f64d8f790a 100644 --- a/lib/CodeGen/AsmPrinter/EHStreamer.cpp +++ b/lib/CodeGen/AsmPrinter/EHStreamer.cpp @@ -188,20 +188,12 @@ bool EHStreamer::callToNoUnwindFunction(const MachineInstr *MI) { return MarkedNoUnwind; } -/// Compute the call-site table. The entry for an invoke has a try-range -/// containing the call, a non-zero landing pad, and an appropriate action. The -/// entry for an ordinary call has a try-range containing the call and zero for -/// the landing pad and the action. Calls marked 'nounwind' have no entry and -/// must not be contained in the try-range of any entry - they form gaps in the -/// table. Entries must be ordered by try-range address. -void EHStreamer:: -computeCallSiteTable(SmallVectorImpl &CallSites, - const SmallVectorImpl &LandingPads, - const SmallVectorImpl &FirstActions) { +void EHStreamer::computePadMap( + const SmallVectorImpl &LandingPads, + RangeMapType &PadMap) { // Invokes and nounwind calls have entries in PadMap (due to being bracketed // by try-range labels when lowered). Ordinary calls do not, so appropriate // try-ranges for them need be deduced so we can put them in the LSDA. - RangeMapType PadMap; for (unsigned i = 0, N = LandingPads.size(); i != N; ++i) { const LandingPadInfo *LandingPad = LandingPads[i]; for (unsigned j = 0, E = LandingPad->BeginLabels.size(); j != E; ++j) { @@ -211,6 +203,20 @@ computeCallSiteTable(SmallVectorImpl &CallSites, PadMap[BeginLabel] = P; } } +} + +/// Compute the call-site table. The entry for an invoke has a try-range +/// containing the call, a non-zero landing pad, and an appropriate action. The +/// entry for an ordinary call has a try-range containing the call and zero for +/// the landing pad and the action. Calls marked 'nounwind' have no entry and +/// must not be contained in the try-range of any entry - they form gaps in the +/// table. Entries must be ordered by try-range address. +void EHStreamer:: +computeCallSiteTable(SmallVectorImpl &CallSites, + const SmallVectorImpl &LandingPads, + const SmallVectorImpl &FirstActions) { + RangeMapType PadMap; + computePadMap(LandingPads, PadMap); // The end label of the previous invoke or nounwind try-range. MCSymbol *LastLabel = nullptr; diff --git a/lib/CodeGen/AsmPrinter/EHStreamer.h b/lib/CodeGen/AsmPrinter/EHStreamer.h index 94d0585347e..aa42373b488 100644 --- a/lib/CodeGen/AsmPrinter/EHStreamer.h +++ b/lib/CodeGen/AsmPrinter/EHStreamer.h @@ -80,13 +80,15 @@ protected: /// `false' otherwise. bool callToNoUnwindFunction(const MachineInstr *MI); + void computePadMap(const SmallVectorImpl &LandingPads, + RangeMapType &PadMap); + /// Compute the call-site table. The entry for an invoke has a try-range /// containing the call, a non-zero landing pad and an appropriate action. /// The entry for an ordinary call has a try-range containing the call and /// zero for the landing pad and the action. Calls marked 'nounwind' have /// no entry and must not be contained in the try-range of any entry - they /// form gaps in the table. Entries must be ordered by try-range address. - void computeCallSiteTable(SmallVectorImpl &CallSites, const SmallVectorImpl &LPs, const SmallVectorImpl &FirstActions); diff --git a/lib/CodeGen/AsmPrinter/Win64Exception.cpp b/lib/CodeGen/AsmPrinter/Win64Exception.cpp index 7d76eaddb56..974e94dcb6a 100644 --- a/lib/CodeGen/AsmPrinter/Win64Exception.cpp +++ b/lib/CodeGen/AsmPrinter/Win64Exception.cpp @@ -19,6 +19,7 @@ #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/WinEHFuncInfo.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Mangler.h" #include "llvm/IR/Module.h" @@ -82,7 +83,7 @@ void Win64Exception::beginFunction(const MachineFunction *MF) { /// endFunction - Gather and emit post-function exception information. /// -void Win64Exception::endFunction(const MachineFunction *) { +void Win64Exception::endFunction(const MachineFunction *MF) { if (!shouldEmitPersonality && !shouldEmitMoves) return; @@ -100,6 +101,8 @@ void Win64Exception::endFunction(const MachineFunction *) { EHPersonality Per = MMI->getPersonalityType(); if (Per == EHPersonality::MSVC_Win64SEH) emitCSpecificHandlerTable(); + else if (Per == EHPersonality::MSVC_CXX) + emitCXXFrameHandler3Table(MF); else emitExceptionTable(); @@ -108,11 +111,19 @@ void Win64Exception::endFunction(const MachineFunction *) { Asm->OutStreamer.EmitWinCFIEndProc(); } -const MCSymbolRefExpr *Win64Exception::createImageRel32(const MCSymbol *Value) { +const MCExpr *Win64Exception::createImageRel32(const MCSymbol *Value) { + if (!Value) + return MCConstantExpr::Create(0, Asm->OutContext); return MCSymbolRefExpr::Create(Value, MCSymbolRefExpr::VK_COFF_IMGREL32, Asm->OutContext); } +const MCExpr *Win64Exception::createImageRel32(const GlobalValue *GV) { + if (!GV) + return MCConstantExpr::Create(0, Asm->OutContext); + return createImageRel32(Asm->getSymbol(GV)); +} + /// Emit the language-specific data that __C_specific_handler expects. This /// handler lives in the x64 Microsoft C runtime and allows catching or cleaning /// up after faults with __try, __except, and __finally. The typeinfo values @@ -237,3 +248,200 @@ void Win64Exception::emitCSpecificHandlerTable() { } } } + +void Win64Exception::emitCXXFrameHandler3Table(const MachineFunction *MF) { + const Function *F = MF->getFunction(); + const Function *ParentF = MMI->getWinEHParent(F); + auto &OS = Asm->OutStreamer; + + StringRef ParentLinkageName = + GlobalValue::getRealLinkageName(ParentF->getName()); + + MCSymbol *FuncInfoXData = + Asm->OutContext.GetOrCreateSymbol(Twine("$cppxdata$", ParentLinkageName)); + OS.EmitValue(createImageRel32(FuncInfoXData), 4); + + // The Itanium LSDA table sorts similar landing pads together to simplify the + // actions table, but we don't need that. + SmallVector LandingPads; + const std::vector &PadInfos = MMI->getLandingPads(); + LandingPads.reserve(PadInfos.size()); + for (const auto &LP : PadInfos) + LandingPads.push_back(&LP); + + RangeMapType PadMap; + computePadMap(LandingPads, PadMap); + + // The end label of the previous invoke or nounwind try-range. + MCSymbol *LastLabel = Asm->getFunctionBegin(); + + // Whether there is a potentially throwing instruction (currently this means + // an ordinary call) between the end of the previous try-range and now. + bool SawPotentiallyThrowing = false; + + WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(ParentF); + + int LastEHState = -2; + + // The parent function and the catch handlers contribute to the 'ip2state' + // table. + for (const auto &MBB : *MF) { + for (const auto &MI : MBB) { + if (!MI.isEHLabel()) { + if (MI.isCall()) + SawPotentiallyThrowing |= !callToNoUnwindFunction(&MI); + continue; + } + + // End of the previous try-range? + MCSymbol *BeginLabel = MI.getOperand(0).getMCSymbol(); + if (BeginLabel == LastLabel) + SawPotentiallyThrowing = false; + + // Beginning of a new try-range? + RangeMapType::const_iterator L = PadMap.find(BeginLabel); + if (L == PadMap.end()) + // Nope, it was just some random label. + continue; + + const PadRange &P = L->second; + const LandingPadInfo *LandingPad = LandingPads[P.PadIndex]; + assert(BeginLabel == LandingPad->BeginLabels[P.RangeIndex] && + "Inconsistent landing pad map!"); + + if (SawPotentiallyThrowing) { + FuncInfo.IPToStateList.push_back(std::make_pair(LastLabel, -1)); + SawPotentiallyThrowing = false; + LastEHState = -1; + } + + if (LandingPad->WinEHState != LastEHState) + FuncInfo.IPToStateList.push_back( + std::make_pair(BeginLabel, LandingPad->WinEHState)); + LastEHState = LandingPad->WinEHState; + LastLabel = LandingPad->EndLabels[P.RangeIndex]; + } + } + + if (ParentF != F) + return; + + MCSymbol *UnwindMapXData = nullptr; + MCSymbol *TryBlockMapXData = nullptr; + MCSymbol *IPToStateXData = nullptr; + if (!FuncInfo.UnwindMap.empty()) + UnwindMapXData = Asm->OutContext.GetOrCreateSymbol( + Twine("$stateUnwindMap$", ParentLinkageName)); + if (!FuncInfo.TryBlockMap.empty()) + TryBlockMapXData = Asm->OutContext.GetOrCreateSymbol( + Twine("$tryMap$", ParentLinkageName)); + if (!FuncInfo.IPToStateList.empty()) + IPToStateXData = Asm->OutContext.GetOrCreateSymbol( + Twine("$ip2state$", ParentLinkageName)); + + // FuncInfo { + // uint32_t MagicNumber + // int32_t MaxState; + // UnwindMapEntry *UnwindMap; + // uint32_t NumTryBlocks; + // TryBlockMapEntry *TryBlockMap; + // uint32_t IPMapEntries; + // IPToStateMapEntry *IPToStateMap; + // uint32_t UnwindHelp; // (x64/ARM only) + // ESTypeList *ESTypeList; + // int32_t EHFlags; + // } + // EHFlags & 1 -> Synchronous exceptions only, no async exceptions. + // EHFlags & 2 -> ??? + // EHFlags & 4 -> The function is noexcept(true), unwinding can't continue. + OS.EmitLabel(FuncInfoXData); + OS.EmitIntValue(0x19930522, 4); // MagicNumber + OS.EmitIntValue(FuncInfo.UnwindMap.size(), 4); // MaxState + OS.EmitValue(createImageRel32(UnwindMapXData), 4); // UnwindMap + OS.EmitIntValue(FuncInfo.TryBlockMap.size(), 4); // NumTryBlocks + OS.EmitValue(createImageRel32(TryBlockMapXData), 4); // TryBlockMap + OS.EmitIntValue(FuncInfo.IPToStateList.size(), 4); // IPMapEntries + OS.EmitValue(createImageRel32(IPToStateXData), 4); // IPToStateMap + OS.EmitIntValue(FuncInfo.UnwindHelpFrameOffset, 4); // UnwindHelp + OS.EmitIntValue(0, 4); // ESTypeList + OS.EmitIntValue(1, 4); // EHFlags + + // UnwindMapEntry { + // int32_t ToState; + // void (*Action)(); + // }; + if (UnwindMapXData) { + OS.EmitLabel(UnwindMapXData); + for (const WinEHUnwindMapEntry &UME : FuncInfo.UnwindMap) { + OS.EmitIntValue(UME.ToState, 4); // ToState + OS.EmitValue(createImageRel32(UME.Cleanup), 4); // Action + } + } + + // TryBlockMap { + // int32_t TryLow; + // int32_t TryHigh; + // int32_t CatchHigh; + // int32_t NumCatches; + // HandlerType *HandlerArray; + // }; + if (TryBlockMapXData) { + OS.EmitLabel(TryBlockMapXData); + SmallVector HandlerMaps; + for (size_t I = 0, E = FuncInfo.TryBlockMap.size(); I != E; ++I) { + WinEHTryBlockMapEntry &TBME = FuncInfo.TryBlockMap[I]; + MCSymbol *HandlerMapXData = nullptr; + + if (!TBME.HandlerArray.empty()) + HandlerMapXData = + Asm->OutContext.GetOrCreateSymbol(Twine("$handlerMap$") + .concat(Twine(I)) + .concat("$") + .concat(ParentLinkageName)); + + HandlerMaps.push_back(HandlerMapXData); + + assert(TBME.TryLow <= TBME.TryHigh); + assert(TBME.CatchHigh > TBME.TryHigh); + OS.EmitIntValue(TBME.TryLow, 4); // TryLow + OS.EmitIntValue(TBME.TryHigh, 4); // TryHigh + OS.EmitIntValue(TBME.CatchHigh, 4); // CatchHigh + OS.EmitIntValue(TBME.HandlerArray.size(), 4); // NumCatches + OS.EmitValue(createImageRel32(HandlerMapXData), 4); // HandlerArray + } + + for (size_t I = 0, E = FuncInfo.TryBlockMap.size(); I != E; ++I) { + WinEHTryBlockMapEntry &TBME = FuncInfo.TryBlockMap[I]; + MCSymbol *HandlerMapXData = HandlerMaps[I]; + if (!HandlerMapXData) + continue; + // HandlerType { + // int32_t Adjectives; + // TypeDescriptor *Type; + // int32_t CatchObjOffset; + // void (*Handler)(); + // int32_t ParentFrameOffset; // x64 only + // }; + OS.EmitLabel(HandlerMapXData); + for (const WinEHHandlerType &HT : TBME.HandlerArray) { + OS.EmitIntValue(HT.Adjectives, 4); // Adjectives + OS.EmitValue(createImageRel32(HT.TypeDescriptor), 4); // Type + OS.EmitIntValue(0, 4); // CatchObjOffset + OS.EmitValue(createImageRel32(HT.Handler), 4); // Handler + OS.EmitIntValue(0, 4); // ParentFrameOffset + } + } + } + + // IPToStateMapEntry { + // void *IP; + // int32_t State; + // }; + if (IPToStateXData) { + OS.EmitLabel(IPToStateXData); + for (auto &IPStatePair : FuncInfo.IPToStateList) { + OS.EmitValue(createImageRel32(IPStatePair.first), 4); // IP + OS.EmitIntValue(IPStatePair.second, 4); // State + } + } +} diff --git a/lib/CodeGen/AsmPrinter/Win64Exception.h b/lib/CodeGen/AsmPrinter/Win64Exception.h index b2d5d1bce56..eb02ca47b39 100644 --- a/lib/CodeGen/AsmPrinter/Win64Exception.h +++ b/lib/CodeGen/AsmPrinter/Win64Exception.h @@ -17,7 +17,9 @@ #include "EHStreamer.h" namespace llvm { +class GlobalValue; class MachineFunction; +class MCExpr; class Win64Exception : public EHStreamer { /// Per-function flag to indicate if personality info should be emitted. @@ -31,7 +33,10 @@ class Win64Exception : public EHStreamer { void emitCSpecificHandlerTable(); - const MCSymbolRefExpr *createImageRel32(const MCSymbol *Value); + void emitCXXFrameHandler3Table(const MachineFunction *MF); + + const MCExpr *createImageRel32(const MCSymbol *Value); + const MCExpr *createImageRel32(const GlobalValue *GV); public: //===--------------------------------------------------------------------===// diff --git a/lib/CodeGen/MachineModuleInfo.cpp b/lib/CodeGen/MachineModuleInfo.cpp index fca7df097b6..d5491213293 100644 --- a/lib/CodeGen/MachineModuleInfo.cpp +++ b/lib/CodeGen/MachineModuleInfo.cpp @@ -14,6 +14,7 @@ #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/Passes.h" +#include "llvm/CodeGen/WinEHFuncInfo.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/GlobalVariable.h" @@ -425,6 +426,12 @@ void MachineModuleInfo::addPersonality(MachineBasicBlock *LandingPad, Personalities.push_back(Personality); } +void MachineModuleInfo::addWinEHState(MachineBasicBlock *LandingPad, + int State) { + LandingPadInfo &LP = getOrCreateLandingPadInfo(LandingPad); + LP.WinEHState = State; +} + /// addCatchTypeInfo - Provide the catch typeinfo for a landing pad. /// void MachineModuleInfo:: @@ -588,3 +595,18 @@ unsigned MachineModuleInfo::getPersonalityIndex() const { // in the zero index. return 0; } + +const Function *MachineModuleInfo::getWinEHParent(const Function *F) const { + StringRef WinEHParentName = + F->getFnAttribute("wineh-parent").getValueAsString(); + if (WinEHParentName.empty() || WinEHParentName == F->getName()) + return F; + return F->getParent()->getFunction(WinEHParentName); +} + +WinEHFuncInfo &MachineModuleInfo::getWinEHFuncInfo(const Function *F) { + auto &Ptr = FuncInfoMap[getWinEHParent(F)]; + if (!Ptr) + Ptr.reset(new WinEHFuncInfo); + return *Ptr; +} diff --git a/lib/CodeGen/PrologEpilogInserter.cpp b/lib/CodeGen/PrologEpilogInserter.cpp index e073e6a8437..5334a633ead 100644 --- a/lib/CodeGen/PrologEpilogInserter.cpp +++ b/lib/CodeGen/PrologEpilogInserter.cpp @@ -30,6 +30,7 @@ #include "llvm/CodeGen/Passes.h" #include "llvm/CodeGen/RegisterScavenging.h" #include "llvm/CodeGen/StackProtector.h" +#include "llvm/CodeGen/WinEHFuncInfo.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/InlineAsm.h" #include "llvm/IR/LLVMContext.h" @@ -752,6 +753,25 @@ void PEI::replaceFrameIndices(MachineFunction &Fn) { const TargetFrameLowering &TFI = *Fn.getSubtarget().getFrameLowering(); if (!TFI.needsFrameIndexResolution(Fn)) return; + MachineModuleInfo &MMI = Fn.getMMI(); + const Function *F = Fn.getFunction(); + const Function *ParentF = MMI.getWinEHParent(F); + unsigned FrameReg; + if (F == ParentF) { + WinEHFuncInfo &FuncInfo = MMI.getWinEHFuncInfo(Fn.getFunction()); + // FIXME: This should be unconditional but we have bugs in the preparation + // pass. + if (FuncInfo.UnwindHelpFrameIdx != INT_MAX) + FuncInfo.UnwindHelpFrameOffset = TFI.getFrameIndexReferenceFromSP( + Fn, FuncInfo.UnwindHelpFrameIdx, FrameReg); + } else if (MMI.hasWinEHFuncInfo(F)) { + WinEHFuncInfo &FuncInfo = MMI.getWinEHFuncInfo(Fn.getFunction()); + auto I = FuncInfo.CatchHandlerParentFrameObjIdx.find(F); + if (I != FuncInfo.CatchHandlerParentFrameObjIdx.end()) + FuncInfo.CatchHandlerParentFrameObjOffset[F] = + TFI.getFrameIndexReferenceFromSP(Fn, I->second, FrameReg); + } + // Store SPAdj at exit of a basic block. SmallVector SPState; SPState.resize(Fn.getNumBlockIDs()); diff --git a/lib/CodeGen/SelectionDAG/FastISel.cpp b/lib/CodeGen/SelectionDAG/FastISel.cpp index 223a149924b..73061b6dc3e 100644 --- a/lib/CodeGen/SelectionDAG/FastISel.cpp +++ b/lib/CodeGen/SelectionDAG/FastISel.cpp @@ -1079,6 +1079,13 @@ bool FastISel::selectIntrinsicCall(const IntrinsicInst *II) { // The donothing intrinsic does, well, nothing. case Intrinsic::donothing: return true; + case Intrinsic::eh_actions: { + unsigned ResultReg = getRegForValue(UndefValue::get(II->getType())); + if (!ResultReg) + return false; + updateValueMap(II, ResultReg); + return true; + } case Intrinsic::dbg_declare: { const DbgDeclareInst *DI = cast(II); DIVariable DIVar(DI->getVariable()); diff --git a/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp b/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp index 80bf9755ec8..77b31fc0566 100644 --- a/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp +++ b/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp @@ -20,6 +20,7 @@ #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/WinEHFuncInfo.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DebugInfo.h" #include "llvm/IR/DerivedTypes.h" @@ -79,12 +80,34 @@ static ISD::NodeType getPreferredExtendForValue(const Value *V) { return ExtendKind; } +namespace { +struct WinEHNumbering { + WinEHNumbering(WinEHFuncInfo &FuncInfo) : FuncInfo(FuncInfo), NextState(0) {} + + WinEHFuncInfo &FuncInfo; + int NextState; + + SmallVector HandlerStack; + + int currentEHNumber() const { + return HandlerStack.empty() ? -1 : HandlerStack.back()->getEHState(); + } + + void parseEHActions(const IntrinsicInst *II, + SmallVectorImpl &Actions); + void createUnwindMapEntry(int ToState, ActionHandler *AH); + void proccessCallSite(ArrayRef Actions, ImmutableCallSite CS); + void calculateStateNumbers(const Function &F); +}; +} + void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf, SelectionDAG *DAG) { Fn = &fn; MF = &mf; TLI = MF->getSubtarget().getTargetLowering(); RegInfo = &MF->getRegInfo(); + MachineModuleInfo &MMI = MF->getMMI(); // Check whether the function can return without sret-demotion. SmallVector Outs; @@ -178,7 +201,6 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf, // during the initial isel pass through the IR so that it is done // in a predictable order. if (const DbgDeclareInst *DI = dyn_cast(I)) { - MachineModuleInfo &MMI = MF->getMMI(); DIVariable DIVar(DI->getVariable()); assert((!DIVar || DIVar.isVariable()) && "Variable in DbgDeclareInst should be either null or a DIVariable."); @@ -250,8 +272,127 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf, // Mark landing pad blocks. for (BB = Fn->begin(); BB != EB; ++BB) - if (const InvokeInst *Invoke = dyn_cast(BB->getTerminator())) + if (const auto *Invoke = dyn_cast(BB->getTerminator())) MBBMap[Invoke->getSuccessor(1)]->setIsLandingPad(); + + // Calculate EH numbers for WinEH. + if (fn.getFnAttribute("wineh-parent").getValueAsString() == fn.getName()) + WinEHNumbering(MMI.getWinEHFuncInfo(&fn)).calculateStateNumbers(fn); +} + +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; + if (auto *CH = dyn_cast(AH)) + UME.Cleanup = cast(CH->getHandlerBlockOrFunc()); + else + UME.Cleanup = nullptr; + FuncInfo.UnwindMap.push_back(UME); +} + +static void print_name(const Value *V) { + if (!V) { + DEBUG(dbgs() << "null"); + return; + } + + if (const auto *F = dyn_cast(V)) + DEBUG(dbgs() << F->getName()); + else + DEBUG(V->dump()); +} + +void WinEHNumbering::proccessCallSite(ArrayRef Actions, + ImmutableCallSite CS) { + // float, int + // float, double, int + int FirstMismatch = 0; + for (int E = std::min(HandlerStack.size(), Actions.size()); FirstMismatch < E; + ++FirstMismatch) { + if (HandlerStack[FirstMismatch]->getHandlerBlockOrFunc() != + Actions[FirstMismatch]->getHandlerBlockOrFunc()) + break; + delete Actions[FirstMismatch]; + } + + // Don't recurse while we are looping over the handler stack. Instead, defer + // the numbering of the catch handlers until we are done popping. + SmallVector UnnumberedHandlers; + for (int I = HandlerStack.size() - 1; I >= FirstMismatch; --I) { + if (auto *CH = dyn_cast(HandlerStack.back())) + if (const auto *F = dyn_cast(CH->getHandlerBlockOrFunc())) + UnnumberedHandlers.push_back(F); + // Pop the handlers off of the stack. + delete HandlerStack.back(); + HandlerStack.pop_back(); + } + + for (const Function *F : UnnumberedHandlers) + calculateStateNumbers(*F); + + for (size_t I = FirstMismatch; I != Actions.size(); ++I) { + createUnwindMapEntry(currentEHNumber(), Actions[I]); + Actions[I]->setEHState(NextState++); + DEBUG(dbgs() << "Creating unwind map entry for: ("); + print_name(Actions[I]->getHandlerBlockOrFunc()); + DEBUG(dbgs() << ", " << currentEHNumber() << ")\n"); + HandlerStack.push_back(Actions[I]); + } + + DEBUG(dbgs() << "In EHState " << currentEHNumber() << " for CallSite: "); + print_name(CS ? CS.getCalledValue() : nullptr); + DEBUG(dbgs() << '\n'); +} + +void WinEHNumbering::calculateStateNumbers(const Function &F) { + DEBUG(dbgs() << "Calculating state numbers for: " << F.getName() << '\n'); + SmallVector ActionList; + for (const BasicBlock &BB : F) { + for (const Instruction &I : BB) { + const auto *CI = dyn_cast(&I); + if (!CI || CI->doesNotThrow()) + continue; + proccessCallSite(None, CI); + } + const auto *II = dyn_cast(BB.getTerminator()); + if (!II) + continue; + const LandingPadInst *LPI = II->getLandingPadInst(); + if (auto *ActionsCall = dyn_cast(LPI->getNextNode())) { + assert(ActionsCall->getIntrinsicID() == Intrinsic::eh_actions); + parseEHActions(ActionsCall, ActionList); + proccessCallSite(ActionList, II); + ActionList.clear(); + FuncInfo.LandingPadStateMap[LPI] = currentEHNumber(); + } + } + proccessCallSite(None, ImmutableCallSite()); } /// clear - Clear out all the function-specific state. This returns this diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index 37f945f138a..fd9d7e6b69a 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -35,6 +35,7 @@ #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/SelectionDAG.h" #include "llvm/CodeGen/StackMaps.h" +#include "llvm/CodeGen/WinEHFuncInfo.h" #include "llvm/IR/CallingConv.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" @@ -5360,6 +5361,9 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) { } case Intrinsic::clear_cache: return TLI.getClearCacheBuiltinName(); + case Intrinsic::eh_actions: + setValue(&I, DAG.getUNDEF(TLI.getPointerTy())); + return nullptr; case Intrinsic::donothing: // ignore return nullptr; @@ -5452,8 +5456,10 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) { assert(FuncInfo.StaticAllocaMap.count(Slot) && "can only use static allocas with llvm.eh.parentframe"); int FI = FuncInfo.StaticAllocaMap[Slot]; - // TODO: Save this in the not-yet-existent WinEHFuncInfo struct. - (void)FI; + MachineFunction &MF = DAG.getMachineFunction(); + const Function *F = MF.getFunction(); + MachineModuleInfo &MMI = MF.getMMI(); + MMI.getWinEHFuncInfo(F).CatchHandlerParentFrameObjIdx[F] = FI; return nullptr; } case Intrinsic::eh_unwindhelp: { @@ -5462,8 +5468,9 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) { assert(FuncInfo.StaticAllocaMap.count(Slot) && "can only use static allocas with llvm.eh.unwindhelp"); int FI = FuncInfo.StaticAllocaMap[Slot]; - // TODO: Save this in the not-yet-existent WinEHFuncInfo struct. - (void)FI; + MachineFunction &MF = DAG.getMachineFunction(); + MachineModuleInfo &MMI = MF.getMMI(); + MMI.getWinEHFuncInfo(MF.getFunction()).UnwindHelpFrameIdx = FI; return nullptr; } } diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp index 17950058bb2..3de9c26a905 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -33,6 +33,7 @@ #include "llvm/CodeGen/SchedulerRegistry.h" #include "llvm/CodeGen/SelectionDAG.h" #include "llvm/CodeGen/SelectionDAGISel.h" +#include "llvm/CodeGen/WinEHFuncInfo.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DebugInfo.h" #include "llvm/IR/Function.h" @@ -988,6 +989,10 @@ void SelectionDAGISel::PrepareEHLandingPad() { FuncInfo->InsertPt = MBB->end(); return; } + if (MF->getMMI().getPersonalityType() == EHPersonality::MSVC_CXX) { + WinEHFuncInfo &FuncInfo = MF->getMMI().getWinEHFuncInfo(MF->getFunction()); + MF->getMMI().addWinEHState(MBB, FuncInfo.LandingPadStateMap[LPadInst]); + } // Mark exception register as live in. if (unsigned Reg = TLI->getExceptionPointerRegister()) diff --git a/lib/CodeGen/WinEHPrepare.cpp b/lib/CodeGen/WinEHPrepare.cpp index e35b94f1d36..94e046c424d 100644 --- a/lib/CodeGen/WinEHPrepare.cpp +++ b/lib/CodeGen/WinEHPrepare.cpp @@ -20,6 +20,7 @@ #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/TinyPtrVector.h" #include "llvm/Analysis/LibCallSemantics.h" +#include "llvm/CodeGen/WinEHFuncInfo.h" #include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Instructions.h" @@ -51,12 +52,7 @@ typedef MapVector> FrameVarInfoMap; typedef SmallSet VisitedBlockSet; -enum ActionType { Catch, Cleanup }; - class LandingPadActions; -class ActionHandler; -class CatchHandler; -class CleanupHandler; class LandingPadMap; typedef DenseMap CatchHandlerMapTy; @@ -242,66 +238,6 @@ public: BasicBlock *NewBB) override; }; -class ActionHandler { -public: - ActionHandler(BasicBlock *BB, ActionType Type) - : StartBB(BB), Type(Type), HandlerBlockOrFunc(nullptr) {} - - ActionType getType() const { return Type; } - BasicBlock *getStartBlock() const { return StartBB; } - - bool hasBeenProcessed() { return HandlerBlockOrFunc != nullptr; } - - void setHandlerBlockOrFunc(Constant *F) { HandlerBlockOrFunc = F; } - Constant *getHandlerBlockOrFunc() { return HandlerBlockOrFunc; } - -private: - BasicBlock *StartBB; - ActionType Type; - - // Can be either a BlockAddress or a Function depending on the EH personality. - Constant *HandlerBlockOrFunc; -}; - -class CatchHandler : public ActionHandler { -public: - CatchHandler(BasicBlock *BB, Constant *Selector, BasicBlock *NextBB) - : ActionHandler(BB, ActionType::Catch), Selector(Selector), - NextBB(NextBB), ExceptionObjectVar(nullptr) {} - - // Method for support type inquiry through isa, cast, and dyn_cast: - static inline bool classof(const ActionHandler *H) { - return H->getType() == ActionType::Catch; - } - - Constant *getSelector() const { return Selector; } - BasicBlock *getNextBB() const { return NextBB; } - - const Value *getExceptionVar() { return ExceptionObjectVar; } - TinyPtrVector &getReturnTargets() { return ReturnTargets; } - - void setExceptionVar(const Value *Val) { ExceptionObjectVar = Val; } - void setReturnTargets(TinyPtrVector &Targets) { - ReturnTargets = Targets; - } - -private: - Constant *Selector; - BasicBlock *NextBB; - const Value *ExceptionObjectVar; - TinyPtrVector ReturnTargets; -}; - -class CleanupHandler : public ActionHandler { -public: - CleanupHandler(BasicBlock *BB) : ActionHandler(BB, ActionType::Cleanup) {} - - // Method for support type inquiry through isa, cast, and dyn_cast: - static inline bool classof(const ActionHandler *H) { - return H->getType() == ActionType::Cleanup; - } -}; - class LandingPadActions { public: LandingPadActions() : HasCleanupHandlers(false) {} @@ -314,6 +250,7 @@ public: bool includesCleanup() const { return HasCleanupHandlers; } + SmallVectorImpl &actions() { return Actions; } SmallVectorImpl::iterator begin() { return Actions.begin(); } SmallVectorImpl::iterator end() { return Actions.end(); } @@ -454,7 +391,7 @@ bool WinEHPrepare::prepareExceptionHandlers( // Replace the landing pad with a new llvm.eh.action based landing pad. BasicBlock *NewLPadBB = BasicBlock::Create(Context, "lpad", &F, LPadBB); assert(!isa(LPadBB->begin())); - Instruction *NewLPad = LPad->clone(); + auto *NewLPad = cast(LPad->clone()); NewLPadBB->getInstList().push_back(NewLPad); while (!pred_empty(LPadBB)) { auto *pred = *pred_begin(LPadBB); @@ -503,6 +440,8 @@ bool WinEHPrepare::prepareExceptionHandlers( if (!HandlersOutlined) return false; + F.addFnAttr("wineh-parent", F.getName()); + // Delete any blocks that were only used by handlers that were outlined above. removeUnreachableBlocks(F); @@ -609,7 +548,8 @@ bool WinEHPrepare::prepareExceptionHandlers( Type *UnwindHelpTy = Type::getInt64Ty(Context); AllocaInst *UnwindHelp = new AllocaInst(UnwindHelpTy, "unwindhelp", &F.getEntryBlock().front()); - Builder.CreateStore(llvm::ConstantInt::get(UnwindHelpTy, -2), UnwindHelp); + Builder.CreateStore(llvm::ConstantInt::get(UnwindHelpTy, -2), UnwindHelp, + /*isVolatile=*/true); Function *UnwindHelpFn = Intrinsic::getDeclaration(M, Intrinsic::eh_unwindhelp); Builder.CreateCall(UnwindHelpFn, @@ -681,6 +621,8 @@ bool WinEHPrepare::outlineHandler(ActionHandler *Action, Function *SrcFn, SrcFn->getName() + ".cleanup", M); } + Handler->addFnAttr("wineh-parent", SrcFn->getName()); + // Generate a standard prolog to setup the frame recovery structure. IRBuilder<> Builder(Context); BasicBlock *Entry = BasicBlock::Create(Context, "entry"); diff --git a/test/CodeGen/WinEH/cppeh-catch-all.ll b/test/CodeGen/WinEH/cppeh-catch-all.ll index 6e69862ce9f..5a51fe6ba45 100644 --- a/test/CodeGen/WinEH/cppeh-catch-all.ll +++ b/test/CodeGen/WinEH/cppeh-catch-all.ll @@ -19,7 +19,7 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-pc-windows-msvc" ; The function entry in this case remains unchanged. -; CHECK: define void @_Z4testv() #0 { +; CHECK: define void @_Z4testv() ; CHECK: entry: ; CHECK: invoke void @_Z9may_throwv() ; CHECK: to label %invoke.cont unwind label %[[LPAD_LABEL:lpad[0-9]+]] @@ -70,7 +70,7 @@ try.cont: ; preds = %invoke.cont2, %invo ; CHECK: } } -; CHECK: define internal i8* @_Z4testv.catch(i8*, i8*) { +; CHECK: define internal i8* @_Z4testv.catch(i8*, i8*) ; CHECK: entry: ; CHECK: call void @_Z16handle_exceptionv() ; CHECK: ret i8* blockaddress(@_Z4testv, %try.cont) diff --git a/test/CodeGen/WinEH/cppeh-catch-scalar.ll b/test/CodeGen/WinEH/cppeh-catch-scalar.ll index 0f8a7a8e063..adb048a982b 100644 --- a/test/CodeGen/WinEH/cppeh-catch-scalar.ll +++ b/test/CodeGen/WinEH/cppeh-catch-scalar.ll @@ -21,7 +21,7 @@ target triple = "x86_64-pc-windows-msvc" @_ZTIi = external constant i8* ; The function entry will be rewritten like this. -; CHECK: define void @_Z4testv() #0 { +; CHECK: define void @_Z4testv() ; CHECK: entry: ; CHECK: [[I_PTR:\%.+]] = alloca i32, align 4 ; CHECK: call void (...)* @llvm.frameescape(i32* [[I_PTR]]) @@ -94,7 +94,7 @@ eh.resume: ; preds = %catch.dispatch ; CHECK: } } -; CHECK: define internal i8* @_Z4testv.catch(i8*, i8*) { +; CHECK: define internal i8* @_Z4testv.catch(i8*, i8*) ; CHECK: entry: ; CHECK: [[RECOVER_I:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @_Z4testv to i8*), i8* %1, i32 0) ; CHECK: [[I_PTR1:\%.+]] = bitcast i8* [[RECOVER_I]] to i32* diff --git a/test/CodeGen/WinEH/cppeh-catch-unwind.ll b/test/CodeGen/WinEH/cppeh-catch-unwind.ll index a9849d9cb1c..60a5256a133 100644 --- a/test/CodeGen/WinEH/cppeh-catch-unwind.ll +++ b/test/CodeGen/WinEH/cppeh-catch-unwind.ll @@ -178,7 +178,7 @@ eh.resume: ; preds = %catch.dispatch7 ; CHECK: } } -; CHECK-LABEL: define internal i8* @"\01?test@@YAXXZ.catch"(i8*, i8*) { +; CHECK-LABEL: define internal i8* @"\01?test@@YAXXZ.catch"(i8*, i8*) ; CHECK: entry: ; CHECK: [[PARENTFRAME:\%.+]] = alloca i8* ; CHECK: store volatile i8* %1, i8** [[PARENTFRAME]] @@ -189,15 +189,15 @@ eh.resume: ; preds = %catch.dispatch7 ; CHECK: ret i8* blockaddress(@"\01?test@@YAXXZ", %try.cont15) ; CHECK: } -; CHECK-LABEL: define internal void @"\01?test@@YAXXZ.cleanup"(i8*, i8*) { +; CHECK-LABEL: define internal void @"\01?test@@YAXXZ.cleanup"(i8*, i8*) ; CHECK: entry: ; CHECK: [[RECOVER_OBJ:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 1) ; CHECK: [[OBJ_PTR:\%.+]] = bitcast i8* %obj.i8 to %class.SomeClass* -; CHECK: call void @"\01??1SomeClass@@QEAA@XZ"(%class.SomeClass* [[OBJ_PTR]]) #3 +; CHECK: call void @"\01??1SomeClass@@QEAA@XZ"(%class.SomeClass* [[OBJ_PTR]]) ; CHECK: ret void ; CHECK: } -; CHECK-LABEL: define internal i8* @"\01?test@@YAXXZ.catch1"(i8*, i8*) { +; CHECK-LABEL: define internal i8* @"\01?test@@YAXXZ.catch1"(i8*, i8*) ; CHECK: entry: ; CHECK: [[PARENTFRAME:\%.+]] = alloca i8* ; CHECK: store volatile i8* %1, i8** [[PARENTFRAME]] diff --git a/test/CodeGen/WinEH/cppeh-cleanups.ll b/test/CodeGen/WinEH/cppeh-cleanups.ll new file mode 100644 index 00000000000..64d9980be39 --- /dev/null +++ b/test/CodeGen/WinEH/cppeh-cleanups.ll @@ -0,0 +1,226 @@ +; RUN: llc < %s | FileCheck %s + +target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-windows-msvc" + +%rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] } +%eh.CatchableType = type { i32, i32, i32, i32, i32, i32, i32 } +%eh.CatchableTypeArray.1 = type { i32, [1 x i32] } +%eh.ThrowInfo = type { i32, i32, i32, i32 } +%struct.S = type { i8 } + +$"\01??_DS@@QEAA@XZ" = comdat any + +$"\01??_R0H@8" = comdat any + +$"_CT??_R0H@84" = comdat any + +$_CTA1H = comdat any + +$_TI1H = comdat any + +@"\01??_7type_info@@6B@" = external constant i8* +@"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat +@__ImageBase = external constant i8 +@"_CT??_R0H@84" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 1, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 0, i32 -1, i32 0, i32 4, i32 0 }, section ".xdata", comdat +@_CTA1H = linkonce_odr unnamed_addr constant %eh.CatchableTypeArray.1 { i32 1, [1 x i32] [i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableType* @"_CT??_R0H@84" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32)] }, section ".xdata", comdat +@_TI1H = linkonce_odr unnamed_addr constant %eh.ThrowInfo { i32 0, i32 0, i32 0, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableTypeArray.1* @_CTA1H to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, section ".xdata", comdat + + +; CHECK-LABEL: ?test1@@YAXXZ": +; CHECK: .seh_handlerdata +; CHECK-NEXT: .long ("$cppxdata$?test1@@YAXXZ")@IMGREL +; CHECK-NEXT:"$cppxdata$?test1@@YAXXZ": +; CHECK-NEXT: .long 429065506 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long ("$stateUnwindMap$?test1@@YAXXZ")@IMGREL +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long ("$ip2state$?test1@@YAXXZ")@IMGREL +; CHECK-NEXT: .long 64 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 1 +; CHECK-NEXT:"$stateUnwindMap$?test1@@YAXXZ": +; CHECK-NEXT: .long -1 +; CHECK-NEXT: .long "?test1@@YAXXZ.cleanup"@IMGREL +; CHECK-NEXT:"$ip2state$?test1@@YAXXZ": +; CHECK-NEXT: .long .Ltmp0@IMGREL +; CHECK-NEXT: .long 0 + +define void @"\01?test1@@YAXXZ"() #0 { +entry: + %unwindhelp = alloca i64 + %tmp = alloca i32, align 4 + %exn.slot = alloca i8* + %ehselector.slot = alloca i32 + store i32 0, i32* %tmp + %0 = bitcast i32* %tmp to i8* + call void (...)* @llvm.frameescape() + store volatile i64 -2, i64* %unwindhelp + %1 = bitcast i64* %unwindhelp to i8* + call void @llvm.eh.unwindhelp(i8* %1) + invoke void @_CxxThrowException(i8* %0, %eh.ThrowInfo* @_TI1H) #8 + to label %unreachable unwind label %lpad1 + +lpad1: ; preds = %entry + %2 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) + cleanup + %recover = call i8* (...)* @llvm.eh.actions(i32 0, void (i8*, i8*)* @"\01?test1@@YAXXZ.cleanup") + indirectbr i8* %recover, [] + +unreachable: ; preds = %entry + unreachable +} + +declare void @_CxxThrowException(i8*, %eh.ThrowInfo*) + +declare i32 @__CxxFrameHandler3(...) + +; Function Attrs: nounwind +define linkonce_odr void @"\01??_DS@@QEAA@XZ"(%struct.S* %this) unnamed_addr #1 comdat align 2 { +entry: + %this.addr = alloca %struct.S*, align 8 + store %struct.S* %this, %struct.S** %this.addr, align 8 + %this1 = load %struct.S*, %struct.S** %this.addr + call void @"\01??1S@@QEAA@XZ"(%struct.S* %this1) #4 + ret void +} + +; CHECK-LABEL: "?test2@@YAX_N@Z": +; CHECK: .seh_handlerdata +; CHECK-NEXT: .long ("$cppxdata$?test2@@YAX_N@Z")@IMGREL +; CHECK-NEXT:"$cppxdata$?test2@@YAX_N@Z": +; CHECK-NEXT: .long 429065506 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long ("$stateUnwindMap$?test2@@YAX_N@Z")@IMGREL +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long ("$ip2state$?test2@@YAX_N@Z")@IMGREL +; CHECK-NEXT: .long 64 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 1 +; CHECK-NEXT:"$stateUnwindMap$?test2@@YAX_N@Z": +; CHECK-NEXT: .long -1 +; CHECK-NEXT: .long "?test2@@YAX_N@Z.cleanup"@IMGREL +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long "?test2@@YAX_N@Z.cleanup1"@IMGREL +; CHECK-NEXT:"$ip2state$?test2@@YAX_N@Z": +; CHECK-NEXT: .long .Lfunc_begin1@IMGREL +; CHECK-NEXT: .long -1 +; CHECK-NEXT: .long .Ltmp7@IMGREL +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long .Ltmp9@IMGREL +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp12@IMGREL +; CHECK-NEXT: .long 0 + +define void @"\01?test2@@YAX_N@Z"(i1 zeroext %b) #2 { +entry: + %unwindhelp = alloca i64 + %b.addr = alloca i8, align 1 + %s = alloca %struct.S, align 1 + %exn.slot = alloca i8* + %ehselector.slot = alloca i32 + %s1 = alloca %struct.S, align 1 + %frombool = zext i1 %b to i8 + store i8 %frombool, i8* %b.addr, align 1 + call void @"\01?may_throw@@YAXXZ"() + call void (...)* @llvm.frameescape(%struct.S* %s, %struct.S* %s1) + store volatile i64 -2, i64* %unwindhelp + %0 = bitcast i64* %unwindhelp to i8* + call void @llvm.eh.unwindhelp(i8* %0) + invoke void @"\01?may_throw@@YAXXZ"() + to label %invoke.cont unwind label %lpad1 + +invoke.cont: ; preds = %entry + %1 = load i8, i8* %b.addr, align 1 + %tobool = trunc i8 %1 to i1 + br i1 %tobool, label %if.then, label %if.else + +if.then: ; preds = %invoke.cont + invoke void @"\01?may_throw@@YAXXZ"() + to label %invoke.cont3 unwind label %lpad3 + +invoke.cont3: ; preds = %if.then + call void @"\01??_DS@@QEAA@XZ"(%struct.S* %s1) #4 + br label %if.end + +lpad1: ; preds = %entry, %if.end + %2 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) + cleanup + %recover = call i8* (...)* @llvm.eh.actions(i32 0, void (i8*, i8*)* @"\01?test2@@YAX_N@Z.cleanup") + indirectbr i8* %recover, [] + +lpad3: ; preds = %if.then + %3 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) + cleanup + %recover4 = call i8* (...)* @llvm.eh.actions(i32 0, void (i8*, i8*)* @"\01?test2@@YAX_N@Z.cleanup1", i32 0, void (i8*, i8*)* @"\01?test2@@YAX_N@Z.cleanup") + indirectbr i8* %recover4, [] + +if.else: ; preds = %invoke.cont + call void @"\01?dont_throw@@YAXXZ"() #4 + br label %if.end + +if.end: ; preds = %if.else, %invoke.cont3 + invoke void @"\01?may_throw@@YAXXZ"() + to label %invoke.cont4 unwind label %lpad1 + +invoke.cont4: ; preds = %if.end + call void @"\01??_DS@@QEAA@XZ"(%struct.S* %s) #4 + ret void +} + +declare void @"\01?may_throw@@YAXXZ"() #3 + +; Function Attrs: nounwind +declare void @"\01?dont_throw@@YAXXZ"() #1 + +; Function Attrs: nounwind +declare void @"\01??1S@@QEAA@XZ"(%struct.S*) #1 + +; Function Attrs: nounwind +declare i8* @llvm.eh.actions(...) #4 + +define internal void @"\01?test1@@YAXXZ.cleanup"(i8*, i8*) #5 { +entry: + %s = alloca %struct.S, align 1 + call void @"\01??_DS@@QEAA@XZ"(%struct.S* %s) #4 + ret void +} + +; Function Attrs: nounwind +declare void @llvm.frameescape(...) #4 + +; Function Attrs: nounwind readnone +declare i8* @llvm.framerecover(i8*, i8*, i32) #6 + +; Function Attrs: nounwind +declare void @llvm.eh.unwindhelp(i8*) #4 + +define internal void @"\01?test2@@YAX_N@Z.cleanup"(i8*, i8*) #7 { +entry: + %s.i8 = call i8* @llvm.framerecover(i8* bitcast (void (i1)* @"\01?test2@@YAX_N@Z" to i8*), i8* %1, i32 0) + %s = bitcast i8* %s.i8 to %struct.S* + call void @"\01??_DS@@QEAA@XZ"(%struct.S* %s) #4 + ret void +} + +define internal void @"\01?test2@@YAX_N@Z.cleanup1"(i8*, i8*) #7 { +entry: + %s1.i8 = call i8* @llvm.framerecover(i8* bitcast (void (i1)* @"\01?test2@@YAX_N@Z" to i8*), i8* %1, i32 1) + %s1 = bitcast i8* %s1.i8 to %struct.S* + call void @"\01??_DS@@QEAA@XZ"(%struct.S* %s1) #4 + ret void +} + +attributes #0 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" "wineh-parent"="?test1@@YAXXZ" } +attributes #1 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" "wineh-parent"="?test2@@YAX_N@Z" } +attributes #3 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #4 = { nounwind } +attributes #5 = { "wineh-parent"="?test1@@YAXXZ" } +attributes #6 = { nounwind readnone } +attributes #7 = { "wineh-parent"="?test2@@YAX_N@Z" } +attributes #8 = { noreturn } diff --git a/test/CodeGen/WinEH/cppeh-frame-vars.ll b/test/CodeGen/WinEH/cppeh-frame-vars.ll index dc5ed1cc0e2..cb97e6e5638 100644 --- a/test/CodeGen/WinEH/cppeh-frame-vars.ll +++ b/test/CodeGen/WinEH/cppeh-frame-vars.ll @@ -47,7 +47,7 @@ $"\01??_R0H@8" = comdat any @"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat ; The function entry should be rewritten like this. -; CHECK: define void @"\01?test@@YAXXZ"() #0 { +; CHECK: define void @"\01?test@@YAXXZ"() ; CHECK: entry: ; CHECK: [[NUMEXCEPTIONS_PTR:\%.+]] = alloca i32, align 4 ; CHECK: [[EXCEPTIONVAL_PTR:\%.+]] = alloca [10 x i32], align 16 @@ -196,7 +196,7 @@ eh.resume: ; preds = %catch.dispatch } ; The following catch handler should be outlined. -; CHECK-LABEL: define internal i8* @"\01?test@@YAXXZ.catch"(i8*, i8*) { +; CHECK-LABEL: define internal i8* @"\01?test@@YAXXZ.catch"(i8*, i8*) ; CHECK: entry: ; CHECK: [[RECOVER_E:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 0) ; CHECK: [[E_PTR1:\%.+]] = bitcast i8* [[RECOVER_E]] to i32* diff --git a/test/CodeGen/WinEH/cppeh-inalloca.ll b/test/CodeGen/WinEH/cppeh-inalloca.ll index f3f36318eb0..f6908feedc2 100644 --- a/test/CodeGen/WinEH/cppeh-inalloca.ll +++ b/test/CodeGen/WinEH/cppeh-inalloca.ll @@ -36,7 +36,7 @@ $"\01??_R0H@8" = comdat any @"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat ; The function entry should be rewritten like this. -; CHECK: define i32 @"\01?test@@YAHUA@@@Z"(<{ %struct.A }>* inalloca) #0 { +; CHECK: define i32 @"\01?test@@YAHUA@@@Z"(<{ %struct.A }>* inalloca) ; CHECK: entry: ; CHECK: [[TMP_REGMEM:\%.+]] = alloca <{ %struct.A }>* ; CHECK: [[TMP:\%.+]] = select i1 true, <{ %struct.A }>* %0, <{ %struct.A }>* undef @@ -142,7 +142,7 @@ eh.resume: ; preds = %ehcleanup } ; The following catch handler should be outlined. -; CHECK: define internal i8* @"\01?test@@YAHUA@@@Z.catch"(i8*, i8*) { +; CHECK: define internal i8* @"\01?test@@YAHUA@@@Z.catch"(i8*, i8*) ; CHECK: entry: ; CHECK: [[RECOVER_E:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (i32 (<{ %struct.A }>*)* @"\01?test@@YAHUA@@@Z" to i8*), i8* %1, i32 0) ; CHECK: [[E_PTR:\%.+]] = bitcast i8* [[RECOVER_E]] to i32* @@ -165,7 +165,7 @@ eh.resume: ; preds = %ehcleanup ; CHECK: } ; The following cleanup handler should be outlined. -; CHECK: define internal void @"\01?test@@YAHUA@@@Z.cleanup"(i8*, i8*) { +; CHECK: define internal void @"\01?test@@YAHUA@@@Z.cleanup"(i8*, i8*) ; CHECK: entry: ; CHECK: [[RECOVER_EH_TEMP1:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (i32 (<{ %struct.A }>*)* @"\01?test@@YAHUA@@@Z" to i8*), i8* %1, i32 1) ; CHECK: [[EH_TEMP1:\%.+]] = bitcast i8* [[RECOVER_EH_TEMP]] to <{ %struct.A }>** diff --git a/test/CodeGen/WinEH/cppeh-min-unwind.ll b/test/CodeGen/WinEH/cppeh-min-unwind.ll index a1e97d5c3a2..3ef5d47f17c 100644 --- a/test/CodeGen/WinEH/cppeh-min-unwind.ll +++ b/test/CodeGen/WinEH/cppeh-min-unwind.ll @@ -21,7 +21,7 @@ target triple = "x86_64-pc-windows-msvc" %class.SomeClass = type { [28 x i32] } ; The function entry should be rewritten like this. -; CHECK: define void @_Z4testv() #0 { +; CHECK: define void @_Z4testv() ; CHECK: entry: ; CHECK: [[OBJ_PTR:\%.+]] = alloca %class.SomeClass, align 4 ; CHECK: call void @_ZN9SomeClassC1Ev(%class.SomeClass* [[OBJ_PTR]]) @@ -72,7 +72,7 @@ eh.resume: ; preds = %lpad } ; This cleanup handler should be outlined. -; CHECK: define internal void @_Z4testv.cleanup(i8*, i8*) { +; CHECK: define internal void @_Z4testv.cleanup(i8*, i8*) ; CHECK: entry: ; CHECK: [[RECOVER_OBJ:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @_Z4testv to i8*), i8* %1, i32 0) ; CHECK: [[OBJ_PTR1:\%.+]] = bitcast i8* [[RECOVER_OBJ]] to %class.SomeClass* diff --git a/test/CodeGen/WinEH/cppeh-nested-1.ll b/test/CodeGen/WinEH/cppeh-nested-1.ll index e94e77167fd..48c68187b94 100644 --- a/test/CodeGen/WinEH/cppeh-nested-1.ll +++ b/test/CodeGen/WinEH/cppeh-nested-1.ll @@ -31,7 +31,7 @@ $"\01??_R0H@8" = comdat any @"\01??_R0M@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".M\00" }, comdat @"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat -; CHECK: define void @"\01?test@@YAXXZ"() #0 { +; CHECK: define void @"\01?test@@YAXXZ"() ; CHECK: entry: ; CHECK: %i = alloca i32, align 4 ; CHECK: %f = alloca float, align 4 @@ -135,7 +135,7 @@ eh.resume: ; %catch.dispatch3 ; CHECK: } } -; CHECK: define internal i8* @"\01?test@@YAXXZ.catch"(i8*, i8*) { +; 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* @@ -158,7 +158,7 @@ eh.resume: ; %catch.dispatch3 ; ; CHECK: } -; CHECK: define internal i8* @"\01?test@@YAXXZ.catch1"(i8*, i8*) { +; 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* diff --git a/test/CodeGen/WinEH/cppeh-nested-2.ll b/test/CodeGen/WinEH/cppeh-nested-2.ll index 3479c41025f..6d5416d304b 100644 --- a/test/CodeGen/WinEH/cppeh-nested-2.ll +++ b/test/CodeGen/WinEH/cppeh-nested-2.ll @@ -38,7 +38,7 @@ target triple = "x86_64-pc-windows-msvc" @_ZTIi = external constant i8* ; The function entry should be rewritten like this. -; CHECK: define void @_Z4testv() #0 { +; CHECK: define void @_Z4testv() ; CHECK: entry: ; CHECK: %outer = alloca %class.Outer, align 1 ; CHECK: %inner = alloca %class.Inner, align 1 @@ -241,7 +241,7 @@ eh.resume: ; preds = %catch.dispatch11 } ; This catch handler should be outlined. -; CHECK: define internal i8* @_Z4testv.catch(i8*, i8*) { +; CHECK: define internal i8* @_Z4testv.catch(i8*, i8*) ; CHECK: entry: ; CHECK: [[RECOVER_F:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @_Z4testv to i8*), i8* %1, i32 0) ; CHECK: [[F_PTR:\%.+]] = bitcast i8* [[RECOVER_F]] to float* @@ -251,7 +251,7 @@ eh.resume: ; preds = %catch.dispatch11 ; CHECK: } ; This catch handler should be outlined. -; CHECK: define internal i8* @_Z4testv.catch1(i8*, i8*) { +; CHECK: define internal i8* @_Z4testv.catch1(i8*, i8*) ; CHECK: entry: ; CHECK: [[RECOVER_I:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @_Z4testv to i8*), i8* %1, i32 1) ; CHECK: [[I_PTR:\%.+]] = bitcast i8* [[RECOVER_I]] to i32* @@ -268,7 +268,7 @@ eh.resume: ; preds = %catch.dispatch11 ; CHECK: } ; This cleanup handler should be outlined. -; CHECK: define internal void @_Z4testv.cleanup(i8*, i8*) { +; CHECK: define internal void @_Z4testv.cleanup(i8*, i8*) ; CHECK: entry: ; CHECK: [[RECOVER_OUTER:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @_Z4testv to i8*), i8* %1, i32 2) ; CHECK: [[OUTER_PTR:\%.+]] = bitcast i8* [[RECOVER_OUTER]] to %class.Outer* @@ -277,7 +277,7 @@ eh.resume: ; preds = %catch.dispatch11 ; CHECK: } ; This cleanup handler should be outlined. -; CHECK: define internal void @_Z4testv.cleanup2(i8*, i8*) { +; CHECK: define internal void @_Z4testv.cleanup2(i8*, i8*) ; CHECK: entry: ; CHECK: [[RECOVER_INNER:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @_Z4testv to i8*), i8* %1, i32 3) ; CHECK: [[INNER_PTR:\%.+]] = bitcast i8* [[RECOVER_INNER]] to %class.Inner* diff --git a/test/CodeGen/WinEH/cppeh-nested-3.ll b/test/CodeGen/WinEH/cppeh-nested-3.ll index d28fa4d5f5c..867b8d6e98d 100644 --- a/test/CodeGen/WinEH/cppeh-nested-3.ll +++ b/test/CodeGen/WinEH/cppeh-nested-3.ll @@ -37,7 +37,7 @@ $"\01??_R0H@8" = comdat any @"\01??_R0M@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".M\00" }, comdat @"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat -; CHECK: define void @"\01?test@@YAXXZ"() #0 { +; CHECK: define void @"\01?test@@YAXXZ"() ; CHECK: entry: ; CHECK: %i = alloca i32, align 4 ; ------------================= FAIL here =================------------ @@ -182,7 +182,7 @@ eh.resume: ; preds = %lpad16, %catch.disp ; CHECK: } } -; CHECK: define internal i8* @"\01?test@@YAXXZ.catch"(i8*, i8*) { +; 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* @@ -220,7 +220,7 @@ eh.resume: ; preds = %lpad16, %catch.disp ; ; CHECK: } -; CHECK: define internal i8* @"\01?test@@YAXXZ.catch1"(i8*, i8*) { +; 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* @@ -229,7 +229,7 @@ eh.resume: ; preds = %lpad16, %catch.disp ; CHECK: ret i8* blockaddress(@"\01?test@@YAXXZ", %try.cont19) ; CHECK: } -; CHECK: define internal i8* @"\01?test@@YAXXZ.catch2"(i8*, i8*) { +; 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) diff --git a/test/CodeGen/WinEH/cppeh-nonalloca-frame-values.ll b/test/CodeGen/WinEH/cppeh-nonalloca-frame-values.ll index 41d9006551d..68bb13404ec 100644 --- a/test/CodeGen/WinEH/cppeh-nonalloca-frame-values.ll +++ b/test/CodeGen/WinEH/cppeh-nonalloca-frame-values.ll @@ -51,7 +51,7 @@ $"\01??_R0H@8" = comdat any @"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat ; The function entry should be rewritten like this. -; CHECK: define void @"\01?test@@YAXXZ"() #0 { +; CHECK: define void @"\01?test@@YAXXZ"() ; CHECK: entry: ; CHECK: [[NUMEXCEPTIONS_REGMEM:\%.+]] = alloca i32 ; CHECK: [[I_REGMEM:\%.+]] = alloca i32 @@ -190,7 +190,7 @@ eh.resume: ; preds = %lpad } ; The following catch handler should be outlined. -; CHECK: define internal i8* @"\01?test@@YAXXZ.catch"(i8*, i8*) { +; CHECK: define internal i8* @"\01?test@@YAXXZ.catch"(i8*, i8*) ; CHECK: entry: ; CHECK: [[RECOVER_E:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 0) ; CHECK: [[E_PTR:\%.+]] = bitcast i8* [[RECOVER_E]] to i32*