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:
parent
33cfd96d53
commit
6b3129357f
@ -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;
|
||||
|
131
include/llvm/CodeGen/WinEHFuncInfo.h
Normal file
131
include/llvm/CodeGen/WinEHFuncInfo.h
Normal 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
|
@ -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) {}
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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:
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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());
|
||||
|
@ -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());
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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())
|
||||
|
@ -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");
|
||||
|
@ -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)
|
||||
|
@ -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*
|
||||
|
@ -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]]
|
||||
|
226
test/CodeGen/WinEH/cppeh-cleanups.ll
Normal file
226
test/CodeGen/WinEH/cppeh-cleanups.ll
Normal 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 }
|
@ -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*
|
||||
|
@ -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 }>**
|
||||
|
@ -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*
|
||||
|
@ -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*
|
||||
|
@ -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*
|
||||
|
@ -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)
|
||||
|
@ -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*
|
||||
|
Loading…
Reference in New Issue
Block a user