From cf26d7ccac1ad052b750edec36b13bc9ea8f70d7 Mon Sep 17 00:00:00 2001 From: Duncan Sands Date: Wed, 4 Jul 2007 20:52:51 +0000 Subject: [PATCH] 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 --- docs/ExceptionHandling.html | 73 ++++++--------- include/llvm/Intrinsics.td | 2 - lib/CodeGen/IntrinsicLowering.cpp | 1 - lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp | 92 ++++++++++++------- 4 files changed, 84 insertions(+), 84 deletions(-) diff --git a/docs/ExceptionHandling.html b/docs/ExceptionHandling.html index 57b0c4d8488..d49a285ce84 100644 --- a/docs/ExceptionHandling.html +++ b/docs/ExceptionHandling.html @@ -29,7 +29,6 @@
  1. llvm.eh.exception
  2. llvm.eh.selector
  3. -
  4. llvm.eh.filter
  5. llvm.eh.typeid.for
  • Asm Table Formats @@ -212,13 +211,18 @@ further use in the landing pad and catch code.

    llvm.eh.selector 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 +filter. +The exception is tested against the arguments sequentially from first to last. The catch all (...) is represented with a null i8*. The result -of the llvm.eh.selector 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.

    +of the llvm.eh.selector 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.

    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.

    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 llvm.eh.filter instead of llvm.eh.selector. The arguments are the -same, but what gets created in the exception table is different. llvm.eh.filter will return a negative value -if it doesn't find a match. If no match is found then a call to -__cxa_call_unexpected should be made, otherwise +number of different type infos the function may throw, followed by the type +infos themselves. +llvm.eh.selector 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 __cxa_call_unexpected should be made, otherwise _Unwind_Resume. Each of these functions require a reference to the exception structure.

    @@ -326,32 +330,16 @@ exception selector.

    llvm.eh.selector 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 catch all (...) is represented with a null i8*.

    - - - - - - -
    -
    -  i32 %llvm.eh.filter(i8*, i8*, i8*, ...)
    -
    - -

    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.

    - -

    llvm.eh.filter 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.

    +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 +filter. +The exception is tested against the arguments sequentially from first to last. +The catch all (...) is represented with a null i8*. The result +of the llvm.eh.selector 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.

    @@ -427,15 +415,6 @@ only calls to non-throwing functions will not need an exception table.

      -
    1. 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.

    2. - -
    3. Actions for a given function should be folded to save space.

    4. - -
    5. Filters for inlined functions need to be handled more extensively. -Currently it's hardwired for one filter per function.

    6. -
    7. Testing/Testing/Testing.

    diff --git a/include/llvm/Intrinsics.td b/include/llvm/Intrinsics.td index 0f9ef6a76fa..df3afde9ed2 100644 --- a/include/llvm/Intrinsics.td +++ b/include/llvm/Intrinsics.td @@ -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----------------===// diff --git a/lib/CodeGen/IntrinsicLowering.cpp b/lib/CodeGen/IntrinsicLowering.cpp index 24ed4d3405d..1e811d61e7c 100644 --- a/lib/CodeGen/IntrinsicLowering.cpp +++ b/lib/CodeGen/IntrinsicLowering.cpp @@ -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: diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp index 4dadde0dfe5..720f6cae2eb 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -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(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(C)) +static GlobalVariable *ExtractGlobalVariable (Value *V) { + if (GlobalVariable *GV = dyn_cast(V)) return GV; - else if (ConstantExpr *CE = dyn_cast(C)) { + else if (ConstantExpr *CE = dyn_cast(V)) { if (CE->getOpcode() == Instruction::BitCast) return dyn_cast(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(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 TyInfo; - for (unsigned i = 3, N = I.getNumOperands(); i < N; ++i) { - Constant *C = cast(I.getOperand(i)); - GlobalVariable *GV = ExtractGlobalVariable(C); - assert (GV || isa(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(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(I.getOperand(1)); - GlobalVariable *GV = ExtractGlobalVariable(C); - assert (GV || isa(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(*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(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) -- 2.34.1