1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 18:54:02 +01:00

[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.

llvm-svn: 233636
This commit is contained in:
David Majnemer 2015-03-30 22:58:10 +00:00
parent 33cfd96d53
commit 6b3129357f
26 changed files with 863 additions and 129 deletions

View File

@ -58,6 +58,7 @@ class MachineFunction;
class Module;
class PointerType;
class StructType;
struct WinEHFuncInfo;
//===----------------------------------------------------------------------===//
/// LandingPadInfo - This structure is used to retain landing pad info for
@ -65,15 +66,17 @@ class StructType;
///
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.
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)
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;

View File

@ -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

View File

@ -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) {}

View File

@ -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,

View File

@ -188,6 +188,23 @@ bool EHStreamer::callToNoUnwindFunction(const MachineInstr *MI) {
return MarkedNoUnwind;
}
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.
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) {
MCSymbol *BeginLabel = LandingPad->BeginLabels[j];
assert(!PadMap.count(BeginLabel) && "Duplicate landing pad labels!");
PadRange P = { i, j };
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
@ -198,19 +215,8 @@ void EHStreamer::
computeCallSiteTable(SmallVectorImpl<CallSiteEntry> &CallSites,
const SmallVectorImpl<const LandingPadInfo *> &LandingPads,
const SmallVectorImpl<unsigned> &FirstActions) {
// 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) {
MCSymbol *BeginLabel = LandingPad->BeginLabels[j];
assert(!PadMap.count(BeginLabel) && "Duplicate landing pad labels!");
PadRange P = { i, j };
PadMap[BeginLabel] = P;
}
}
computePadMap(LandingPads, PadMap);
// The end label of the previous invoke or nounwind try-range.
MCSymbol *LastLabel = nullptr;

View File

@ -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);

View File

@ -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
}
}
}

View File

@ -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:
//===--------------------------------------------------------------------===//

View File

@ -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;
}

View File

@ -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());

View File

@ -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());

View File

@ -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

View File

@ -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;
}
}

View File

@ -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())

View File

@ -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");

View File

@ -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)

View File

@ -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*

View File

@ -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]]

View File

@ -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 }

View File

@ -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*

View File

@ -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 }>**

View File

@ -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*

View File

@ -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*

View File

@ -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*

View File

@ -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)

View File

@ -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*