Extend eh.selector to support both catches and filters.

Drop the eh.filter intrinsic.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@37875 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Duncan Sands 2007-07-04 20:52:51 +00:00
parent b2e18600c0
commit cf26d7ccac
4 changed files with 84 additions and 84 deletions

View File

@ -29,7 +29,6 @@
<ol>
<li><a href="#llvm_eh_exception"><tt>llvm.eh.exception</tt></a></li>
<li><a href="#llvm_eh_selector"><tt>llvm.eh.selector</tt></a></li>
<li><a href="#llvm_eh_filter"><tt>llvm.eh.filter</tt></a></li>
<li><a href="#llvm_eh_typeid_for"><tt>llvm.eh.typeid.for</tt></a></li>
</ol></li>
<li><a href="#asm">Asm Table Formats</a>
@ -212,13 +211,18 @@ further use in the landing pad and catch code.</p>
<p><a href="#llvm_eh_selector"><tt>llvm.eh.selector</tt></a> takes a minimum of
three arguments. The first argument is the reference to the exception
structure. The second argument is a reference to the personality function to be
used for this try catch sequence. The remaining arguments are references to the
type infos for each of the catch statements in the order they should be tested.
used for this try catch sequence. Each of the remaining arguments is either a
reference to the type info for a catch statement, or a non-negative integer
followed by that many type info references, representing a
<a href="#throw_filters">filter</a>.
The exception is tested against the arguments sequentially from first to last.
The <i>catch all</i> (...) is represented with a <tt>null i8*</tt>. The result
of the <a href="#llvm_eh_selector"><tt>llvm.eh.selector</tt></a> is the index of
the type info in the corresponding exception table. The LLVM C++ front end
generates code to save this value in an alloca location for further use in the
landing pad and catch code.</p>
of the <a href="#llvm_eh_selector"><tt>llvm.eh.selector</tt></a> is a positive
number if the exception matched a type info, a negative number if it matched a
filter, and zero if it didn't match anything. If a type info matched then the
returned value is the index of the type info in the exception table.
The LLVM C++ front end generates code to save this value in an alloca location
for further use in the landing pad and catch code.</p>
<p>Once the landing pad has the type info selector, the code branches to the
code for the first catch. The catch then checks the value of the type info
@ -268,12 +272,12 @@ constructor), there may be several landing pads for a given try.</p>
<p>C++ allows the specification of which exception types that can be thrown from
a function. To represent this a top level landing pad may exist to filter out
invalid types. To express this in LLVM code the landing pad will call <a
href="#llvm_eh_filter"><tt>llvm.eh.filter</tt></a> instead of <a
href="#llvm_eh_selector"><tt>llvm.eh.selector</tt></a>. The arguments are the
same, but what gets created in the exception table is different. <a
href="#llvm_eh_filter"><tt>llvm.eh.filter</tt></a> will return a negative value
if it doesn't find a match. If no match is found then a call to
<tt>__cxa_call_unexpected</tt> should be made, otherwise
number of different type infos the function may throw, followed by the type
infos themselves.
<a href="#llvm_eh_selector"><tt>llvm.eh.selector</tt></a> will return a negative
value if the exception does not match any of the type infos. If no match is
found then a call to <tt>__cxa_call_unexpected</tt> should be made, otherwise
<tt>_Unwind_Resume</tt>. Each of these functions require a reference to the
exception structure.</p>
@ -326,32 +330,16 @@ exception selector.</p>
<p><a href="#llvm_eh_selector"><tt>llvm.eh.selector</tt></a> takes a minimum of
three arguments. The first argument is the reference to the exception
structure. The second argument is a reference to the personality function to be
used for this try catch sequence. The remaining arguments are references to the
type infos for each of the catch statements in the order they should be tested.
The <i>catch all</i> (...) is represented with a <tt>null i8*</tt>.</p>
</div>
<!-- ======================================================================= -->
<div class="doc_subsubsection">
<a name="llvm_eh_filter">llvm.eh.filter</a>
</div>
<div class="doc_text">
<pre>
i32 %<a href="#llvm_eh_filter">llvm.eh.filter</a>(i8*, i8*, i8*, ...)
</pre>
<p>This intrinsic indicates that the exception selector is available at this
point in the code. The backend will replace this intrinsic with code to fetch
the second argument of a call. The effect is that the intrinsic result is the
exception selector.</p>
<p><a href="#llvm_eh_filter"><tt>llvm.eh.filter</tt></a> takes a minimum of
three arguments. The first argument is the reference to the exception
structure. The second argument is a reference to the personality function to be
used for this function. The remaining arguments are references to the type infos
for each type that can be thrown by the current function.</p>
used for this try catch sequence. Each of the remaining arguments is either a
reference to the type info for a catch statement, or a non-negative integer
followed by that many type info references, representing a
<a href="#throw_filters">filter</a>.
The exception is tested against the arguments sequentially from first to last.
The <i>catch all</i> (...) is represented with a <tt>null i8*</tt>. The result
of the <a href="#llvm_eh_selector"><tt>llvm.eh.selector</tt></a> is a positive
number if the exception matched a type info, a negative number if it matched a
filter, and zero if it didn't match anything. If a type info matched then the
returned value is the index of the type info in the exception table.</p>
</div>
@ -427,15 +415,6 @@ only calls to non-throwing functions will not need an exception table.</p>
<ol>
<li><p>Need to create landing pads for code in between explicit landing pads.
The landing pads will have a zero action and a NULL landing pad address and are
used to inform the runtime that the exception should be rethrown.</li></p>
<li><p>Actions for a given function should be folded to save space.</p></li>
<li><p>Filters for inlined functions need to be handled more extensively.
Currently it&apos;s hardwired for one filter per function.</li></p>
<li><p>Testing/Testing/Testing.</li></p>
</ol>

View File

@ -231,8 +231,6 @@ def int_dbg_declare : Intrinsic<[llvm_void_ty, llvm_descriptor_ty,
def int_eh_exception : Intrinsic<[llvm_ptr_ty]>;
def int_eh_selector : Intrinsic<[llvm_i32_ty, llvm_ptr_ty, llvm_ptr_ty,
llvm_vararg_ty]>;
def int_eh_filter : Intrinsic<[llvm_i32_ty, llvm_ptr_ty, llvm_ptr_ty,
llvm_vararg_ty]>;
def int_eh_typeid_for : Intrinsic<[llvm_i32_ty, llvm_ptr_ty]>;
//===---------------- Generic Variable Attribute Intrinsics----------------===//

View File

@ -708,7 +708,6 @@ void IntrinsicLowering::LowerIntrinsicCall(CallInst *CI) {
case Intrinsic::dbg_declare:
case Intrinsic::eh_exception:
case Intrinsic::eh_selector:
case Intrinsic::eh_filter:
break; // Simply strip out debugging and eh intrinsics
case Intrinsic::var_annotation:

View File

@ -205,12 +205,11 @@ namespace llvm {
};
}
/// isFilterOrSelector - Return true if this instruction is a call to the
/// eh.filter or the eh.selector intrinsic.
static bool isFilterOrSelector(Instruction *I) {
/// isSelector - Return true if this instruction is a call to the
/// eh.selector intrinsic.
static bool isSelector(Instruction *I) {
if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(I))
return II->getIntrinsicID() == Intrinsic::eh_selector
|| II->getIntrinsicID() == Intrinsic::eh_filter;
return II->getIntrinsicID() == Intrinsic::eh_selector;
return false;
}
@ -2293,12 +2292,12 @@ void SelectionDAGLowering::visitTargetIntrinsic(CallInst &I,
}
}
/// ExtractGlobalVariable - If C is a global variable, or a bitcast of one
/// ExtractGlobalVariable - If V is a global variable, or a bitcast of one
/// (possibly constant folded), return it. Otherwise return NULL.
static GlobalVariable *ExtractGlobalVariable (Constant *C) {
if (GlobalVariable *GV = dyn_cast<GlobalVariable>(C))
static GlobalVariable *ExtractGlobalVariable (Value *V) {
if (GlobalVariable *GV = dyn_cast<GlobalVariable>(V))
return GV;
else if (ConstantExpr *CE = dyn_cast<ConstantExpr>(C)) {
else if (ConstantExpr *CE = dyn_cast<ConstantExpr>(V)) {
if (CE->getOpcode() == Instruction::BitCast)
return dyn_cast<GlobalVariable>(CE->getOperand(0));
else if (CE->getOpcode() == Instruction::GetElementPtr) {
@ -2311,8 +2310,16 @@ static GlobalVariable *ExtractGlobalVariable (Constant *C) {
return NULL;
}
/// ExtractTypeInfo - Extracts the type info from a value.
static GlobalVariable *ExtractTypeInfo (Value *V) {
GlobalVariable *GV = ExtractGlobalVariable(V);
assert (GV || isa<ConstantPointerNull>(V) &&
"TypeInfo must be a global variable or NULL");
return GV;
}
/// addCatchInfo - Extract the personality and type infos from an eh.selector
/// or eh.filter call, and add them to the specified machine basic block.
/// call, and add them to the specified machine basic block.
static void addCatchInfo(CallInst &I, MachineModuleInfo *MMI,
MachineBasicBlock *MBB) {
// Inform the MachineModuleInfo of the personality for this landing pad.
@ -2325,17 +2332,38 @@ static void addCatchInfo(CallInst &I, MachineModuleInfo *MMI,
// Gather all the type infos for this landing pad and pass them along to
// MachineModuleInfo.
std::vector<GlobalVariable *> TyInfo;
for (unsigned i = 3, N = I.getNumOperands(); i < N; ++i) {
Constant *C = cast<Constant>(I.getOperand(i));
GlobalVariable *GV = ExtractGlobalVariable(C);
assert (GV || isa<ConstantPointerNull>(C) &&
"TypeInfo must be a global variable or NULL");
TyInfo.push_back(GV);
unsigned N = I.getNumOperands();
for (unsigned i = N - 1; i > 2; --i) {
if (ConstantInt *CI = dyn_cast<ConstantInt>(I.getOperand(i))) {
unsigned FilterLength = CI->getZExtValue();
unsigned FirstCatch = i + FilterLength + 1;
assert (FirstCatch <= N && "Invalid filter length");
if (FirstCatch < N) {
TyInfo.reserve(N - FirstCatch);
for (unsigned j = FirstCatch; j < N; ++j)
TyInfo.push_back(ExtractTypeInfo(I.getOperand(j)));
MMI->addCatchTypeInfo(MBB, TyInfo);
TyInfo.clear();
}
TyInfo.reserve(FilterLength);
for (unsigned j = i + 1; j < FirstCatch; ++j)
TyInfo.push_back(ExtractTypeInfo(I.getOperand(j)));
MMI->addFilterTypeInfo(MBB, TyInfo);
TyInfo.clear();
N = i;
}
}
if (I.getCalledFunction()->getIntrinsicID() == Intrinsic::eh_filter)
MMI->addFilterTypeInfo(MBB, TyInfo);
else
if (N > 3) {
TyInfo.reserve(N - 3);
for (unsigned j = 3; j < N; ++j)
TyInfo.push_back(ExtractTypeInfo(I.getOperand(j)));
MMI->addCatchTypeInfo(MBB, TyInfo);
}
}
/// propagateEHRegister - The specified EH register is required in a successor
@ -2483,8 +2511,7 @@ SelectionDAGLowering::visitIntrinsicCall(CallInst &I, unsigned Intrinsic) {
return 0;
}
case Intrinsic::eh_selector:
case Intrinsic::eh_filter:{
case Intrinsic::eh_selector:{
MachineModuleInfo *MMI = DAG.getMachineModuleInfo();
if (ExceptionHandling && MMI) {
@ -2518,10 +2545,7 @@ SelectionDAGLowering::visitIntrinsicCall(CallInst &I, unsigned Intrinsic) {
if (MMI) {
// Find the type id for the given typeinfo.
Constant *C = cast<Constant>(I.getOperand(1));
GlobalVariable *GV = ExtractGlobalVariable(C);
assert (GV || isa<ConstantPointerNull>(C) &&
"TypeInfo must be a global variable or NULL");
GlobalVariable *GV = ExtractTypeInfo(I.getOperand(1));
unsigned TypeID = MMI->getTypeIDFor(GV);
setValue(&I, DAG.getConstant(TypeID, MVT::i32));
@ -4297,7 +4321,7 @@ static void copyCatchInfo(BasicBlock *SrcBB, BasicBlock *DestBB,
assert(!FLI.MBBMap[SrcBB]->isLandingPad() &&
"Copying catch info out of a landing pad!");
for (BasicBlock::iterator I = SrcBB->begin(), E = --SrcBB->end(); I != E; ++I)
if (isFilterOrSelector(I)) {
if (isSelector(I)) {
// Apply the catch info to DestBB.
addCatchInfo(cast<CallInst>(*I), MMI, FLI.MBBMap[DestBB]);
#ifndef NDEBUG
@ -4341,19 +4365,19 @@ void SelectionDAGISel::BuildSelectionDAG(SelectionDAG &DAG, BasicBlock *LLVMBB,
// function and list of typeids logically belong to the invoke (or, if you
// like, the basic block containing the invoke), and need to be associated
// with it in the dwarf exception handling tables. Currently however the
// information is provided by intrinsics (eh.filter and eh.selector) that
// can be moved to unexpected places by the optimizers: if the unwind edge
// is critical, then breaking it can result in the intrinsics being in the
// successor of the landing pad, not the landing pad itself. This results
// in exceptions not being caught because no typeids are associated with
// the invoke. This may not be the only way things can go wrong, but it
// is the only way we try to work around for the moment.
// information is provided by an intrinsic (eh.selector) that can be moved
// to unexpected places by the optimizers: if the unwind edge is critical,
// then breaking it can result in the intrinsics being in the successor of
// the landing pad, not the landing pad itself. This results in exceptions
// not being caught because no typeids are associated with the invoke.
// This may not be the only way things can go wrong, but it is the only way
// we try to work around for the moment.
BranchInst *Br = dyn_cast<BranchInst>(LLVMBB->getTerminator());
if (Br && Br->isUnconditional()) { // Critical edge?
BasicBlock::iterator I, E;
for (I = LLVMBB->begin(), E = --LLVMBB->end(); I != E; ++I)
if (isFilterOrSelector(I))
if (isSelector(I))
break;
if (I == E)