JITのllvmコード内に例外ハンドラを作成しようとしています。 exception handling in LLVMに関する最新のドキュメントは、現時点では非常に手を加えていますので、私は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
このスロー関数が呼び出されることを示し、それがスローされますが、私はクリーンアップコールに上陸することはありません。 (私のクリーンアップコールは「C/C++のクリーンアップを呼び出すJITの内側に」言ったはず)
(試行)を呼び出し、関数がスローされた例外をキャッチすることです:
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;
}
これは、通常のビジネスのように呼び出されます
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;
}
と私のクリーンアップ:スロー私の関数である
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 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に関する最近の例外処理の変更を読んで、しかし、あなたは知っている、これらの変更は、実際に変換する方法は明らかではない、コード
素晴らしいですが、新しいアプローチを使用していくつかの例を指してもいいですか、私はこの記事を読んでいます:http://lists.cs.uiuc.edu/pipermail/llvmdev/2011-July/041768.htmlしかし、私は何をすべきかわからない – lurscher
ehドキュメントは書き直されているので、正確でなければなりません。もう一つの選択肢は、clangの出力を見て、どのように見えるかを知ることです。 – echristo