Nicolas Geoffray wrote:> Hi Talin, > > You're not using the llvm intrinsics for exception handling, so your > code won't work. Using _Unwind_RaiseException should be OK, but your > main function must at least use llvm.eh.exception, > llvm.eh.selector.i32/64 and probably __cxa_begin_catch and __cxa_end_catch. >Let me ask a follow-up question then - if the llvm.eh.* intrinsics are required to define the landing pad, then what is the role of the "unwind" target in the invoke instruction? According to the docs, the unwind target defines where execution will jump to when the called function returns with an exception, but clearly that isn't true - the flow of control passes directly to the personality function, bypassing the unwind target completely (as far as I can tell). By using the llvm.eh* intrinsics, I have managed to get the code to call my custom personality function without crashing. However, what I don't yet understand is how to get the result from the personality function back to the landing pad. For example, I could use the function _Unwind_SetIP to tell it where to jump to, except that I can't take the address of a label in LLVM. I could call _Unwind_SetGR to set an index and then have a switch in the landing pad that uses that index - except that I would have no way to determine which register is safe to set in a platform-independent way. I could even just have the personality function do nothing at all, and have the landing pad do all the work - except that if my personality function doesn't do anything, then the landing pad is skipped entirely, and control resumes at the non-unwind target of the original invoke instruction, as if no exception had been thrown at all.> Nicolas > > > Talin wrote: > >> I've been struggling for several days, trying to get native exceptions >> to work in my code. I managed to boil down the IR to the simplest >> possible example that I can think of. >> >> If anyone on this list can tell me what changes I need to make to the >> following code to get it to work (i.e. return 0 instead of a bus >> error), it would make my life immensely better. >> >> ; ModuleID = 'ExceptionTest' >> %Object = type {} >> %UnwindInfo = type { i64, void (i32, %UnwindInfo *)*, i16, i16 } >> %Throwable = type { %Object, %UnwindInfo } >> >> define i32 @main(i32, i8**) nounwind { >> entry: >> invoke fastcc void @throwSomething() to label %nounwind unwind >> label %catch >> >> catch: >> ret i32 0 >> >> nounwind: >> ret i32 -1 >> } >> >> define internal fastcc void @throwSomething() noreturn { >> entry: >> %throwable = malloc %Throwable >> call fastcc void @Throwable.construct(%Throwable* %throwable) >> %unwindInfo = getelementptr %Throwable* %throwable, i32 0, i32 1 >> %throw = call i32 @_Unwind_RaiseException(%UnwindInfo* >> %unwindInfo) >> unreachable >> } >> >> define internal fastcc void @Throwable.construct(%Throwable* %self) >> nounwind { >> entry: >> %exceptionClass = getelementptr %Throwable* %self, i32 0, i32 1, >> i32 0 >> store i64 0, i64* %exceptionClass >> %exceptionCleanup = getelementptr %Throwable* %self, i32 0, i32 >> 1, i32 1 >> store void (i32, %UnwindInfo *)* @exceptionCleanupFn, void (i32, >> %UnwindInfo *)** %exceptionCleanup >> %private1 = getelementptr %Throwable* %self, i32 0, i32 1, i32 2 >> store i16 0, i16* %private1 >> %private2 = getelementptr %Throwable* %self, i32 0, i32 1, i32 3 >> store i16 0, i16* %private2 >> ret void >> } >> >> define internal void @exceptionCleanupFn(i32 %reason, %UnwindInfo * >> %exc) { >> ret void >> } >> >> declare i32 @_Unwind_RaiseException(%UnwindInfo*) noreturn >> >> -- Talin >> >> ------------------------------------------------------------------------ >> >> _______________________________________________ >> LLVM Developers mailing list >> LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu >> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev >> > > _______________________________________________ > LLVM Developers mailing list > LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev > >
Hello, Talin> By using the llvm.eh* intrinsics, I have managed to get the code to call > my custom personality function without crashing. However, what I don't > yet understand is how to get the result from the personality function > back to the landing pad.You might find this useful: http://www.codesourcery.com/public/cxx-abi/abi-eh.html#cxx-catch -- With best regards, Anton Korobeynikov Faculty of Mathematics and Mechanics, Saint Petersburg State University
Anton Korobeynikov wrote:> Hello, Talin > > >> By using the llvm.eh* intrinsics, I have managed to get the code to call >> my custom personality function without crashing. However, what I don't >> yet understand is how to get the result from the personality function >> back to the landing pad. >> > You might find this useful: > http://www.codesourcery.com/public/cxx-abi/abi-eh.html#cxx-catch >I've been reading that. But what's not clear is how to translate that into LLVM-speak. For example, what value would you pass to _Unwind_SetIP? -- Talin
Talin wrote:> Nicolas Geoffray wrote: >> Hi Talin, >> >> You're not using the llvm intrinsics for exception handling, so your >> code won't work. Using _Unwind_RaiseException should be OK, but your >> main function must at least use llvm.eh.exception, >> llvm.eh.selector.i32/64 and probably __cxa_begin_catch and __cxa_end_catch. >> > Let me ask a follow-up question then - if the llvm.eh.* intrinsics are > required to define the landing pad, then what is the role of the > "unwind" target in the invoke instruction?They are not required to define a landing pad. They are currently required by the code generators. The interpreter works fine without them for example. The current design is pretty horrible: the dwarf eh intrinsics were tacked on to the pre-existing invoke-unwind scheme, and it shows. Anyway, I plan to teach the code generators that if no personality function was specified then it should use the C personality function (yes, there is one). This is probably good enough for simple cases such as running cleanups. According to the docs, the> unwind target defines where execution will jump to when the called > function returns with an exception, but clearly that isn't true - the > flow of control passes directly to the personality function, bypassing > the unwind target completely (as far as I can tell).The language description describes how it is supposed to work. It simply hasn't been implemented yet in the code generator. Obviously some code is necessarily executed by the run-time when an exception is thrown, to unwind the stack etc. You should think of the personality function as part of the runtime.> By using the llvm.eh* intrinsics, I have managed to get the code to call > my custom personality function without crashing. However, what I don't > yet understand is how to get the result from the personality function > back to the landing pad. For example, I could use the function > _Unwind_SetIP to tell it where to jump to, except that I can't take the > address of a label in LLVM. I could call _Unwind_SetGR to set an index > and then have a switch in the landing pad that uses that index - except > that I would have no way to determine which register is safe to set in a > platform-independent way. I could even just have the personality > function do nothing at all, and have the landing pad do all the work - > except that if my personality function doesn't do anything, then the > landing pad is skipped entirely, and control resumes at the non-unwind > target of the original invoke instruction, as if no exception had been > thrown at all.I would just use the C personality function, __gcc_personality_v0, if I were you. It should know where to jump to because the code generators record the invoke unwind target in the dwarf exception handling info in the object file. Ciao, Duncan.>> Nicolas >> >> >> Talin wrote: >> >>> I've been struggling for several days, trying to get native exceptions >>> to work in my code. I managed to boil down the IR to the simplest >>> possible example that I can think of. >>> >>> If anyone on this list can tell me what changes I need to make to the >>> following code to get it to work (i.e. return 0 instead of a bus >>> error), it would make my life immensely better. >>> >>> ; ModuleID = 'ExceptionTest' >>> %Object = type {} >>> %UnwindInfo = type { i64, void (i32, %UnwindInfo *)*, i16, i16 } >>> %Throwable = type { %Object, %UnwindInfo } >>> >>> define i32 @main(i32, i8**) nounwind { >>> entry: >>> invoke fastcc void @throwSomething() to label %nounwind unwind >>> label %catch >>> >>> catch: >>> ret i32 0 >>> >>> nounwind: >>> ret i32 -1 >>> } >>> >>> define internal fastcc void @throwSomething() noreturn { >>> entry: >>> %throwable = malloc %Throwable >>> call fastcc void @Throwable.construct(%Throwable* %throwable) >>> %unwindInfo = getelementptr %Throwable* %throwable, i32 0, i32 1 >>> %throw = call i32 @_Unwind_RaiseException(%UnwindInfo* >>> %unwindInfo) >>> unreachable >>> } >>> >>> define internal fastcc void @Throwable.construct(%Throwable* %self) >>> nounwind { >>> entry: >>> %exceptionClass = getelementptr %Throwable* %self, i32 0, i32 1, >>> i32 0 >>> store i64 0, i64* %exceptionClass >>> %exceptionCleanup = getelementptr %Throwable* %self, i32 0, i32 >>> 1, i32 1 >>> store void (i32, %UnwindInfo *)* @exceptionCleanupFn, void (i32, >>> %UnwindInfo *)** %exceptionCleanup >>> %private1 = getelementptr %Throwable* %self, i32 0, i32 1, i32 2 >>> store i16 0, i16* %private1 >>> %private2 = getelementptr %Throwable* %self, i32 0, i32 1, i32 3 >>> store i16 0, i16* %private2 >>> ret void >>> } >>> >>> define internal void @exceptionCleanupFn(i32 %reason, %UnwindInfo * >>> %exc) { >>> ret void >>> } >>> >>> declare i32 @_Unwind_RaiseException(%UnwindInfo*) noreturn >>> >>> -- Talin >>> >>> ------------------------------------------------------------------------ >>> >>> _______________________________________________ >>> LLVM Developers mailing list >>> LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu >>> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev >>> >> _______________________________________________ >> LLVM Developers mailing list >> LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu >> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev >> >> > > _______________________________________________ > LLVM Developers mailing list > LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
Duncan Sands wrote:> I would just use the C personality function, __gcc_personality_v0, if > I were you. It should know where to jump to because the code generators > record the invoke unwind target in the dwarf exception handling info in > the object file. > >I see. OK, I will try that. I was hoping to be able to test the exception type in the personality function - the language I am working on has its own type system, unrelated to C or C++, so I want to minimize reliance on C++ exception handling libraries. In this case, I guess I can do the exception type checking in the landing pad instead of the personality function. -- Talin
Duncan Sands wrote:> I would just use the C personality function, __gcc_personality_v0, if > I were you. It should know where to jump to because the code generators > record the invoke unwind target in the dwarf exception handling info in > the object file. > >So I tried what you suggested, and it just gives me a bus error: define i32 @main(i32, i8**) nounwind { entry: call void @print(i8* bitcast ([6 x i8]* @str_begin to i8 *)) invoke fastcc void @throwSomething() to label %nounwind unwind label %catch; catch: %eh_ptr = call i8* @llvm.eh.exception(); %eh_select34 = call i32 (i8*, i8*, ...)* @llvm.eh.selector.i32 ( i8* %eh_ptr, i8* bitcast (i32 (i32, i32, i64, i8*, %UnwindContext*)* @__gcc_personality_v0 to i8*), i32 1) call void @print(i8* bitcast ([6 x i8]* @str_catch to i8 *)) ret i32 0 nounwind: call void @print(i8* bitcast ([8 x i8]* @str_nocatch to i8 *)) ret i32 -1 } However, when I use my own personality function instead of __gcc_personality_v0, it doesn't crash, but it doesn't work right either (for reasons we've already discussed - it doesn't know how to redirect the execution to the landing pad): @str_persn = internal constant [10 x i8] c"persn %d\0a\00" define i32 @personality_func(i32 %version, i32 %action, i64 %eh_class, i8* %eh_ptr, %UnwindContext* %eh_context) nounwind { call void (i8*, ...)* @printf(i8* bitcast ([10 x i8]* @str_persn to i8*), i32 %action) %phase = icmp eq i32 %action, 1 br i1 %phase, label %search, label %handler search: ret i32 6 handler: call void @_Unwind_SetIP(%UnwindContext* %eh_context, i8* %cc0) ret i32 7 } -- Talin