mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-12 13:30:51 +00:00
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:
parent
b2e18600c0
commit
cf26d7ccac
@ -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's hardwired for one filter per function.</li></p>
|
||||
|
||||
<li><p>Testing/Testing/Testing.</li></p>
|
||||
|
||||
</ol>
|
||||
|
@ -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----------------===//
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user