Merge pull request #968 from JosephTremoulet/NewRep

Update LLILC to generate new funclet EH IR
This commit is contained in:
Joseph Tremoulet 2015-12-29 19:17:37 -05:00
Родитель 9efe7b2727 4e5d0c5a88
Коммит e9956ab80b
5 изменённых файлов: 271 добавлений и 171 удалений

Просмотреть файл

@ -967,6 +967,7 @@ EHRegion *rgnGetParent(EHRegion *EhRegion);
/// \param Region The child region to check against its parent /// \param Region The child region to check against its parent
/// \returns True iff this region is lexically outside its parent /// \returns True iff this region is lexically outside its parent
bool rgnIsOutsideParent(EHRegion *Region); bool rgnIsOutsideParent(EHRegion *Region);
EHRegion *rgnGetEnclosingAncestor(EHRegion *Region);
void rgnSetChildList(EHRegion *EhRegion, EHRegionList *Children); void rgnSetChildList(EHRegion *EhRegion, EHRegionList *Children);
EHRegionList *rgnGetChildList(EHRegion *EhRegion); EHRegionList *rgnGetChildList(EHRegion *EhRegion);
EHRegion *rgnGetFilterHandlerRegion(EHRegion *EhRegion); EHRegion *rgnGetFilterHandlerRegion(EHRegion *EhRegion);

Просмотреть файл

@ -533,18 +533,14 @@ public:
void fgEnterRegion(EHRegion *Region) override; void fgEnterRegion(EHRegion *Region) override;
/// Make an EH pad suitable as an unwind label for code in the try region /// Make an EH pad suitable as the head of the given handler.
/// protected by the given handler, and any dispatch code needed after the
/// EH pad to transfer control to the handler code.
/// ///
/// \param Handler Catch/Finally/Fault/Filter region we need to /// \param Handler Catch/Finally/Fault/Filter region we need to
/// build an EH pad for. /// build an EH pad for.
/// \param EndPad [in/out] CatchEndPad/CleanupEndPad that should be the /// \param EnclosingPad EH pad representing the handler enclosing this one
/// unwind target of code in the handler body. /// if there is one, ConstantTokenNone otherwise.
/// \param NextPad Next outer (or successor catch) EH region.
/// \returns A new CatchPad/CleanupPad in a populated EH pad block. /// \returns A new CatchPad/CleanupPad in a populated EH pad block.
llvm::Instruction *createEHPad(EHRegion *Handler, llvm::Instruction *&EndPad, llvm::Instruction *createEHPad(EHRegion *Handler, llvm::Value *EnclosingPad);
llvm::Instruction *NextPad);
IRNode *fgNodeFindStartLabel(FlowGraphNode *Block) override; IRNode *fgNodeFindStartLabel(FlowGraphNode *Block) override;

Просмотреть файл

@ -2205,11 +2205,7 @@ EHRegion *ReaderBase::fgSwitchRegion(EHRegion *OldRegion, uint32_t Offset,
// Exit this region; recursively check parent (may need to exit to ancestor // Exit this region; recursively check parent (may need to exit to ancestor
// and/or may need to enter sibling/cousin). // and/or may need to enter sibling/cousin).
assert(Offset == TransitionOffset && "over-stepped region end"); assert(Offset == TransitionOffset && "over-stepped region end");
EHRegion *ParentRegion = rgnGetParent(OldRegion); EHRegion *ParentRegion = rgnGetEnclosingAncestor(OldRegion);
if (rgnIsOutsideParent(OldRegion)) {
// We want the enclosing ancestor, not the immediate parent.
ParentRegion = rgnGetParent(ParentRegion);
}
return fgSwitchRegion(ParentRegion, Offset, NextOffset); return fgSwitchRegion(ParentRegion, Offset, NextOffset);
} }

Просмотреть файл

@ -198,6 +198,15 @@ bool rgnIsOutsideParent(EHRegion *Region) {
} }
} }
EHRegion *rgnGetEnclosingAncestor(EHRegion *Region) {
EHRegion *OuterRegion = rgnGetParent(Region);
if (rgnIsOutsideParent(Region)) {
// We want the enclosing ancestor, not the immediate parent.
OuterRegion = rgnGetParent(OuterRegion);
}
return OuterRegion;
}
void rgnSetChildList(EHRegion *Region, EHRegionList *Children) { void rgnSetChildList(EHRegion *Region, EHRegionList *Children) {
Region->Children = Children; Region->Children = Children;
} }
@ -581,16 +590,7 @@ void GenIR::cloneFinallyBodies() {
continue; continue;
} }
BasicBlock *InsertBlock; LLVMBuilder->SetInsertPoint(&BB, std::next(First->getIterator()));
BasicBlock::iterator InsertPoint;
if (auto *Catchpad = dyn_cast<CatchPadInst>(First)) {
InsertBlock = Catchpad->getNormalDest();
InsertPoint = InsertBlock->getFirstInsertionPt();
} else {
InsertBlock = &BB;
InsertPoint = std::next(First->getIterator());
}
LLVMBuilder->SetInsertPoint(InsertBlock, InsertPoint);
Type *VoidType = Type::getVoidTy(*JitContext->LLVMContext); Type *VoidType = Type::getVoidTy(*JitContext->LLVMContext);
const bool MayThrow = false; const bool MayThrow = false;
callHelperImpl(CORINFO_HELP_FAIL_FAST, MayThrow, VoidType); callHelperImpl(CORINFO_HELP_FAIL_FAST, MayThrow, VoidType);
@ -603,16 +603,9 @@ void GenIR::cloneFinallyBody(EHRegion *FinallyRegion) {
// Find the exceptional exits // Find the exceptional exits
BasicBlock *CleanupRetBlock = nullptr; BasicBlock *CleanupRetBlock = nullptr;
BasicBlock *CleanupEndBlock = nullptr;
BasicBlock *CleanupEndSucc = nullptr;
for (User *U : Cleanup->users()) { for (User *U : Cleanup->users()) {
if (auto *CleanupEndPad = dyn_cast<CleanupEndPadInst>(U)) { if (isa<CleanupReturnInst>(U)) {
assert(CleanupEndBlock == nullptr && "Expected just one cleanupendpad");
CleanupEndBlock = CleanupEndPad->getParent();
CleanupEndSucc = CleanupEndPad->getUnwindDest();
} else {
assert(isa<CleanupReturnInst>(U));
assert(CleanupRetBlock == nullptr && "Expected just one cleanupret"); assert(CleanupRetBlock == nullptr && "Expected just one cleanupret");
CleanupRetBlock = cast<Instruction>(U)->getParent(); CleanupRetBlock = cast<Instruction>(U)->getParent();
// Check that the switch is the only predecessor of the cleanupret, since // Check that the switch is the only predecessor of the cleanupret, since
@ -623,10 +616,9 @@ void GenIR::cloneFinallyBody(EHRegion *FinallyRegion) {
} }
} }
assert(CleanupRetBlock && "Could not find cleanupret"); assert(CleanupRetBlock && "Could not find cleanupret");
assert(CleanupEndBlock && "Could not find cleanupendpad");
// Walk the flow graph to find the blocks that make up the finally. // Walk the flow graph to find the blocks that make up the finally.
// Don't include the cleanuppad itself or the cleanupret or cleanupendpad, // Don't include the cleanuppad itself or the cleanupret,
// since those only need to exist on the exception path. // since those only need to exist on the exception path.
SmallPtrSet<BasicBlock *, 8> FinallyBlocks; SmallPtrSet<BasicBlock *, 8> FinallyBlocks;
SmallVector<BasicBlock *, 4> Worklist; SmallVector<BasicBlock *, 4> Worklist;
@ -637,9 +629,25 @@ void GenIR::cloneFinallyBody(EHRegion *FinallyRegion) {
while (!Worklist.empty()) { while (!Worklist.empty()) {
BasicBlock *Block = Worklist.pop_back_val(); BasicBlock *Block = Worklist.pop_back_val();
for (BasicBlock *Succ : successors(Block)) { for (BasicBlock *Succ : successors(Block)) {
if (Succ == CleanupEndBlock) { if (Succ->isEHPad()) {
// Don't need to clone the cleanupendpad. // Need to figure out if this unwind edge exits the finally or not.
continue; // If it stays within the finally, then its target will be a descendant
// of the finally per the parent linkage on the EH pads.
bool FoundAncestry = false;
for (Value *Pad = Succ->getFirstNonPHI(); !isa<ConstantTokenNone>(Pad);
Pad = isa<CatchSwitchInst>(Pad)
? cast<CatchSwitchInst>(Pad)->getParentPad()
: cast<FuncletPadInst>(Pad)->getParentPad()) {
if (Pad == Cleanup) {
FoundAncestry = true;
break;
}
}
if (!FoundAncestry) {
// This EH edge exits the funclet, so we do not need to clone the
// successor block.
continue;
}
} }
if (FinallyBlocks.insert(Succ).second) { if (FinallyBlocks.insert(Succ).second) {
if (Succ == ExitSwitchBlock) { if (Succ == ExitSwitchBlock) {
@ -667,27 +675,25 @@ void GenIR::cloneFinallyBody(EHRegion *FinallyRegion) {
} }
} }
// Add entries to re-route exceptional exits in the non-exception clone.
// The cleanupret is targeted just by the switch in the case that handles // The cleanupret is targeted just by the switch in the case that handles
// the exceptional continuation, so on the non-exception path it can target // the exceptional continuation, so on the non-exception path it can target
// the `unreachable` that is the switch default instead. // the `unreachable` that is the switch default instead.
assert(isa<UnreachableInst>(ExitSwitch->getDefaultDest()->getFirstNonPHI())); assert(isa<UnreachableInst>(ExitSwitch->getDefaultDest()->getFirstNonPHI()));
ValueMap[CleanupRetBlock] = ExitSwitch->getDefaultDest(); ValueMap[CleanupRetBlock] = ExitSwitch->getDefaultDest();
// The cleanupendpad is targeted by any exceptions that propagate out of the // Map the finally itself to its parent funclet, so that any calls or nested
// finally. These need to be redirected to the next outer handler. If the // funclets which reference the finally being cloned as their parent will
// cleanupendpad unwinds to caller, we'll need to rewrite its preds to // have their clones on the non-exception path reference the outer parent
// unwind to caller in a post-pass, so use the entry block as a sentinel // instead.
// during the initial mapping. Value *ParentPad = Cleanup->getParentPad();
BasicBlock *CallerUnwindSentinel; bool TrueParentIsNone = isa<ConstantTokenNone>(ParentPad);
if (CleanupEndSucc == nullptr) { if (TrueParentIsNone) {
CallerUnwindSentinel = &Function->getEntryBlock(); // Any call/invoke bundles referring to the cleanup will need to be
ValueMap[CleanupEndBlock] = CallerUnwindSentinel; // removed. Place a sentinel in the map to make them easy to find and
} else { // fix up later.
CallerUnwindSentinel = nullptr; ParentPad = CleanupPadInst::Create(ParentPad);
ValueMap[CleanupEndBlock] = CleanupEndSucc;
} }
ValueMap[Cleanup] = ParentPad;
// Now apply the value map fixups to the cloned instructions using the // Now apply the value map fixups to the cloned instructions using the
// RemapInstruction utility. // RemapInstruction utility.
@ -698,15 +704,45 @@ void GenIR::cloneFinallyBody(EHRegion *FinallyRegion) {
} }
} }
if (CallerUnwindSentinel != nullptr) { if (TrueParentIsNone) {
// Remove the sentinel unwind edges. // Remove references to the sentinel parent.
for (pred_iterator PI = pred_begin(CallerUnwindSentinel), SmallVector<Instruction *, 8> ReplacedInstructions;
PE = pred_end(CallerUnwindSentinel); for (User *U : ParentPad->users()) {
PI != PE;) { Instruction *OldInstruction;
// Advance the iterator before erasing the edge. Instruction *NewInstruction;
BasicBlock *Predecessor = *PI++; if (auto *Call = dyn_cast<CallInst>(U)) {
llvm::removeUnwindEdge(Predecessor); OldInstruction = Call;
NewInstruction = CallInst::Create(Call, {}, Call);
} else if (auto *Invoke = dyn_cast<InvokeInst>(U)) {
OldInstruction = Invoke;
NewInstruction = InvokeInst::Create(Invoke, {}, Invoke);
} else {
continue;
}
NewInstruction->setDebugLoc(OldInstruction->getDebugLoc());
OldInstruction->replaceAllUsesWith(NewInstruction);
// Make sure the funclet bundle is the only one we're removing
assert(CallSite(OldInstruction).getNumOperandBundles() == 1);
assert(CallSite(OldInstruction).getOperandBundleAt(0).getTagID() ==
LLVMContext::OB_funclet);
// Queue the old instruction for deferred removal so we don't messs up
// the user iterator.
ReplacedInstructions.push_back(OldInstruction);
} }
for (Instruction *OldInstruction : ReplacedInstructions) {
OldInstruction->eraseFromParent();
}
// Any remaining users should be child EH pads, which need to get their
// parent set to "none"
assert(llvm::all_of(ParentPad->users(), [](User *U) {
return cast<Instruction>(U)->isEHPad();
}));
ConstantTokenNone *TrueParent =
ConstantTokenNone::get(*JitContext->LLVMContext);
ParentPad->replaceAllUsesWith(TrueParent);
delete ParentPad;
ParentPad = TrueParent;
} }
// Now the clone should hold the right code for the non-exceptional path, // Now the clone should hold the right code for the non-exceptional path,
@ -740,9 +776,8 @@ bool GenIR::canExecuteHandler(BasicBlock &Handler) {
return true; return true;
} }
// Funclet prologs currently don't correctly set up the frame pointer, and // Handler execution is still off by default, since precise GC reporting
// we have no way to guarantee that a handler won't reference something on // isn't correct on exception paths.
// the stack (like an RA) spill, so currently we can't execute any handler.
return false; return false;
} }
@ -3275,12 +3310,13 @@ IRNode *GenIR::fgMakeEndFinally(IRNode *InsertNode, EHRegion *FinallyRegion,
LLVMBuilder->Insert(Switch); LLVMBuilder->Insert(Switch);
// Create the cleanupret to handle the exceptional continuation // Create the cleanupret to handle the exceptional continuation
auto *EndPad = cast<CleanupEndPadInst>(FinallyRegion->HandlerEHPad); BasicBlock *UnwindDest = FinallyRegion->HandlerEHPad
BasicBlock *OuterPad = EndPad->getUnwindDest(); ? FinallyRegion->HandlerEHPad->getParent()
: nullptr;
BasicBlock *ExitBlock = BasicBlock *ExitBlock =
createPointBlock(FinallyRegion->EndMsilOffset, "ContinueExn"); createPointBlock(FinallyRegion->EndMsilOffset, "exn.continue");
LLVMBuilder->SetInsertPoint(ExitBlock); LLVMBuilder->SetInsertPoint(ExitBlock);
LLVMBuilder->CreateCleanupRet(FinallyRegion->CleanupPad, OuterPad); LLVMBuilder->CreateCleanupRet(FinallyRegion->CleanupPad, UnwindDest);
ConstantInt *Zero = ConstantInt::get(cast<IntegerType>(Load->getType()), 0); ConstantInt *Zero = ConstantInt::get(cast<IntegerType>(Load->getType()), 0);
Switch->addCase(Zero, ExitBlock); Switch->addCase(Zero, ExitBlock);
@ -3330,13 +3366,38 @@ void GenIR::fgEnterRegion(EHRegion *Region) {
EHRegion *Parent = rgnGetParent(Region); EHRegion *Parent = rgnGetParent(Region);
assert(!rgnIsOutsideParent(Region)); assert(!rgnIsOutsideParent(Region));
Instruction *EHPad = Parent->HandlerEHPad; // Also find the nearest non-try ancestor -- this corresponds to the funclet
// that this try is nested within (if any), which we'll need to record on
// the EH pad generated here.
EHRegion *EnclosingHandler = Parent;
while (EnclosingHandler->Kind == ReaderBaseNS::RegionKind::RGN_Try) {
assert(!rgnIsOutsideParent(EnclosingHandler));
EnclosingHandler = rgnGetParent(EnclosingHandler);
}
Value *EnclosingPad;
switch (EnclosingHandler->Kind) {
case ReaderBaseNS::RegionKind::RGN_Root:
EnclosingPad = ConstantTokenNone::get(*JitContext->LLVMContext);
break;
case ReaderBaseNS::RegionKind::RGN_MCatch:
case ReaderBaseNS::RegionKind::RGN_MExcept:
EnclosingPad = EnclosingHandler->CatchPad;
break;
case ReaderBaseNS::RegionKind::RGN_Finally:
case ReaderBaseNS::RegionKind::RGN_Fault:
EnclosingPad = EnclosingHandler->CleanupPad;
break;
case ReaderBaseNS::RegionKind::RGN_Filter:
EnclosingPad = EnclosingHandler->HandlerRegion->CatchPad;
break;
default:
llvm_unreachable("Unexpected region kind");
}
// When we enter a try region, eagerly create EH pads for its handler(s), // Visit each child of the try, creating handler code for any that are
// in reverse order, because each needs to name the next as its successor // handlers.
// when it is constructed, and any invokes inside the try need to name the CatchSwitchInst *CatchSwitch = nullptr;
// first handler as their successsor. Instruction *NewPad = nullptr;
SmallVector<EHRegion *, 4> Handlers;
for (EHRegionList *ChildNode = rgnGetChildList(Region); ChildNode; for (EHRegionList *ChildNode = rgnGetChildList(Region); ChildNode;
ChildNode = rgnListGetNext(ChildNode)) { ChildNode = rgnListGetNext(ChildNode)) {
EHRegion *Child = rgnListGetRgn(ChildNode); EHRegion *Child = rgnListGetRgn(ChildNode);
@ -3350,31 +3411,65 @@ void GenIR::fgEnterRegion(EHRegion *Region) {
// branches to the handler at the point of the endfilter. // branches to the handler at the point of the endfilter.
break; break;
case ReaderBaseNS::RegionKind::RGN_MCatch: case ReaderBaseNS::RegionKind::RGN_MCatch:
case ReaderBaseNS::RegionKind::RGN_Filter: case ReaderBaseNS::RegionKind::RGN_Filter: {
// These become catchpads, which need to be embedded in a catchswitch.
if (CatchSwitch == nullptr) {
assert(NewPad == nullptr &&
"try with finally/fault can't also have catch/filter");
BasicBlock *SwitchBlock =
createPointBlock(Region->EndMsilOffset, "exn.dispatch");
LLVMBuilder->SetInsertPoint(SwitchBlock);
// Compute the number of handlers we'll attach to this catchswitch
unsigned NumHandlers = 1;
for (EHRegionList *Node = rgnListGetNext(ChildNode); Node != nullptr;
Node = rgnListGetNext(Node)) {
if (rgnListGetRgn(Node)->Kind ==
ReaderBaseNS::RegionKind::RGN_MExcept) {
// This will share its filter's handler
continue;
}
// The rest of the list should just be more catch/filter handlers.
assert(rgnListGetRgn(Node)->Kind ==
ReaderBaseNS::RegionKind::RGN_MCatch ||
rgnListGetRgn(Node)->Kind ==
ReaderBaseNS::RegionKind::RGN_Filter);
++NumHandlers;
}
// Create the catchswitch
BasicBlock *UnwindDest =
Parent->HandlerEHPad ? Parent->HandlerEHPad->getParent() : nullptr;
NewPad = CatchSwitch = LLVMBuilder->CreateCatchSwitch(
EnclosingPad, UnwindDest, NumHandlers, "catchswitch");
}
// Any exception bubbling out of this handler will unwind to the same
// thing that the parent region unwinds to.
Child->HandlerEHPad = Parent->HandlerEHPad;
// Create the catchpad
Instruction *CatchPad = createEHPad(Child, CatchSwitch);
CatchSwitch->addHandler(CatchPad->getParent());
break;
}
case ReaderBaseNS::RegionKind::RGN_Finally: case ReaderBaseNS::RegionKind::RGN_Finally:
case ReaderBaseNS::RegionKind::RGN_Fault: case ReaderBaseNS::RegionKind::RGN_Fault:
// This handler needs processing. assert(NewPad == nullptr &&
Handlers.push_back(Child); "try with finally/fault cannot have multiple handlers");
// Any exception bubbling out of this handler will unwind to the same
// thing that the parent region unwinds to.
Child->HandlerEHPad = Parent->HandlerEHPad;
// Create the cleanuppad
NewPad = createEHPad(Child, EnclosingPad);
break; break;
default: default:
llvm_unreachable("Unexpected region kind"); llvm_unreachable("Unexpected region kind");
} }
} }
Instruction *EndPad = nullptr;
for (auto I = Handlers.rbegin(), E = Handlers.rend(); I != E; ++I) {
EHPad = createEHPad(*I, EndPad, EHPad);
}
// Record the handler so we can hook up exception edges later. // Record the handler so we can hook up exception edges later.
Region->HandlerEHPad = EHPad; Region->HandlerEHPad = NewPad;
} }
Instruction *GenIR::createEHPad(EHRegion *Handler, Instruction *&EndPad, Instruction *GenIR::createEHPad(EHRegion *Handler, Value *EnclosingPad) {
Instruction *NextPad) {
LLVMContext &LLVMContext = *JitContext->LLVMContext; LLVMContext &LLVMContext = *JitContext->LLVMContext;
BasicBlock *NextPadBlock =
(NextPad == nullptr ? nullptr : NextPad->getParent());
if (PersonalityFunction == nullptr) { if (PersonalityFunction == nullptr) {
// The EE provides a CorInfoHelpFunc handle for the actual personality // The EE provides a CorInfoHelpFunc handle for the actual personality
@ -3394,19 +3489,6 @@ Instruction *GenIR::createEHPad(EHRegion *Handler, Instruction *&EndPad,
Function->setPersonalityFn(PersonalityFunction); Function->setPersonalityFn(PersonalityFunction);
} }
BasicBlock *EndPadSuccessor = nullptr;
if ((EndPad == nullptr) || !isa<CatchEndPadInst>(EndPad) ||
(Handler->Kind == ReaderBaseNS::RegionKind::RGN_Finally) ||
(Handler->Kind == ReaderBaseNS::RegionKind::RGN_Fault)) {
// Create a block to hold the endpad
EndPadSuccessor = NextPadBlock;
uint32_t EndPoint = Handler->EndMsilOffset;
if (Handler->Kind == ReaderBaseNS::RegionKind::RGN_Filter) {
EndPoint = Handler->HandlerRegion->EndMsilOffset;
}
NextPadBlock = createPointBlock(EndPoint, "EndPad");
}
FlowGraphNode *HandlerCodeBlock = nullptr; FlowGraphNode *HandlerCodeBlock = nullptr;
fgAddNodeMSILOffset(&HandlerCodeBlock, Handler->StartMsilOffset); fgAddNodeMSILOffset(&HandlerCodeBlock, Handler->StartMsilOffset);
@ -3418,10 +3500,12 @@ Instruction *GenIR::createEHPad(EHRegion *Handler, Instruction *&EndPad,
} }
Instruction *Pad; Instruction *Pad;
Instruction *Exception;
switch (Handler->Kind) { switch (Handler->Kind) {
case ReaderBaseNS::RegionKind::RGN_Filter: case ReaderBaseNS::RegionKind::RGN_Filter:
case ReaderBaseNS::RegionKind::RGN_MCatch: { case ReaderBaseNS::RegionKind::RGN_MCatch: {
// Get the token to attach to the catchpad so we can emit it in the EH
// tables (for filters we use System.Object), and the type to use in the
// IR for the exception pointer.
mdToken ClassToken; mdToken ClassToken;
Type *CaughtType; Type *CaughtType;
if (Handler->Kind == ReaderBaseNS::RegionKind::RGN_MCatch) { if (Handler->Kind == ReaderBaseNS::RegionKind::RGN_MCatch) {
@ -3435,77 +3519,72 @@ Instruction *GenIR::createEHPad(EHRegion *Handler, Instruction *&EndPad,
getType(CORINFO_TYPE_CLASS, getType(CORINFO_TYPE_CLASS,
getBuiltinClass(CorInfoClassId::CLASSID_SYSTEM_OBJECT)); getBuiltinClass(CorInfoClassId::CLASSID_SYSTEM_OBJECT));
} }
// Build an IR Value representing the metadata token for the caught type.
static_assert(sizeof(mdToken) == sizeof(int32_t), "Unexpected token size"); static_assert(sizeof(mdToken) == sizeof(int32_t), "Unexpected token size");
IntegerType *TokenType = Type::getInt32Ty(*JitContext->LLVMContext); IntegerType *TokenType = Type::getInt32Ty(*JitContext->LLVMContext);
Constant *TokenConstant = ConstantInt::get(TokenType, ClassToken); Constant *TokenConstant = ConstantInt::get(TokenType, ClassToken);
BasicBlock *PadBlock = createPointBlock(Handler->StartMsilOffset, "Catch");
BasicBlock *ThunkBlock = // Create a thunk block that splits the edge from exception dispatch to
createPointBlock(Handler->StartMsilOffset, "Catch.Exn"); // the start of the handler (that will NOT be the target of any back-edges
// from within the handler to the start of the handler). This block holds
// a call to the @llvm.eh.exceptionpointer intrinsic that retrieves the
// exception pointer as a function of the catchpad.
BasicBlock *PadBlock = createPointBlock(Handler->StartMsilOffset, "catch");
LLVMBuilder->SetInsertPoint(PadBlock); LLVMBuilder->SetInsertPoint(PadBlock);
Pad = Handler->CatchPad = LLVMBuilder->CreateCatchPad( Pad = Handler->CatchPad =
ThunkBlock, NextPadBlock, {TokenConstant}, "CatchPad"); LLVMBuilder->CreateCatchPad(EnclosingPad, {TokenConstant}, "catch.pad");
LLVMBuilder->SetInsertPoint(ThunkBlock);
llvm::Function *GetException = llvm::Function *GetException =
Intrinsic::getDeclaration(JitContext->CurrentModule, Intrinsic::getDeclaration(JitContext->CurrentModule,
Intrinsic::eh_exceptionpointer, {CaughtType}); Intrinsic::eh_exceptionpointer, {CaughtType});
Exception = LLVMBuilder->CreateCall(GetException, {Pad}, "exn"); Instruction *Exception =
LLVMBuilder->CreateCall(GetException, {Pad}, "exn");
LLVMBuilder->CreateBr(HandlerCodeBlock); LLVMBuilder->CreateBr(HandlerCodeBlock);
break; // Propagate the exception object on the evaluation stack
}
case ReaderBaseNS::RegionKind::RGN_Finally: {
BasicBlock *PadBlock =
createPointBlock(Handler->StartMsilOffset, "Finally");
LLVMBuilder->SetInsertPoint(PadBlock);
Pad = Handler->CleanupPad = LLVMBuilder->CreateCleanupPad({}, "FinallyPad");
LLVMBuilder->CreateBr(HandlerCodeBlock);
// The in-flight exception is not available to a finally handler.
Exception = nullptr;
break;
}
case ReaderBaseNS::RegionKind::RGN_Fault: {
BasicBlock *PadBlock = createPointBlock(Handler->StartMsilOffset, "Fault");
LLVMBuilder->SetInsertPoint(PadBlock);
// Add an i32 argument to faults, to distinguish them from filters.
Value *Undef = UndefValue::get(Type::getInt32Ty(LLVMContext));
Pad = Handler->CleanupPad =
LLVMBuilder->CreateCleanupPad({Undef}, "FaultPad");
LLVMBuilder->CreateBr(HandlerCodeBlock);
// The in-flight exception is not available to a fault handler.
Exception = nullptr;
break;
}
default:
llvm_unreachable("Unexpected handler type");
}
if (Exception != nullptr) {
// Propagate the exception object
FlowGraphNode *ExceptionBlock = (FlowGraphNode *)Exception->getParent(); FlowGraphNode *ExceptionBlock = (FlowGraphNode *)Exception->getParent();
ReaderStack *ExceptionBlockStack = createStack(); ReaderStack *ExceptionBlockStack = createStack();
ExceptionBlockStack->push((IRNode *)Exception); ExceptionBlockStack->push((IRNode *)Exception);
fgNodeSetOperandStack(ExceptionBlock, ExceptionBlockStack); fgNodeSetOperandStack(ExceptionBlock, ExceptionBlockStack);
fgNodeSetPropagatesOperandStack(ExceptionBlock, true); fgNodeSetPropagatesOperandStack(ExceptionBlock, true);
if ((EndPad == nullptr) || !isa<CatchEndPadInst>(EndPad)) { if (Handler->Kind == ReaderBaseNS::RegionKind::RGN_Filter) {
// This is the tail of the catchpad chain, so we need to set the endpad. // copy relevant attributes to the filter-handler.
EndPad = EHRegion *FilterHandler = Handler->HandlerRegion;
CatchEndPadInst::Create(LLVMContext, EndPadSuccessor, NextPadBlock); FilterHandler->CatchPad = cast<CatchPadInst>(Pad);
FilterHandler->HandlerEHPad = Handler->HandlerEHPad;
FilterHandler->Exception = Exception;
} }
} else { break;
// Every cleanuppad gets its own cleanupendpad
CleanupPadInst *CleanupPad = cast<CleanupPadInst>(Pad);
EndPad =
CleanupEndPadInst::Create(CleanupPad, EndPadSuccessor, NextPadBlock);
} }
case ReaderBaseNS::RegionKind::RGN_Finally: {
// Any EH edge inside the handler itself should target the associated endpad. // Create a thunk block that splits the edge from exception dispatch to
Handler->HandlerEHPad = EndPad; // the start of the handler (that will NOT be the target of any back-edges
if (Handler->Kind == ReaderBaseNS::RegionKind::RGN_Filter) { // from within the handler to the start of the handler). It just has the
// copy relevant attributes to the filter-handler. // cleanuppad and a branch to the start of the handler.
EHRegion *FilterHandler = Handler->HandlerRegion; BasicBlock *PadBlock =
FilterHandler->CatchPad = cast<CatchPadInst>(Pad); createPointBlock(Handler->StartMsilOffset, "finally");
FilterHandler->HandlerEHPad = EndPad; LLVMBuilder->SetInsertPoint(PadBlock);
FilterHandler->Exception = Exception; Pad = Handler->CleanupPad =
LLVMBuilder->CreateCleanupPad(EnclosingPad, {}, "finally.pad");
LLVMBuilder->CreateBr(HandlerCodeBlock);
break;
}
case ReaderBaseNS::RegionKind::RGN_Fault: {
// Create a thunk block that splits the edge from exception dispatch to
// the start of the handler (that will NOT be the target of any back-edges
// from within the handler to the start of the handler). It just has the
// cleanuppad and a branch to the start of the handler.
BasicBlock *PadBlock = createPointBlock(Handler->StartMsilOffset, "fault");
LLVMBuilder->SetInsertPoint(PadBlock);
// Add an i32 argument to faults, to distinguish them from filters.
Value *Undef = UndefValue::get(Type::getInt32Ty(LLVMContext));
Pad = Handler->CleanupPad =
LLVMBuilder->CreateCleanupPad(EnclosingPad, {Undef}, "fault.pad");
LLVMBuilder->CreateBr(HandlerCodeBlock);
break;
}
default:
llvm_unreachable("Unexpected handler type");
} }
return Pad; return Pad;
@ -4841,6 +4920,33 @@ LoadInst *GenIR::makeLoad(Value *Address, bool IsVolatile,
} }
CallSite GenIR::makeCall(Value *Callee, bool MayThrow, ArrayRef<Value *> Args) { CallSite GenIR::makeCall(Value *Callee, bool MayThrow, ArrayRef<Value *> Args) {
// First, figure out if we're inside a handler -- if so, we need a bundle
// indicating which one.
Value *ParentPad = nullptr;
for (EHRegion *Region = CurrentRegion; Region != nullptr;
Region = rgnGetEnclosingAncestor(Region)) {
auto Kind = Region->Kind;
if ((Kind == ReaderBaseNS::RegionKind::RGN_Fault) ||
(Kind == ReaderBaseNS::RegionKind::RGN_Finally)) {
ParentPad = Region->CleanupPad;
break;
}
if ((Kind == ReaderBaseNS::RegionKind::RGN_MCatch) ||
(Kind == ReaderBaseNS::RegionKind::RGN_MExcept)) {
ParentPad = Region->CatchPad;
break;
}
if (Kind == ReaderBaseNS::RegionKind::RGN_Filter) {
ParentPad = Region->HandlerRegion->CatchPad;
break;
}
}
SmallVector<OperandBundleDef, 1> Bundles;
if (ParentPad != nullptr) {
Bundles.emplace_back("funclet", ParentPad);
}
if (MayThrow) { if (MayThrow) {
Instruction *EHPad = Instruction *EHPad =
(CurrentRegion == nullptr ? nullptr : CurrentRegion->HandlerEHPad); (CurrentRegion == nullptr ? nullptr : CurrentRegion->HandlerEHPad);
@ -4856,8 +4962,8 @@ CallSite GenIR::makeCall(Value *Callee, bool MayThrow, ArrayRef<Value *> Args) {
BasicBlock *ExceptionSuccessor = EHPad->getParent(); BasicBlock *ExceptionSuccessor = EHPad->getParent();
TerminatorInst *Goto; TerminatorInst *Goto;
BasicBlock *NormalSuccessor = splitCurrentBlock(&Goto); BasicBlock *NormalSuccessor = splitCurrentBlock(&Goto);
InvokeInst *Invoke = InvokeInst *Invoke = InvokeInst::Create(
InvokeInst::Create(Callee, NormalSuccessor, ExceptionSuccessor, Args); Callee, NormalSuccessor, ExceptionSuccessor, Args, Bundles);
replaceInstruction(Goto, Invoke); replaceInstruction(Goto, Invoke);
return Invoke; return Invoke;
@ -4865,7 +4971,7 @@ CallSite GenIR::makeCall(Value *Callee, bool MayThrow, ArrayRef<Value *> Args) {
} }
// Generate a simple call. // Generate a simple call.
return LLVMBuilder->CreateCall(Callee, Args); return LLVMBuilder->CreateCall(Callee, Args, Bundles);
} }
void GenIR::storeStaticField(CORINFO_RESOLVED_TOKEN *FieldToken, void GenIR::storeStaticField(CORINFO_RESOLVED_TOKEN *FieldToken,
@ -6746,8 +6852,9 @@ void GenIR::nop() {
llvm::InlineAsm *AsmCode = llvm::InlineAsm::get(FTy, "nop", "", true, false, llvm::InlineAsm *AsmCode = llvm::InlineAsm::get(FTy, "nop", "", true, false,
llvm::InlineAsm::AD_Intel); llvm::InlineAsm::AD_Intel);
const bool MayThrow = false;
ArrayRef<Value *> Args; ArrayRef<Value *> Args;
LLVMBuilder->CreateCall(AsmCode, Args); makeCall(AsmCode, MayThrow, Args);
} }
IRNode *GenIR::unbox(CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *Object, IRNode *GenIR::unbox(CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *Object,

Просмотреть файл

@ -1147,6 +1147,18 @@
<ExcludeList Include="$(XunitTestBinBase)\JIT\CodeGenBringUpTests\localloc\*" > <ExcludeList Include="$(XunitTestBinBase)\JIT\CodeGenBringUpTests\localloc\*" >
<Issue>13</Issue> <Issue>13</Issue>
</ExcludeList> </ExcludeList>
<ExcludeList Include="$(XunitTestBinBase)\JIT\Directed\StrAccess\straccess3_cs_r\*" >
<Issue>13</Issue>
</ExcludeList>
<ExcludeList Include="$(XunitTestBinBase)\JIT\Directed\StrAccess\straccess3_cs_ro\*" >
<Issue>13</Issue>
</ExcludeList>
<ExcludeList Include="$(XunitTestBinBase)\JIT\Directed\StrAccess\straccess3_cs_do\*" >
<Issue>13</Issue>
</ExcludeList>
<ExcludeList Include="$(XunitTestBinBase)\JIT\Methodical\casts\SEH\_relthrow\*" >
<Issue>13</Issue>
</ExcludeList>
<ExcludeList Include="$(XunitTestBinBase)\JIT\Regression\v4\dev10_804810\dev10_804810\*" > <ExcludeList Include="$(XunitTestBinBase)\JIT\Regression\v4\dev10_804810\dev10_804810\*" >
<Issue>636</Issue> <Issue>636</Issue>
</ExcludeList> </ExcludeList>
@ -1755,12 +1767,6 @@
<ExcludeList Include="$(XunitTestBinBase)\JIT\Regression\VS-ia64-JIT\M00\b112982\b112982\*" > <ExcludeList Include="$(XunitTestBinBase)\JIT\Regression\VS-ia64-JIT\M00\b112982\b112982\*" >
<Issue>13</Issue> <Issue>13</Issue>
</ExcludeList> </ExcludeList>
<ExcludeList Include="$(XunitTestBinBase)\JIT\Directed\StrAccess\straccess3_cs_ro\*" >
<Issue>13</Issue>
</ExcludeList>
<ExcludeList Include="$(XunitTestBinBase)\JIT\Directed\StrAccess\straccess3_cs_do\*" >
<Issue>13</Issue>
</ExcludeList>
<ExcludeList Include="$(XunitTestBinBase)\JIT\Methodical\MDArray\basics\structarr_cs_do\*" > <ExcludeList Include="$(XunitTestBinBase)\JIT\Methodical\MDArray\basics\structarr_cs_do\*" >
<Issue>13</Issue> <Issue>13</Issue>
</ExcludeList> </ExcludeList>
@ -3432,9 +3438,6 @@
<ExcludeList Include="$(XunitTestBinBase)\JIT\Methodical\int64\signed\_il_rels_ldsfld_mulovf\*" > <ExcludeList Include="$(XunitTestBinBase)\JIT\Methodical\int64\signed\_il_rels_ldsfld_mulovf\*" >
<Issue>13</Issue> <Issue>13</Issue>
</ExcludeList> </ExcludeList>
<ExcludeList Include="$(XunitTestBinBase)\JIT\Methodical\casts\SEH\_relthrow\*" >
<Issue>13</Issue>
</ExcludeList>
<ExcludeList Include="$(XunitTestBinBase)\JIT\Methodical\int64\unsigned\_reladdsub\*" > <ExcludeList Include="$(XunitTestBinBase)\JIT\Methodical\int64\unsigned\_reladdsub\*" >
<Issue>13</Issue> <Issue>13</Issue>
</ExcludeList> </ExcludeList>
@ -3759,9 +3762,6 @@
<ExcludeList Include="$(XunitTestBinBase)\JIT\Methodical\casts\iface\_il_dbgiface2\*" > <ExcludeList Include="$(XunitTestBinBase)\JIT\Methodical\casts\iface\_il_dbgiface2\*" >
<Issue>13</Issue> <Issue>13</Issue>
</ExcludeList> </ExcludeList>
<ExcludeList Include="$(XunitTestBinBase)\JIT\Directed\StrAccess\straccess3_cs_r\*" >
<Issue>13</Issue>
</ExcludeList>
<ExcludeList Include="$(XunitTestBinBase)\JIT\Methodical\int64\unsigned\_il_dbgldfld_mulovf\*" > <ExcludeList Include="$(XunitTestBinBase)\JIT\Methodical\int64\unsigned\_il_dbgldfld_mulovf\*" >
<Issue>13</Issue> <Issue>13</Issue>
</ExcludeList> </ExcludeList>