diff options
Diffstat (limited to 'llvm')
26 files changed, 862 insertions, 128 deletions
diff --git a/llvm/include/llvm/CodeGen/MachineModuleInfo.h b/llvm/include/llvm/CodeGen/MachineModuleInfo.h index f171df20e76..ce1943bff57 100644 --- a/llvm/include/llvm/CodeGen/MachineModuleInfo.h +++ b/llvm/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<MCSymbol*, 1> BeginLabels; // Labels prior to invoke. - SmallVector<MCSymbol*, 1> EndLabels; // Labels after invoke. - SmallVector<MCSymbol*, 1> ClauseLabels; // Labels for each clause. - MCSymbol *LandingPadLabel; // Label at beginning of landing pad. - const Function *Personality; // Personality function. - std::vector<int> TypeIds; // List of type ids (filters negative) + MachineBasicBlock *LandingPadBlock; // Landing pad block. + SmallVector<MCSymbol *, 1> BeginLabels; // Labels prior to invoke. + SmallVector<MCSymbol *, 1> EndLabels; // Labels after invoke. + SmallVector<MCSymbol *, 1> ClauseLabels; // Labels for each clause. + MCSymbol *LandingPadLabel; // Label at beginning of landing pad. + const Function *Personality; // Personality function. + std::vector<int> 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<const Function *, std::unique_ptr<WinEHFuncInfo>> 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/llvm/include/llvm/CodeGen/WinEHFuncInfo.h b/llvm/include/llvm/CodeGen/WinEHFuncInfo.h new file mode 100644 index 00000000000..807afe6f8ae --- /dev/null +++ b/llvm/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<BasicBlock *> &getReturnTargets() { return ReturnTargets; } + + void setExceptionVar(const Value *Val) { ExceptionObjectVar = Val; } + void setReturnTargets(TinyPtrVector<BasicBlock *> &Targets) { + ReturnTargets = Targets; + } + +private: + Constant *Selector; + BasicBlock *NextBB; + const Value *ExceptionObjectVar; + TinyPtrVector<BasicBlock *> 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<WinEHHandlerType, 4> HandlerArray; +}; + +struct WinEHFuncInfo { + DenseMap<const LandingPadInst *, int> LandingPadStateMap; + DenseMap<const Function *, int> CatchHandlerParentFrameObjIdx; + DenseMap<const Function *, int> CatchHandlerParentFrameObjOffset; + SmallVector<WinEHUnwindMapEntry, 4> UnwindMap; + SmallVector<WinEHTryBlockMapEntry, 4> TryBlockMap; + SmallVector<std::pair<MCSymbol *, int>, 4> IPToStateList; + int UnwindHelpFrameIdx; + int UnwindHelpFrameOffset; + + WinEHFuncInfo() : UnwindHelpFrameIdx(INT_MAX), UnwindHelpFrameOffset(-1) {} +}; + +} +#endif // LLVM_CODEGEN_WINEHFUNCINFO_H diff --git a/llvm/include/llvm/IR/CallSite.h b/llvm/include/llvm/IR/CallSite.h index 9c87936dd21..b2f545ac2a1 100644 --- a/llvm/include/llvm/IR/CallSite.h +++ b/llvm/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/llvm/lib/Analysis/TargetLibraryInfo.cpp b/llvm/lib/Analysis/TargetLibraryInfo.cpp index 7e574d55c83..8b378a340fd 100644 --- a/llvm/lib/Analysis/TargetLibraryInfo.cpp +++ b/llvm/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/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp b/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp index 14df4c91625..6f64d8f790a 100644 --- a/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp +++ b/llvm/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<CallSiteEntry> &CallSites, - const SmallVectorImpl<const LandingPadInfo *> &LandingPads, - const SmallVectorImpl<unsigned> &FirstActions) { +void EHStreamer::computePadMap( + const SmallVectorImpl<const LandingPadInfo *> &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<CallSiteEntry> &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<CallSiteEntry> &CallSites, + const SmallVectorImpl<const LandingPadInfo *> &LandingPads, + const SmallVectorImpl<unsigned> &FirstActions) { + RangeMapType PadMap; + computePadMap(LandingPads, PadMap); // The end label of the previous invoke or nounwind try-range. MCSymbol *LastLabel = nullptr; diff --git a/llvm/lib/CodeGen/AsmPrinter/EHStreamer.h b/llvm/lib/CodeGen/AsmPrinter/EHStreamer.h index 94d0585347e..aa42373b488 100644 --- a/llvm/lib/CodeGen/AsmPrinter/EHStreamer.h +++ b/llvm/lib/CodeGen/AsmPrinter/EHStreamer.h @@ -80,13 +80,15 @@ protected: /// `false' otherwise. bool callToNoUnwindFunction(const MachineInstr *MI); + void computePadMap(const SmallVectorImpl<const LandingPadInfo *> &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<CallSiteEntry> &CallSites, const SmallVectorImpl<const LandingPadInfo *> &LPs, const SmallVectorImpl<unsigned> &FirstActions); diff --git a/llvm/lib/CodeGen/AsmPrinter/Win64Exception.cpp b/llvm/lib/CodeGen/AsmPrinter/Win64Exception.cpp index 7d76eaddb56..974e94dcb6a 100644 --- a/llvm/lib/CodeGen/AsmPrinter/Win64Exception.cpp +++ b/llvm/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<const LandingPadInfo *, 64> LandingPads; + const std::vector<LandingPadInfo> &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<MCSymbol *, 1> 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/llvm/lib/CodeGen/AsmPrinter/Win64Exception.h b/llvm/lib/CodeGen/AsmPrinter/Win64Exception.h index b2d5d1bce56..eb02ca47b39 100644 --- a/llvm/lib/CodeGen/AsmPrinter/Win64Exception.h +++ b/llvm/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/llvm/lib/CodeGen/MachineModuleInfo.cpp b/llvm/lib/CodeGen/MachineModuleInfo.cpp index fca7df097b6..d5491213293 100644 --- a/llvm/lib/CodeGen/MachineModuleInfo.cpp +++ b/llvm/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/llvm/lib/CodeGen/PrologEpilogInserter.cpp b/llvm/lib/CodeGen/PrologEpilogInserter.cpp index e073e6a8437..5334a633ead 100644 --- a/llvm/lib/CodeGen/PrologEpilogInserter.cpp +++ b/llvm/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<int, 8> SPState; SPState.resize(Fn.getNumBlockIDs()); diff --git a/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp b/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp index 223a149924b..73061b6dc3e 100644 --- a/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp +++ b/llvm/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<DbgDeclareInst>(II); DIVariable DIVar(DI->getVariable()); diff --git a/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp b/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp index 80bf9755ec8..77b31fc0566 100644 --- a/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp +++ b/llvm/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<ActionHandler *, 4> HandlerStack; + + int currentEHNumber() const { + return HandlerStack.empty() ? -1 : HandlerStack.back()->getEHState(); + } + + void parseEHActions(const IntrinsicInst *II, + SmallVectorImpl<ActionHandler *> &Actions); + void createUnwindMapEntry(int ToState, ActionHandler *AH); + void proccessCallSite(ArrayRef<ActionHandler *> 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<ISD::OutputArg, 4> 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<DbgDeclareInst>(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<InvokeInst>(BB->getTerminator())) + if (const auto *Invoke = dyn_cast<InvokeInst>(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<ActionHandler *> &Actions) { + for (unsigned I = 0, E = II->getNumArgOperands(); I != E;) { + uint64_t ActionKind = + cast<ConstantInt>(II->getArgOperand(I))->getZExtValue(); + if (ActionKind == /*catch=*/1) { + auto *Selector = cast<Constant>(II->getArgOperand(I + 1)); + Value *CatchObject = II->getArgOperand(I + 2); + Constant *Handler = cast<Constant>(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<Constant>(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<CleanupHandler>(AH)) + UME.Cleanup = cast<Function>(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<Function>(V)) + DEBUG(dbgs() << F->getName()); + else + DEBUG(V->dump()); +} + +void WinEHNumbering::proccessCallSite(ArrayRef<ActionHandler *> 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<const Function *, 4> UnnumberedHandlers; + for (int I = HandlerStack.size() - 1; I >= FirstMismatch; --I) { + if (auto *CH = dyn_cast<CatchHandler>(HandlerStack.back())) + if (const auto *F = dyn_cast<Function>(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<ActionHandler *, 4> ActionList; + for (const BasicBlock &BB : F) { + for (const Instruction &I : BB) { + const auto *CI = dyn_cast<CallInst>(&I); + if (!CI || CI->doesNotThrow()) + continue; + proccessCallSite(None, CI); + } + const auto *II = dyn_cast<InvokeInst>(BB.getTerminator()); + if (!II) + continue; + const LandingPadInst *LPI = II->getLandingPadInst(); + if (auto *ActionsCall = dyn_cast<IntrinsicInst>(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/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index 37f945f138a..fd9d7e6b69a 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/llvm/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/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp index 17950058bb2..3de9c26a905 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/llvm/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/llvm/lib/CodeGen/WinEHPrepare.cpp b/llvm/lib/CodeGen/WinEHPrepare.cpp index e35b94f1d36..94e046c424d 100644 --- a/llvm/lib/CodeGen/WinEHPrepare.cpp +++ b/llvm/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<Value *, TinyPtrVector<AllocaInst *>> FrameVarInfoMap; typedef SmallSet<BasicBlock *, 4> VisitedBlockSet; -enum ActionType { Catch, Cleanup }; - class LandingPadActions; -class ActionHandler; -class CatchHandler; -class CleanupHandler; class LandingPadMap; typedef DenseMap<const BasicBlock *, CatchHandler *> 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<BasicBlock *> &getReturnTargets() { return ReturnTargets; } - - void setExceptionVar(const Value *Val) { ExceptionObjectVar = Val; } - void setReturnTargets(TinyPtrVector<BasicBlock *> &Targets) { - ReturnTargets = Targets; - } - -private: - Constant *Selector; - BasicBlock *NextBB; - const Value *ExceptionObjectVar; - TinyPtrVector<BasicBlock *> 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<ActionHandler *> &actions() { return Actions; } SmallVectorImpl<ActionHandler *>::iterator begin() { return Actions.begin(); } SmallVectorImpl<ActionHandler *>::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<PHINode>(LPadBB->begin())); - Instruction *NewLPad = LPad->clone(); + auto *NewLPad = cast<LandingPadInst>(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/llvm/test/CodeGen/WinEH/cppeh-catch-all.ll b/llvm/test/CodeGen/WinEH/cppeh-catch-all.ll index 6e69862ce9f..5a51fe6ba45 100644 --- a/llvm/test/CodeGen/WinEH/cppeh-catch-all.ll +++ b/llvm/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/llvm/test/CodeGen/WinEH/cppeh-catch-scalar.ll b/llvm/test/CodeGen/WinEH/cppeh-catch-scalar.ll index 0f8a7a8e063..adb048a982b 100644 --- a/llvm/test/CodeGen/WinEH/cppeh-catch-scalar.ll +++ b/llvm/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/llvm/test/CodeGen/WinEH/cppeh-catch-unwind.ll b/llvm/test/CodeGen/WinEH/cppeh-catch-unwind.ll index a9849d9cb1c..60a5256a133 100644 --- a/llvm/test/CodeGen/WinEH/cppeh-catch-unwind.ll +++ b/llvm/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/llvm/test/CodeGen/WinEH/cppeh-cleanups.ll b/llvm/test/CodeGen/WinEH/cppeh-cleanups.ll new file mode 100644 index 00000000000..64d9980be39 --- /dev/null +++ b/llvm/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/llvm/test/CodeGen/WinEH/cppeh-frame-vars.ll b/llvm/test/CodeGen/WinEH/cppeh-frame-vars.ll index dc5ed1cc0e2..cb97e6e5638 100644 --- a/llvm/test/CodeGen/WinEH/cppeh-frame-vars.ll +++ b/llvm/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/llvm/test/CodeGen/WinEH/cppeh-inalloca.ll b/llvm/test/CodeGen/WinEH/cppeh-inalloca.ll index f3f36318eb0..f6908feedc2 100644 --- a/llvm/test/CodeGen/WinEH/cppeh-inalloca.ll +++ b/llvm/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/llvm/test/CodeGen/WinEH/cppeh-min-unwind.ll b/llvm/test/CodeGen/WinEH/cppeh-min-unwind.ll index a1e97d5c3a2..3ef5d47f17c 100644 --- a/llvm/test/CodeGen/WinEH/cppeh-min-unwind.ll +++ b/llvm/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/llvm/test/CodeGen/WinEH/cppeh-nested-1.ll b/llvm/test/CodeGen/WinEH/cppeh-nested-1.ll index e94e77167fd..48c68187b94 100644 --- a/llvm/test/CodeGen/WinEH/cppeh-nested-1.ll +++ b/llvm/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/llvm/test/CodeGen/WinEH/cppeh-nested-2.ll b/llvm/test/CodeGen/WinEH/cppeh-nested-2.ll index 3479c41025f..6d5416d304b 100644 --- a/llvm/test/CodeGen/WinEH/cppeh-nested-2.ll +++ b/llvm/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/llvm/test/CodeGen/WinEH/cppeh-nested-3.ll b/llvm/test/CodeGen/WinEH/cppeh-nested-3.ll index d28fa4d5f5c..867b8d6e98d 100644 --- a/llvm/test/CodeGen/WinEH/cppeh-nested-3.ll +++ b/llvm/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/llvm/test/CodeGen/WinEH/cppeh-nonalloca-frame-values.ll b/llvm/test/CodeGen/WinEH/cppeh-nonalloca-frame-values.ll index 41d9006551d..68bb13404ec 100644 --- a/llvm/test/CodeGen/WinEH/cppeh-nonalloca-frame-values.ll +++ b/llvm/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* |