2011-09-27 3 views
5

JIT llvm 코드 내에 예외 처리기를 만들려고합니다. exception handling in LLVM 관한 현재 문서는 매우 handwavy 순간에, 그래서 난 예제 코드를 얻으려면 http://llvm.org/demo에서 얻을 대부분의 조각을 재사용하려고 노력하고있어,하지만 난 그게 최신의 llvm 함께 있는지 모르겠다. 2.9 (내가 사용하고있는 버전). 이 모듈은 Module :: dump(); 내가 기능을 실행하려고 할 때llvm 예외; catch 처리기가 처리되지 않음, 정리가 호출되지 않음

; ModuleID = 'testModule' 

declare i32 @myfunc() 

define i32 @test_function_that_invokes_another() { 
entryBlock: 
    %0 = alloca i8* 
    %1 = alloca i32 
    %someName = invoke i32 @myfunc() 
      to label %exitBlock unwind label %unwindBlock 

exitBlock:          ; preds = %entryBlock 
    ret i32 1 

unwindBlock:          ; preds = %entryBlock 
    %2 = call i8* @llvm.eh.exception() 
    store i8* %2, i8** %0 
    %3 = call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* %2, i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i8* null) 
    store i32 1, i32* %1 
    %4 = load i8** %0 
    %5 = call i32 (...)* @__cxa_begin_catch(i8* %4) nounwind 
    %cleanup_call = call i32 @myCleanup() 
    %6 = call i32 (...)* @__cxa_end_catch() 
    ret i32 1 
} 

declare i32 @__gxx_personality_v0(...) 

declare i32 @__cxa_begin_catch(...) 

declare i32 @__cxa_end_catch(...) 

declare i8* @llvm.eh.exception() nounwind readonly 

declare i32 @llvm.eh.selector(i8*, i8*, ...) nounwind 

declare i32 @myCleanup() 

는이 발생 무엇 :

inside JIT calling C/C++ call 
terminate called after throwing an instance of 'int' 
Aborted 

이 발생 함수가이 발생, 호출되는 것을 보여줍니다,하지만 난 정리 호출에 착륙하지 않았다.

const inline llvm::FunctionType* getTestFunctionSignature(llvm::LLVMContext& context) { 
      return llvm::TypeBuilder< unsigned int(), false > ::get(context); 
     } 

llvm::Function* createFunctionThatInvokesAnother(llvm::LLVMContext& ctx, llvm::Module* mod , llvm::Function* another) { 
    llvm::Function* result = llvm::Function::Create(getTestFunctionSignature(ctx), 
          llvm::GlobalValue::ExternalLinkage, 
          "test_function_that_invokes_another", 
          mod); 
    llvm::BasicBlock* entry_block = llvm::BasicBlock::Create(ctx, "entryBlock", result); 
    llvm::BasicBlock* exit_block = llvm::BasicBlock::Create(ctx, "exitBlock", result); 
    llvm::BasicBlock* unwind_block = llvm::BasicBlock::Create(ctx, "unwindBlock", result); 
    llvm::IRBuilder<> builder(entry_block); 
    llvm::ConstantInt* ci = llvm::ConstantInt::get(mod->getContext() , llvm::APInt(32 , llvm::StringRef("1"), 10)); 
    llvm::PointerType* pty3 = llvm::PointerType::get(llvm::IntegerType::get(mod->getContext(), 8), 0); 
    llvm::AllocaInst* ptr_24 = new llvm::AllocaInst(pty3, "", entry_block); 
    llvm::AllocaInst* ptr_25 = new llvm::AllocaInst(llvm::IntegerType::get(mod->getContext(), 32), "", entry_block); 
    llvm::Twine name("someName"); 
    builder.CreateInvoke(another , exit_block , unwind_block , "someName"); 

    builder.SetInsertPoint(exit_block); 
    builder.CreateRet(ci); 

    builder.SetInsertPoint(unwind_block); 
    llvm::Function* func___gxx_personality_v0 = func__gxx_personality_v0(mod); 
    llvm::Function* func___cxa_begin_catch = func__cxa_begin_catch(mod); 
    llvm::Function* func___cxa_end_catch = func__cxa_end_catch(mod); 
    llvm::Function* func_eh_ex = func_llvm_eh_exception(mod); 
    llvm::Function* func_eh_sel = func__llvm_eh_selector(mod); 
    llvm::Constant* const_ptr_17 = llvm::ConstantExpr::getCast(llvm::Instruction::BitCast, func___gxx_personality_v0, pty3); 
    llvm::ConstantPointerNull* const_ptr_18 = llvm::ConstantPointerNull::get(pty3); 

    llvm::CallInst* get_ex = llvm::CallInst::Create(func_eh_ex, "", unwind_block); 
    get_ex->setCallingConv(llvm::CallingConv::C); 
    get_ex->setTailCall(false); 
    new llvm::StoreInst(get_ex, ptr_24, false, unwind_block); 

    std::vector<llvm::Value*> int32_37_params; 
    int32_37_params.push_back(get_ex); 
    int32_37_params.push_back(const_ptr_17); 
    int32_37_params.push_back(const_ptr_18); 
    llvm::CallInst* eh_sel = llvm::CallInst::Create(func_eh_sel, int32_37_params.begin(), int32_37_params.end(), "", unwind_block); 
    eh_sel->setCallingConv(llvm::CallingConv::C); 
    eh_sel->setTailCall(false); 
    new llvm::StoreInst(ci, ptr_25, false, unwind_block); 

    llvm::LoadInst* ptr_29 = new llvm::LoadInst(ptr_24, "", false, unwind_block); 
    llvm::CallInst* ptr_30 = llvm::CallInst::Create(func___cxa_begin_catch, ptr_29, "", unwind_block); 
    ptr_30->setCallingConv(llvm::CallingConv::C); 
    ptr_30->setTailCall(false); 
    llvm::AttrListPtr ptr_30_PAL; 
    { 
     llvm::SmallVector<llvm::AttributeWithIndex, 4 > Attrs; 
     llvm::AttributeWithIndex PAWI; 
     PAWI.Index = 4294967295U; 
     PAWI.Attrs = 0 | llvm::Attribute::NoUnwind; 
     Attrs.push_back(PAWI); 
     ptr_30_PAL = llvm::AttrListPtr::get(Attrs.begin(), Attrs.end()); 

    } 
    ptr_30->setAttributes(ptr_30_PAL); 
    llvm::Function* cleanup = call_myCleanup(mod); 
    builder.CreateCall(cleanup , "cleanup_call"); 
    llvm::CallInst* end_catch = llvm::CallInst::Create(func___cxa_end_catch, "", unwind_block); 
    builder.CreateRet(ci); 
    //createCatchHandler(mod , unwind_block); 
    return result; 
} 

이것은 일반적인 사업과 같이 호출됩니다 :

호출하고이 함수는 (시도)가 발생한 예외가 잡으려고 (내 정리 호출은 'JIT 호출 C/C++ 정리 내부에'말했다한다) :

발생 제 기능을
testMain() { 
llvm::LLVMContext ctx; 
    llvm::InitializeNativeTarget(); 
    llvm::StringRef idRef("testModule"); 
    llvm::Module* module = new llvm::Module(idRef, ctx); 
    std::string jitErrorString; 
    llvm::ExecutionEngine* execEngine = executionEngine(module , jitErrorString); 
    llvm::FunctionPassManager* OurFPM = new llvm::FunctionPassManager(module); 

llvm::Function *thr = call_my_func_that_throws(module); 
    llvm::Function* result = createFunctionThatInvokesAnother(ctx, module ,thr); 


    std::string errorInfo; 
    llvm::verifyModule(* module, llvm::PrintMessageAction, & errorInfo); 
    module->dump(); 


    void *fptr = execEngine->getPointerToFunction(result); 
    unsigned int (*fp)() = (unsigned int (*)())fptr; 
    try { 
    unsigned int value = fp(); 
    } catch (...) { 
     std::cout << " handled a throw from JIT function" << std::endl; 
    } 
} 

입니다 :

int myfunc() { 
    std::cout << " inside JIT calling C/C++ call" << std::endl; 
    throw 0; 
}; 

llvm::Function* call_my_func_that_throws (llvm::Module* mod) { 
    std::vector< const llvm::Type* > FuncTy_ex_args; 
    llvm::FunctionType* FuncTy_ex = llvm::FunctionType::get(llvm::IntegerType::get(mod->getContext() , 32) , FuncTy_ex_args , false); 
    llvm::Function* result = llvm::Function::Create(FuncTy_ex, llvm::GlobalValue::ExternalLinkage, "myfunc", mod); 
    result->setCallingConv(llvm::CallingConv::C); 
    llvm::AttrListPtr PAL; 
    result->setAttributes(PAL); 
    llvm::sys::DynamicLibrary::AddSymbol("myfunc" , (void*) &myfunc); 
    return result; 
} 

내 정리 기능이 유사한 방법으로 정의된다 : 이러한 변경 사항이 실제로 변환하는 방법


int myCleanup() { 
    std::cout << " inside JIT calling C/C++ Cleanup" << std::endl; 
    return 18; 
}; 

llvm::Function* call_myCleanup (llvm::Module* mod) { 
    std::vector< const llvm::Type* > FuncTy_ex_args; 
    llvm::FunctionType* FuncTy_ex = llvm::FunctionType::get(llvm::IntegerType::get(mod->getContext() , 32) , FuncTy_ex_args , false); 
    llvm::Function* result = llvm::Function::Create(FuncTy_ex, llvm::GlobalValue::ExternalLinkage, "myCleanup", mod); 
    result->setCallingConv(llvm::CallingConv::C); 
    llvm::AttrListPtr PAL; 
    result->setAttributes(PAL); 
    llvm::sys::DynamicLibrary::AddSymbol("myCleanup" , (void*) &myCleanup); 
    return result; 
} 
가 나는 또한 LLVM 최근의 예외 처리 변경에 대한 this document을 읽었습니다,하지만 확실하지 않습니다, 당신은

답변

2
코드, 알고

지금 EH 코드가 많은 수정을 받고 있습니다. 데모 버전은 2.9 버전이 아니지만 현재 개발 소스입니다. 2.9 버전으로 무언가를하려고 할 때 의미하는 것은 상상의 세계가 될 것입니다.

즉, EH 표현은 훨씬 나아졌으며 이번 주에 문서를 개선하기 위해 수많은 패치가 도입되었습니다. llvm을 통해 예외를 사용하는 언어를 작성하려는 경우 코드를 현재 개발 소스로 마이그레이션하는 것이 좋습니다.

이 모든 것이 JIT에서 예외 처리가 얼마나 잘 작동하는지 잘 모르겠습니다. 명목상 지원되지만 메모리가 올바른지 확인하기 위해 unwind 테이블을 디버깅해야 할 수도 있습니다.

+0

우수한, 당신은 새로운 접근법을 사용하여 몇 가지 예를 가리킬 수 있습니까,이 게시물을 읽고 있었 : http://lists.cs.uiuc.edu/pipermail/llvmdev/2011-July/041768.html하지만 난 ' 무슨 일을해야할지 모르겠다. – lurscher

+0

eh 문서가 다시 작성되어 정확해야한다. 또 다른 옵션은 clang 출력을보고 어떻게 보이는지에 대한 아이디어를 얻는 것입니다. – echristo

관련 문제