//===----------------------------------------------------------------------===//
//
// This pass lowers LLVM IR exception handling into something closer to what the
-// backend wants. It snifs the personality function to see which kind of
-// preparation is necessary. If the personality function uses the Itanium LSDA,
-// this pass delegates to the DWARF EH preparation pass.
+// backend wants for functions using a personality function from a runtime
+// provided by MSVC. Functions with other personality functions are left alone
+// and may be prepared by other passes. In particular, all supported MSVC
+// personality functions require cleanup code to be outlined, and the C++
+// personality requires catch handler code to be outlined.
//
//===----------------------------------------------------------------------===//
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SetVector.h"
+#include "llvm/ADT/Triple.h"
#include "llvm/ADT/TinyPtrVector.h"
#include "llvm/Analysis/LibCallSemantics.h"
#include "llvm/CodeGen/WinEHFuncInfo.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/PatternMatch.h"
#include "llvm/Pass.h"
-#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
public:
static char ID; // Pass identification, replacement for typeid.
WinEHPrepare(const TargetMachine *TM = nullptr)
- : FunctionPass(ID), DT(nullptr) {}
+ : FunctionPass(ID) {
+ if (TM)
+ TheTriple = Triple(TM->getTargetTriple());
+ }
bool runOnFunction(Function &Fn) override;
void promoteLandingPadValues(LandingPadInst *LPad);
void demoteValuesLiveAcrossHandlers(Function &F,
SmallVectorImpl<LandingPadInst *> &LPads);
+ void findSEHEHReturnPoints(Function &F,
+ SetVector<BasicBlock *> &EHReturnBlocks);
+ void findCXXEHReturnPoints(Function &F,
+ SetVector<BasicBlock *> &EHReturnBlocks);
+ void getPossibleReturnTargets(Function *ParentF, Function *HandlerF,
+ SetVector<BasicBlock*> &Targets);
void completeNestedLandingPad(Function *ParentFn,
LandingPadInst *OutlinedLPad,
const LandingPadInst *OriginalLPad,
FrameVarInfoMap &VarInfo);
+ Function *createHandlerFunc(Type *RetTy, const Twine &Name, Module *M,
+ Value *&ParentFP);
bool outlineHandler(ActionHandler *Action, Function *SrcFn,
LandingPadInst *LPad, BasicBlock *StartBB,
FrameVarInfoMap &VarInfo);
void processSEHCatchHandler(CatchHandler *Handler, BasicBlock *StartBB);
+ Triple TheTriple;
+
// All fields are reset by runOnFunction.
- DominatorTree *DT;
- EHPersonality Personality;
+ DominatorTree *DT = nullptr;
+ EHPersonality Personality = EHPersonality::Unknown;
CatchHandlerMapTy CatchHandlerMap;
CleanupHandlerMapTy CleanupHandlerMap;
DenseMap<const LandingPadInst *, LandingPadMap> LPadMaps;
// outlined into a handler. This is done after all handlers have been
// outlined but before the outlined code is pruned from the parent function.
DenseMap<const BasicBlock *, BasicBlock *> LPadTargetBlocks;
+
+ // Map from outlined handler to call to llvm.frameaddress(1). Only used for
+ // 32-bit EH.
+ DenseMap<Function *, Value *> HandlerToParentFP;
+
+ AllocaInst *SEHExceptionCodeSlot = nullptr;
};
class WinEHFrameVariableMaterializer : public ValueMaterializer {
public:
- WinEHFrameVariableMaterializer(Function *OutlinedFn,
+ WinEHFrameVariableMaterializer(Function *OutlinedFn, Value *ParentFP,
FrameVarInfoMap &FrameVarInfo);
~WinEHFrameVariableMaterializer() override {}
class WinEHCloningDirectorBase : public CloningDirector {
public:
- WinEHCloningDirectorBase(Function *HandlerFn, FrameVarInfoMap &VarInfo,
- LandingPadMap &LPadMap)
- : Materializer(HandlerFn, VarInfo),
+ WinEHCloningDirectorBase(Function *HandlerFn, Value *ParentFP,
+ FrameVarInfoMap &VarInfo, LandingPadMap &LPadMap)
+ : Materializer(HandlerFn, ParentFP, VarInfo),
SelectorIDType(Type::getInt32Ty(HandlerFn->getContext())),
Int8PtrType(Type::getInt8PtrTy(HandlerFn->getContext())),
- LPadMap(LPadMap) {
- auto AI = HandlerFn->getArgumentList().begin();
- ++AI;
- EstablisherFrame = AI;
- }
+ LPadMap(LPadMap), ParentFP(ParentFP) {}
CloningAction handleInstruction(ValueToValueMapTy &VMap,
const Instruction *Inst,
LandingPadMap &LPadMap;
/// The value representing the parent frame pointer.
- Value *EstablisherFrame;
+ Value *ParentFP;
};
class WinEHCatchDirector : public WinEHCloningDirectorBase {
public:
WinEHCatchDirector(
- Function *CatchFn, Value *Selector, FrameVarInfoMap &VarInfo,
- LandingPadMap &LPadMap,
+ Function *CatchFn, Value *ParentFP, Value *Selector,
+ FrameVarInfoMap &VarInfo, LandingPadMap &LPadMap,
DenseMap<LandingPadInst *, const LandingPadInst *> &NestedLPads)
- : WinEHCloningDirectorBase(CatchFn, VarInfo, LPadMap),
+ : WinEHCloningDirectorBase(CatchFn, ParentFP, VarInfo, LPadMap),
CurrentSelector(Selector->stripPointerCasts()),
ExceptionObjectVar(nullptr), NestedLPtoOriginalLP(NestedLPads) {}
BasicBlock *NewBB) override;
CloningAction handleResume(ValueToValueMapTy &VMap, const ResumeInst *Resume,
BasicBlock *NewBB) override;
- CloningAction handleCompare(ValueToValueMapTy &VMap,
- const CmpInst *Compare, BasicBlock *NewBB) override;
+ CloningAction handleCompare(ValueToValueMapTy &VMap, const CmpInst *Compare,
+ BasicBlock *NewBB) override;
CloningAction handleLandingPad(ValueToValueMapTy &VMap,
const LandingPadInst *LPad,
BasicBlock *NewBB) override;
class WinEHCleanupDirector : public WinEHCloningDirectorBase {
public:
- WinEHCleanupDirector(Function *CleanupFn, FrameVarInfoMap &VarInfo,
- LandingPadMap &LPadMap)
- : WinEHCloningDirectorBase(CleanupFn, VarInfo, LPadMap) {}
+ WinEHCleanupDirector(Function *CleanupFn, Value *ParentFP,
+ FrameVarInfoMap &VarInfo, LandingPadMap &LPadMap)
+ : WinEHCloningDirectorBase(CleanupFn, ParentFP, VarInfo,
+ LPadMap) {}
CloningAction handleBeginCatch(ValueToValueMapTy &VMap,
const Instruction *Inst,
BasicBlock *NewBB) override;
CloningAction handleResume(ValueToValueMapTy &VMap, const ResumeInst *Resume,
BasicBlock *NewBB) override;
- CloningAction handleCompare(ValueToValueMapTy &VMap,
- const CmpInst *Compare, BasicBlock *NewBB) override;
+ CloningAction handleCompare(ValueToValueMapTy &VMap, const CmpInst *Compare,
+ BasicBlock *NewBB) override;
CloningAction handleLandingPad(ValueToValueMapTy &VMap,
const LandingPadInst *LPad,
BasicBlock *NewBB) override;
return new WinEHPrepare(TM);
}
-// FIXME: Remove this once the backend can handle the prepared IR.
-static cl::opt<bool>
- SEHPrepare("sehprepare", cl::Hidden,
- cl::desc("Prepare functions with SEH personalities"));
-
bool WinEHPrepare::runOnFunction(Function &Fn) {
// No need to prepare outlined handlers.
if (Fn.hasFnAttribute("wineh-parent"))
DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
- if (isAsynchronousEHPersonality(Personality) && !SEHPrepare) {
- // Replace all resume instructions with unreachable.
- // FIXME: Remove this once the backend can handle the prepared IR.
- for (ResumeInst *Resume : Resumes) {
- IRBuilder<>(Resume).CreateUnreachable();
- Resume->eraseFromParent();
- }
- return true;
- }
-
// If there were any landing pads, prepareExceptionHandlers will make changes.
prepareExceptionHandlers(Fn, LPads);
return true;
}
}
+// Attempt to find an instruction where a block can be split before
+// a call to llvm.eh.begincatch and its operands. If the block
+// begins with the begincatch call or one of its adjacent operands
+// the block will not be split.
+static Instruction *findBeginCatchSplitPoint(BasicBlock *BB,
+ IntrinsicInst *II) {
+ // If the begincatch call is already the first instruction in the block,
+ // don't split.
+ Instruction *FirstNonPHI = BB->getFirstNonPHI();
+ if (II == FirstNonPHI)
+ return nullptr;
+
+ // If either operand is in the same basic block as the instruction and
+ // isn't used by another instruction before the begincatch call, include it
+ // in the split block.
+ auto *Op0 = dyn_cast<Instruction>(II->getOperand(0));
+ auto *Op1 = dyn_cast<Instruction>(II->getOperand(1));
+
+ Instruction *I = II->getPrevNode();
+ Instruction *LastI = II;
+
+ while (I == Op0 || I == Op1) {
+ // If the block begins with one of the operands and there are no other
+ // instructions between the operand and the begincatch call, don't split.
+ if (I == FirstNonPHI)
+ return nullptr;
+
+ LastI = I;
+ I = I->getPrevNode();
+ }
+
+ // If there is at least one instruction in the block before the begincatch
+ // call and its operands, split the block at either the begincatch or
+ // its operand.
+ return LastI;
+}
+
/// Find all points where exceptional control rejoins normal control flow via
/// llvm.eh.endcatch. Add them to the normal bb reachability worklist.
-static void findCXXEHReturnPoints(Function &F,
- SetVector<BasicBlock *> &EHReturnBlocks) {
+void WinEHPrepare::findCXXEHReturnPoints(
+ Function &F, SetVector<BasicBlock *> &EHReturnBlocks) {
for (auto BBI = F.begin(), BBE = F.end(); BBI != BBE; ++BBI) {
BasicBlock *BB = BBI;
for (Instruction &I : *BB) {
+ if (match(&I, m_Intrinsic<Intrinsic::eh_begincatch>())) {
+ Instruction *SplitPt =
+ findBeginCatchSplitPoint(BB, cast<IntrinsicInst>(&I));
+ if (SplitPt) {
+ // Split the block before the llvm.eh.begincatch call to allow
+ // cleanup and catch code to be distinguished later.
+ // Do not update BBI because we still need to process the
+ // portion of the block that we are splitting off.
+ SplitBlock(BB, SplitPt, DT);
+ break;
+ }
+ }
if (match(&I, m_Intrinsic<Intrinsic::eh_endcatch>())) {
// Split the block after the call to llvm.eh.endcatch if there is
// anything other than an unconditional branch, or if the successor
isa<PHINode>(Br->getSuccessor(0)->begin())) {
DEBUG(dbgs() << "splitting block " << BB->getName()
<< " with llvm.eh.endcatch\n");
- BBI = BB->splitBasicBlock(I.getNextNode(), "ehreturn");
+ BBI = SplitBlock(BB, I.getNextNode(), DT);
}
// The next BB is normal control flow.
EHReturnBlocks.insert(BB->getTerminator()->getSuccessor(0));
/// Find all points where exceptions control rejoins normal control flow via
/// selector dispatch.
-static void findSEHEHReturnPoints(Function &F,
- SetVector<BasicBlock *> &EHReturnBlocks) {
+void WinEHPrepare::findSEHEHReturnPoints(
+ Function &F, SetVector<BasicBlock *> &EHReturnBlocks) {
for (auto BBI = F.begin(), BBE = F.end(); BBI != BBE; ++BBI) {
BasicBlock *BB = BBI;
// If the landingpad is a catch-all, treat the whole lpad as if it is
dbgs() << " " << BB->getName() << '\n';
});
- // Join points should not have phis at this point, unless they are a
- // landingpad, in which case we will demote their phis later.
+// Join points should not have phis at this point, unless they are a
+// landingpad, in which case we will demote their phis later.
#ifndef NDEBUG
for (BasicBlock *BB : EHReturnBlocks)
assert((BB->isLandingPad() || !isa<PHINode>(BB->begin())) &&
Type *Int32Type = Type::getInt32Ty(Context);
Function *ActionIntrin = Intrinsic::getDeclaration(M, Intrinsic::eh_actions);
+ if (isAsynchronousEHPersonality(Personality)) {
+ // FIXME: Switch the ehptr type to i32 and then switch this.
+ SEHExceptionCodeSlot =
+ new AllocaInst(Int8PtrType, nullptr, "seh_exception_code",
+ F.getEntryBlock().getFirstInsertionPt());
+ }
+
+ // This container stores the llvm.eh.recover and IndirectBr instructions
+ // that make up the body of each landing pad after it has been outlined.
+ // We need to defer the population of the target list for the indirectbr
+ // until all landing pads have been outlined so that we can handle the
+ // case of blocks in the target that are reached only from nested
+ // landing pads.
+ SmallVector<std::pair<CallInst*, IndirectBrInst *>, 4> LPadImpls;
+
for (LandingPadInst *LPad : LPads) {
// Look for evidence that this landingpad has already been processed.
bool LPadHasActionList = false;
outlineHandler(Action, &F, LPad, StartBB, FrameVarInfo);
}
- // 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()));
- auto *NewLPad = cast<LandingPadInst>(LPad->clone());
- NewLPadBB->getInstList().push_back(NewLPad);
- while (!pred_empty(LPadBB)) {
- auto *pred = *pred_begin(LPadBB);
- InvokeInst *Invoke = cast<InvokeInst>(pred->getTerminator());
- Invoke->setUnwindDest(NewLPadBB);
- }
-
- // Replace the mapping of any nested landing pad that previously mapped
- // to this landing pad with a referenced to the cloned version.
- for (auto &LPadPair : NestedLPtoOriginalLP) {
- const LandingPadInst *OriginalLPad = LPadPair.second;
- if (OriginalLPad == LPad) {
- LPadPair.second = NewLPad;
- }
- }
+ // Split the block after the landingpad instruction so that it is just a
+ // call to llvm.eh.actions followed by indirectbr.
+ assert(!isa<PHINode>(LPadBB->begin()) && "lpad phi not removed");
+ SplitBlock(LPadBB, LPad->getNextNode(), DT);
+ // Erase the branch inserted by the split so we can insert indirectbr.
+ LPadBB->getTerminator()->eraseFromParent();
// Replace all extracted values with undef and ultimately replace the
// landingpad with undef.
- // FIXME: This doesn't handle SEH GetExceptionCode(). For now, we just give
- // out undef until we figure out the codegen support.
- SmallVector<Instruction *, 4> Extracts;
+ SmallVector<Instruction *, 4> SEHCodeUses;
+ SmallVector<Instruction *, 4> EHUndefs;
for (User *U : LPad->users()) {
auto *E = dyn_cast<ExtractValueInst>(U);
if (!E)
continue;
assert(E->getNumIndices() == 1 &&
"Unexpected operation: extracting both landing pad values");
- Extracts.push_back(E);
+ unsigned Idx = *E->idx_begin();
+ assert((Idx == 0 || Idx == 1) && "unexpected index");
+ if (Idx == 0 && isAsynchronousEHPersonality(Personality))
+ SEHCodeUses.push_back(E);
+ else
+ EHUndefs.push_back(E);
}
- for (Instruction *E : Extracts) {
+ for (Instruction *E : EHUndefs) {
E->replaceAllUsesWith(UndefValue::get(E->getType()));
E->eraseFromParent();
}
LPad->replaceAllUsesWith(UndefValue::get(LPad->getType()));
+ // Rewrite uses of the exception pointer to loads of an alloca.
+ for (Instruction *E : SEHCodeUses) {
+ SmallVector<Use *, 4> Uses;
+ for (Use &U : E->uses())
+ Uses.push_back(&U);
+ for (Use *U : Uses) {
+ auto *I = cast<Instruction>(U->getUser());
+ if (isa<ResumeInst>(I))
+ continue;
+ LoadInst *LI;
+ if (auto *Phi = dyn_cast<PHINode>(I))
+ LI = new LoadInst(SEHExceptionCodeSlot, "sehcode", false,
+ Phi->getIncomingBlock(*U));
+ else
+ LI = new LoadInst(SEHExceptionCodeSlot, "sehcode", false, I);
+ U->set(LI);
+ }
+ E->replaceAllUsesWith(UndefValue::get(E->getType()));
+ E->eraseFromParent();
+ }
+
// Add a call to describe the actions for this landing pad.
std::vector<Value *> ActionArgs;
for (ActionHandler *Action : Actions) {
ActionArgs.push_back(Action->getHandlerBlockOrFunc());
}
CallInst *Recover =
- CallInst::Create(ActionIntrin, ActionArgs, "recover", NewLPadBB);
+ CallInst::Create(ActionIntrin, ActionArgs, "recover", LPadBB);
- // Add an indirect branch listing possible successors of the catch handlers.
- SetVector<BasicBlock *> ReturnTargets;
- for (ActionHandler *Action : Actions) {
- if (auto *CatchAction = dyn_cast<CatchHandler>(Action)) {
- const auto &CatchTargets = CatchAction->getReturnTargets();
- ReturnTargets.insert(CatchTargets.begin(), CatchTargets.end());
+ if (isAsynchronousEHPersonality(Personality)) {
+ // SEH can create the target list directly, since catch handlers
+ // are not outlined.
+ SetVector<BasicBlock *> ReturnTargets;
+ for (ActionHandler *Action : Actions) {
+ if (auto *CatchAction = dyn_cast<CatchHandler>(Action)) {
+ const auto &CatchTargets = CatchAction->getReturnTargets();
+ ReturnTargets.insert(CatchTargets.begin(), CatchTargets.end());
+ }
}
+ IndirectBrInst *Branch =
+ IndirectBrInst::Create(Recover, ReturnTargets.size(), LPadBB);
+ for (BasicBlock *Target : ReturnTargets)
+ Branch->addDestination(Target);
+ } else {
+ // C++ EH must defer populating the targets to handle the case of
+ // targets that are reached indirectly through nested landing pads.
+ IndirectBrInst *Branch =
+ IndirectBrInst::Create(Recover, 0, LPadBB);
+
+ LPadImpls.push_back(std::make_pair(Recover, Branch));
}
- IndirectBrInst *Branch =
- IndirectBrInst::Create(Recover, ReturnTargets.size(), NewLPadBB);
- for (BasicBlock *Target : ReturnTargets)
- Branch->addDestination(Target);
} // End for each landingpad
// If nothing got outlined, there is no more processing to be done.
completeNestedLandingPad(&F, LPadPair.first, LPadPair.second, FrameVarInfo);
NestedLPtoOriginalLP.clear();
+ // Populate the indirectbr instructions' target lists if we deferred
+ // doing so above.
+ SetVector<BasicBlock*> CheckedTargets;
+ for (auto &LPadImplPair : LPadImpls) {
+ IntrinsicInst *Recover = cast<IntrinsicInst>(LPadImplPair.first);
+ IndirectBrInst *Branch = LPadImplPair.second;
+
+ // Get a list of handlers called by
+ SmallVector<ActionHandler *, 4> ActionList;
+ parseEHActions(Recover, ActionList);
+
+ // Add an indirect branch listing possible successors of the catch handlers.
+ SetVector<BasicBlock *> ReturnTargets;
+ for (ActionHandler *Action : ActionList) {
+ if (auto *CA = dyn_cast<CatchHandler>(Action)) {
+ Function *Handler = cast<Function>(CA->getHandlerBlockOrFunc());
+ getPossibleReturnTargets(&F, Handler, ReturnTargets);
+ }
+ delete Action;
+ }
+ ActionList.clear();
+ for (BasicBlock *Target : ReturnTargets) {
+ Branch->addDestination(Target);
+ // The target may be a block that we excepted to get pruned.
+ // If it is, it may contain a call to llvm.eh.endcatch.
+ if (CheckedTargets.insert(Target)) {
+ // Earlier preparations guarantee that all calls to llvm.eh.endcatch
+ // will be followed by an unconditional branch.
+ auto *Br = dyn_cast<BranchInst>(Target->getTerminator());
+ if (Br && Br->isUnconditional() &&
+ Br != Target->getFirstNonPHIOrDbgOrLifetime()) {
+ Instruction *Prev = Br->getPrevNode();
+ if (match(cast<Value>(Prev), m_Intrinsic<Intrinsic::eh_endcatch>()))
+ Prev->eraseFromParent();
+ }
+ }
+ }
+ }
+ LPadImpls.clear();
+
F.addFnAttr("wineh-parent", F.getName());
// Delete any blocks that were only used by handlers that were outlined above.
if (TempAlloca == getCatchObjectSentinel())
continue; // Skip catch parameter sentinels.
Function *HandlerFn = TempAlloca->getParent()->getParent();
- // FIXME: Sink this GEP into the blocks where it is used.
+ llvm::Value *FP = HandlerToParentFP[HandlerFn];
+ assert(FP);
+
+ // FIXME: Sink this framerecover into the blocks where it is used.
Builder.SetInsertPoint(TempAlloca);
Builder.SetCurrentDebugLocation(TempAlloca->getDebugLoc());
Value *RecoverArgs[] = {
- Builder.CreateBitCast(&F, Int8PtrType, ""),
- &(HandlerFn->getArgumentList().back()),
+ Builder.CreateBitCast(&F, Int8PtrType, ""), FP,
llvm::ConstantInt::get(Int32Type, AllocasToEscape.size() - 1)};
- Value *RecoveredAlloca = Builder.CreateCall(RecoverFrameFn, RecoverArgs);
+ Instruction *RecoveredAlloca =
+ Builder.CreateCall(RecoverFrameFn, RecoverArgs);
+
// Add a pointer bitcast if the alloca wasn't an i8.
if (RecoveredAlloca->getType() != TempAlloca->getType()) {
RecoveredAlloca->setName(Twine(TempAlloca->getName()) + ".i8");
- RecoveredAlloca =
- Builder.CreateBitCast(RecoveredAlloca, TempAlloca->getType());
+ RecoveredAlloca = cast<Instruction>(
+ Builder.CreateBitCast(RecoveredAlloca, TempAlloca->getType()));
}
TempAlloca->replaceAllUsesWith(RecoveredAlloca);
TempAlloca->removeFromParent();
Builder.SetInsertPoint(&F.getEntryBlock().back());
Builder.CreateCall(FrameEscapeFn, AllocasToEscape);
+ if (SEHExceptionCodeSlot) {
+ if (SEHExceptionCodeSlot->hasNUses(0))
+ SEHExceptionCodeSlot->eraseFromParent();
+ else if (isAllocaPromotable(SEHExceptionCodeSlot))
+ PromoteMemToReg(SEHExceptionCodeSlot, *DT);
+ }
+
// Clean up the handler action maps we created for this function
DeleteContainerSeconds(CatchHandlerMap);
CatchHandlerMap.clear();
DeleteContainerSeconds(CleanupHandlerMap);
CleanupHandlerMap.clear();
+ HandlerToParentFP.clear();
+ DT = nullptr;
+ SEHExceptionCodeSlot = nullptr;
return HandlersOutlined;
}
RecursivelyDeleteTriviallyDeadInstructions(U);
}
+void WinEHPrepare::getPossibleReturnTargets(Function *ParentF,
+ Function *HandlerF,
+ SetVector<BasicBlock*> &Targets) {
+ for (BasicBlock &BB : *HandlerF) {
+ // If the handler contains landing pads, check for any
+ // handlers that may return directly to a block in the
+ // parent function.
+ if (auto *LPI = BB.getLandingPadInst()) {
+ IntrinsicInst *Recover = cast<IntrinsicInst>(LPI->getNextNode());
+ SmallVector<ActionHandler *, 4> ActionList;
+ parseEHActions(Recover, ActionList);
+ for (auto *Action : ActionList) {
+ if (auto *CH = dyn_cast<CatchHandler>(Action)) {
+ Function *NestedF = cast<Function>(CH->getHandlerBlockOrFunc());
+ getPossibleReturnTargets(ParentF, NestedF, Targets);
+ }
+ }
+ }
+
+ auto *Ret = dyn_cast<ReturnInst>(BB.getTerminator());
+ if (!Ret)
+ continue;
+
+ // Handler functions must always return a block address.
+ BlockAddress *BA = cast<BlockAddress>(Ret->getReturnValue());
+
+ // If this is the handler for a nested landing pad, the
+ // return address may have been remapped to a block in the
+ // parent handler. We're not interested in those.
+ if (BA->getFunction() != ParentF)
+ continue;
+
+ Targets.insert(BA->getBasicBlock());
+ }
+}
+
void WinEHPrepare::completeNestedLandingPad(Function *ParentFn,
LandingPadInst *OutlinedLPad,
const LandingPadInst *OriginalLPad,
IntrinsicInst *EHActions = cast<IntrinsicInst>(Recover->clone());
// Remap the exception variables into the outlined function.
- WinEHFrameVariableMaterializer Materializer(OutlinedHandlerFn, FrameVarInfo);
SmallVector<BlockAddress *, 4> ActionTargets;
SmallVector<ActionHandler *, 4> ActionList;
parseEHActions(EHActions, ActionList);
Type::getInt32Ty(Context), nullptr),
PersonalityFn, 0);
// Insert a call to llvm.eh.actions so that we don't try to outline this lpad.
- Function *ActionIntrin = Intrinsic::getDeclaration(Handler->getParent(),
- Intrinsic::eh_actions);
+ Function *ActionIntrin =
+ Intrinsic::getDeclaration(Handler->getParent(), Intrinsic::eh_actions);
Builder.CreateCall(ActionIntrin, "recover");
LPad->setCleanup(true);
Builder.CreateUnreachable();
else
Term = Unreached;
BasicBlock *OldRetBB = Term->getParent();
- BasicBlock *NewRetBB = SplitBlock(OldRetBB, Term);
+ BasicBlock *NewRetBB = SplitBlock(OldRetBB, Term, DT);
// SplitBlock adds an unconditional branch instruction at the end of the
// parent block. We want to replace that with an invoke call, so we can
// erase it now.
InvokeInst::Create(F, NewRetBB, StubLandingPad, None, "", OldRetBB);
}
+// FIXME: Consider sinking this into lib/Target/X86 somehow. TargetLowering
+// usually doesn't build LLVM IR, so that's probably the wrong place.
+Function *WinEHPrepare::createHandlerFunc(Type *RetTy, const Twine &Name,
+ Module *M, Value *&ParentFP) {
+ // x64 uses a two-argument prototype where the parent FP is the second
+ // argument. x86 uses no arguments, just the incoming EBP value.
+ LLVMContext &Context = M->getContext();
+ FunctionType *FnType;
+ if (TheTriple.getArch() == Triple::x86_64) {
+ Type *Int8PtrType = Type::getInt8PtrTy(Context);
+ Type *ArgTys[2] = {Int8PtrType, Int8PtrType};
+ FnType = FunctionType::get(RetTy, ArgTys, false);
+ } else {
+ FnType = FunctionType::get(RetTy, None, false);
+ }
+
+ Function *Handler =
+ Function::Create(FnType, GlobalVariable::InternalLinkage, Name, M);
+ BasicBlock *Entry = BasicBlock::Create(Context, "entry");
+ Handler->getBasicBlockList().push_front(Entry);
+ if (TheTriple.getArch() == Triple::x86_64) {
+ ParentFP = &(Handler->getArgumentList().back());
+ } else {
+ assert(M);
+ Function *FrameAddressFn =
+ Intrinsic::getDeclaration(M, Intrinsic::frameaddress);
+ Value *Args[1] = {ConstantInt::get(Type::getInt32Ty(Context), 1)};
+ ParentFP = CallInst::Create(FrameAddressFn, Args, "parent_fp",
+ &Handler->getEntryBlock());
+ }
+ return Handler;
+}
+
bool WinEHPrepare::outlineHandler(ActionHandler *Action, Function *SrcFn,
LandingPadInst *LPad, BasicBlock *StartBB,
FrameVarInfoMap &VarInfo) {
Module *M = SrcFn->getParent();
LLVMContext &Context = M->getContext();
+ Type *Int8PtrType = Type::getInt8PtrTy(Context);
// Create a new function to receive the handler contents.
- Type *Int8PtrType = Type::getInt8PtrTy(Context);
- std::vector<Type *> ArgTys;
- ArgTys.push_back(Int8PtrType);
- ArgTys.push_back(Int8PtrType);
+ Value *ParentFP;
Function *Handler;
if (Action->getType() == Catch) {
- FunctionType *FnType = FunctionType::get(Int8PtrType, ArgTys, false);
- Handler = Function::Create(FnType, GlobalVariable::InternalLinkage,
- SrcFn->getName() + ".catch", M);
+ Handler = createHandlerFunc(Int8PtrType, SrcFn->getName() + ".catch", M,
+ ParentFP);
} else {
- FunctionType *FnType =
- FunctionType::get(Type::getVoidTy(Context), ArgTys, false);
- Handler = Function::Create(FnType, GlobalVariable::InternalLinkage,
- SrcFn->getName() + ".cleanup", M);
+ Handler = createHandlerFunc(Type::getVoidTy(Context),
+ SrcFn->getName() + ".cleanup", M, ParentFP);
}
-
+ HandlerToParentFP[Handler] = ParentFP;
Handler->addFnAttr("wineh-parent", SrcFn->getName());
+ BasicBlock *Entry = &Handler->getEntryBlock();
// Generate a standard prolog to setup the frame recovery structure.
IRBuilder<> Builder(Context);
- BasicBlock *Entry = BasicBlock::Create(Context, "entry");
- Handler->getBasicBlockList().push_front(Entry);
Builder.SetInsertPoint(Entry);
Builder.SetCurrentDebugLocation(LPad->getDebugLoc());
LPadMap.mapLandingPad(LPad);
if (auto *CatchAction = dyn_cast<CatchHandler>(Action)) {
Constant *Sel = CatchAction->getSelector();
- Director.reset(new WinEHCatchDirector(Handler, Sel, VarInfo, LPadMap,
+ Director.reset(new WinEHCatchDirector(Handler, ParentFP, Sel,
+ VarInfo, LPadMap,
NestedLPtoOriginalLP));
LPadMap.remapEHValues(VMap, UndefValue::get(Int8PtrType),
ConstantInt::get(Type::getInt32Ty(Context), 1));
} else {
- Director.reset(new WinEHCleanupDirector(Handler, VarInfo, LPadMap));
+ Director.reset(
+ new WinEHCleanupDirector(Handler, ParentFP, VarInfo, LPadMap));
LPadMap.remapEHValues(VMap, UndefValue::get(Int8PtrType),
UndefValue::get(Type::getInt32Ty(Context)));
}
/*ModuleLevelChanges=*/false, Returns, "",
&OutlinedFunctionInfo, Director.get());
- // Move all the instructions in the first cloned block into our entry block.
- BasicBlock *FirstClonedBB = std::next(Function::iterator(Entry));
- Entry->getInstList().splice(Entry->end(), FirstClonedBB->getInstList());
- FirstClonedBB->eraseFromParent();
+ // Move all the instructions in the cloned "entry" block into our entry block.
+ // Depending on how the parent function was laid out, the block that will
+ // correspond to the outlined entry block may not be the first block in the
+ // list. We can recognize it, however, as the cloned block which has no
+ // predecessors. Any other block wouldn't have been cloned if it didn't
+ // have a predecessor which was also cloned.
+ Function::iterator ClonedIt = std::next(Function::iterator(Entry));
+ while (!pred_empty(ClonedIt))
+ ++ClonedIt;
+ BasicBlock *ClonedEntryBB = ClonedIt;
+ assert(ClonedEntryBB);
+ Entry->getInstList().splice(Entry->end(), ClonedEntryBB->getInstList());
+ ClonedEntryBB->eraseFromParent();
// Make sure we can identify the handler's personality later.
addStubInvokeToHandlerIfNeeded(Handler, LPad->getPersonalityFn());
} else {
// This must be a catch-all. Split the block after the landingpad.
assert(CatchAction->getSelector()->isNullValue() && "expected catch-all");
- HandlerBB =
- StartBB->splitBasicBlock(StartBB->getFirstInsertionPt(), "catch.all");
+ HandlerBB = SplitBlock(StartBB, StartBB->getFirstInsertionPt(), DT);
}
+ IRBuilder<> Builder(HandlerBB->getFirstInsertionPt());
+ Function *EHCodeFn = Intrinsic::getDeclaration(
+ StartBB->getParent()->getParent(), Intrinsic::eh_exceptioncode);
+ Value *Code = Builder.CreateCall(EHCodeFn, "sehcode");
+ Code = Builder.CreateIntToPtr(Code, SEHExceptionCodeSlot->getAllocatedType());
+ Builder.CreateStore(Code, SEHExceptionCodeSlot);
CatchAction->setHandlerBlockOrFunc(BlockAddress::get(HandlerBB));
TinyPtrVector<BasicBlock *> Targets(HandlerBB);
CatchAction->setReturnTargets(Targets);
// When outlining llvm.frameaddress(i32 0), remap that to the second argument,
// which is the FP of the parent.
if (isFrameAddressCall(Inst)) {
- VMap[Inst] = EstablisherFrame;
+ VMap[Inst] = ParentFP;
return CloningDirector::SkipInstruction;
}
const IntrinsicInst *IntrinCall = nullptr;
if (match(Compare->getOperand(0), m_Intrinsic<Intrinsic::eh_typeid_for>())) {
IntrinCall = dyn_cast<IntrinsicInst>(Compare->getOperand(0));
- } else if (match(Compare->getOperand(1), m_Intrinsic<Intrinsic::eh_typeid_for>())) {
+ } else if (match(Compare->getOperand(1),
+ m_Intrinsic<Intrinsic::eh_typeid_for>())) {
IntrinCall = dyn_cast<IntrinsicInst>(Compare->getOperand(1));
}
if (IntrinCall) {
// on the filter function we intend to match.
if (Selector == CurrentSelector->stripPointerCasts()) {
VMap[Compare] = ConstantInt::get(SelectorIDType, 1);
- }
- else {
+ } else {
VMap[Compare] = ConstantInt::get(SelectorIDType, 0);
}
return CloningDirector::SkipInstruction;
return CloningDirector::SkipInstruction;
}
return CloningDirector::CloneInstruction;
-
}
WinEHFrameVariableMaterializer::WinEHFrameVariableMaterializer(
- Function *OutlinedFn, FrameVarInfoMap &FrameVarInfo)
+ Function *OutlinedFn, Value *ParentFP, FrameVarInfoMap &FrameVarInfo)
: FrameVarInfo(FrameVarInfo), Builder(OutlinedFn->getContext()) {
BasicBlock *EntryBB = &OutlinedFn->getEntryBlock();
- Builder.SetInsertPoint(EntryBB, EntryBB->getFirstInsertionPt());
+
+ // New allocas should be inserted in the entry block, but after the parent FP
+ // is established if it is an instruction.
+ Instruction *InsertPoint = EntryBB->getFirstInsertionPt();
+ if (auto *FPInst = dyn_cast<Instruction>(ParentFP))
+ InsertPoint = FPInst->getNextNode();
+ Builder.SetInsertPoint(EntryBB, InsertPoint);
}
Value *WinEHFrameVariableMaterializer::materializeValueFor(Value *V) {
}
if (isa<Instruction>(V) || isa<Argument>(V)) {
- errs() << "Failed to demote instruction used in exception handler:\n";
+ Function *Parent = isa<Instruction>(V)
+ ? cast<Instruction>(V)->getParent()->getParent()
+ : cast<Argument>(V)->getParent();
+ errs()
+ << "Failed to demote instruction used in exception handler of function "
+ << GlobalValue::getRealLinkageName(Parent->getName()) << ":\n";
errs() << " " << *V << '\n';
report_fatal_error("WinEHPrepare failed to demote instruction");
}
// See if the clause we're looking for is a catch-all.
// If so, the catch begins immediately.
- Constant *ExpectedSelector = LPad->getClause(HandlersFound)->stripPointerCasts();
+ Constant *ExpectedSelector =
+ LPad->getClause(HandlersFound)->stripPointerCasts();
if (isa<ConstantPointerNull>(ExpectedSelector)) {
// The catch all must occur last.
assert(HandlersFound == NumClauses - 1);
Constant *Selector;
while (BB && isSelectorDispatch(BB, CatchBlock, Selector, NextBB)) {
DEBUG(dbgs() << " Found extra catch dispatch in block "
- << CatchBlock->getName() << "\n");
+ << CatchBlock->getName() << "\n");
BB = NextBB;
}
- // For C++ EH, check if there is any interesting cleanup code before we
- // begin the catch. This is important because cleanups cannot rethrow
- // exceptions but code called from catches can. For SEH, it isn't
- // important if some finally code before a catch-all is executed out of
- // line or after recovering from the exception.
- if (Personality == EHPersonality::MSVC_CXX)
- findCleanupHandlers(Actions, BB, BB);
-
// Add the catch handler to the action list.
CatchHandler *Action = nullptr;
if (CatchHandlerMap.count(BB) && CatchHandlerMap[BB] != nullptr) {
Action = CatchHandlerMap[BB];
assert(Action->getSelector() == ExpectedSelector);
} else {
- // Since this is a catch-all handler, the selector won't actually appear
- // in the code anywhere. ExpectedSelector here is the constant null ptr
- // that we got from the landing pad instruction.
- Action = new CatchHandler(BB, ExpectedSelector, nullptr);
- CatchHandlerMap[BB] = Action;
+ // We don't expect a selector dispatch, but there may be a call to
+ // llvm.eh.begincatch, which separates catch handling code from
+ // cleanup code in the same control flow. This call looks for the
+ // begincatch intrinsic.
+ Action = findCatchHandler(BB, NextBB, VisitedBlocks);
+ if (Action) {
+ // For C++ EH, check if there is any interesting cleanup code before
+ // we begin the catch. This is important because cleanups cannot
+ // rethrow exceptions but code called from catches can. For SEH, it
+ // isn't important if some finally code before a catch-all is executed
+ // out of line or after recovering from the exception.
+ if (Personality == EHPersonality::MSVC_CXX)
+ findCleanupHandlers(Actions, BB, BB);
+ } else {
+ // If an action was not found, it means that the control flows
+ // directly into the catch-all handler and there is no cleanup code.
+ // That's an expected situation and we must create a catch action.
+ // Since this is a catch-all handler, the selector won't actually
+ // appear in the code anywhere. ExpectedSelector here is the constant
+ // null ptr that we got from the landing pad instruction.
+ Action = new CatchHandler(BB, ExpectedSelector, nullptr);
+ CatchHandlerMap[BB] = Action;
+ }
}
Actions.insertCatchHandler(Action);
DEBUG(dbgs() << " Catch all handler at block " << BB->getName() << "\n");
if (auto *Action = CleanupHandlerMap[BB]) {
Actions.insertCleanupHandler(Action);
DEBUG(dbgs() << " Found cleanup code in block "
- << Action->getStartBlock()->getName() << "\n");
+ << Action->getStartBlock()->getName() << "\n");
// FIXME: This cleanup might chain into another, and we need to discover
// that.
return;
// for finally calls in the normal successor block.
BasicBlock *SuccBB = BB;
if (FinallyCall.getInstruction() != BB->getTerminator() &&
- FinallyCall.getInstruction()->getNextNode() != BB->getTerminator()) {
- SuccBB = BB->splitBasicBlock(FinallyCall.getInstruction()->getNextNode());
+ FinallyCall.getInstruction()->getNextNode() !=
+ BB->getTerminator()) {
+ SuccBB =
+ SplitBlock(BB, FinallyCall.getInstruction()->getNextNode(), DT);
} else {
if (FinallyCall.isInvoke()) {
- SuccBB = cast<InvokeInst>(FinallyCall.getInstruction())->getNormalDest();
+ SuccBB =
+ cast<InvokeInst>(FinallyCall.getInstruction())->getNormalDest();
} else {
SuccBB = BB->getUniqueSuccessor();
- assert(SuccBB && "splitOutlinedFinallyCalls didn't insert a branch");
+ assert(SuccBB &&
+ "splitOutlinedFinallyCalls didn't insert a branch");
}
}
BB = SuccBB;