Hi, I'm trying to get exception handling working in my compiler targetting LLVM. I've been working from the LLVM exception handling documentation (including http://llvm.org/docs/ExceptionHandling.html and http://wiki.llvm.org/HowTo:_Build_JIT_based_Exception_mechanism) and looking at g++-llvm's output. I've been trying to get a minimal test function to work, which simply invokes _Unwind_RaiseException with a single clean-up landing pad. However. when I run it my personality function is not getting called - _Unwind_RaiseException simply returns apparently doing nothing. Looking at the x86-64 assembly output from llc, I can see this is happening because the personality function is not getting into the DWARF eh table (the landing pad is there though). I'm stumped as to why not. I'd be grateful if anyone can point out what I'm doing wrong here: define i32 @_ZN4N0014Main5test5EN2IO6WriterEiA_l(%6*, %4*, i32, %33*) { entry: %err = alloca %4* ; <%4**> [#uses=1] %count = alloca i32 ; <i32*> [#uses=1] %e = alloca %33* ; <%33**> [#uses=2] %this = alloca %6* ; <%6**> [#uses=1] %.ex_value = alloca i8* ; <i8**> [#uses=1] %.ex_value_l = alloca i8* ; <i8**> [#uses=0] %.ex_type = alloca i64 ; <i64*> [#uses=1] br label %4 ; <label>:4 ; preds = %entry store %6* %0, %6** %this store %4* %1, %4** %err store i32 %2, i32* %count store %33* %3, %33** %e br label %.try_body .try_body: ; preds = %4 %5 = load %33** %e ; <%33*> [#uses=1] %6 = getelementptr inbounds %33* %5, i32 0, i32 2, i32 0 ; <i64*> [#uses=1] %7 = invoke i8* (...)* bitcast (i32 (%struct._Unwind_Exception*)* @_Unwind_RaiseException to i8* (...)*)(i64* %6) to label %8 unwind label %.finally_pad ; <i8*> [#uses=0] ; <label>:8 ; preds = %.try_body br label %.finally_handler .finally_pad: ; preds = %.try_body %9 = call i8* @llvm.eh.exception() ; <i8*> [#uses=2] store i8* %9, i8** %.ex_value %10 = call i64 (i8*, i8*, ...)* @llvm.eh.selector.i64(i8* %9, i8* bitcast (i32 (i32, i32, i64, %struct._Unwind_Exception*, %struct._Unwind_Context*)* @__l_personality to i8*)) ; <i64> [#uses=1] %11 = icmp eq i64 %10, 0 ; <i1> [#uses=1] %12 = select i1 %11, i64 0, i64 1 ; <i64> [#uses=1] store i64 %12, i64* %.ex_type br label %.finally_handler .finally_handler: ; preds = %.finally_pad, %8 %13 = call i8* (...)* bitcast (i32 (i8*, ...)* @printf to i8* (...)*)(i8* getelementptr ([9 x i8]* @__string_27, i32 0, i32 0)) ; <i8*> [#uses=0] ret i32 0 } Thanks in advance, -- James Williams PS: Thanks to all LLVM contributers for such a well designed IR and code generation library. Switching my compiler from its existing back end to LLVM has so far been incredibly quick and easy - a matter of a few evenings and a couple of weekends! -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20100121/922d63d7/attachment.html>
On Jan 21, 2010, at 3:50 PM, James Williams wrote:> Hi, > > I'm trying to get exception handling working in my compiler targetting LLVM. I've been working from the LLVM exception handling documentation (including http://llvm.org/docs/ExceptionHandling.html and http://wiki.llvm.org/HowTo:_Build_JIT_based_Exception_mechanism) and looking at g++-llvm's output. > > I've been trying to get a minimal test function to work, which simply invokes _Unwind_RaiseException with a single clean-up landing pad. However. when I run it my personality function is not getting called - _Unwind_RaiseException simply returns apparently doing nothing. Looking at the x86-64 assembly output from llc, I can see this is happening because the personality function is not getting into the DWARF eh table (the landing pad is there though). > > I'm stumped as to why not. I'd be grateful if anyone can point out what I'm doing wrong here: > > define i32 @_ZN4N0014Main5test5EN2IO6WriterEiA_l(%6*, %4*, i32, %33*) { > entry: > %err = alloca %4* ; <%4**> [#uses=1] > %count = alloca i32 ; <i32*> [#uses=1] > %e = alloca %33* ; <%33**> [#uses=2] > %this = alloca %6* ; <%6**> [#uses=1] > %.ex_value = alloca i8* ; <i8**> [#uses=1] > %.ex_value_l = alloca i8* ; <i8**> [#uses=0] > %.ex_type = alloca i64 ; <i64*> [#uses=1] > br label %4 > > ; <label>:4 ; preds = %entry > store %6* %0, %6** %this > store %4* %1, %4** %err > store i32 %2, i32* %count > store %33* %3, %33** %e > br label %.try_body > > .try_body: ; preds = %4 > %5 = load %33** %e ; <%33*> [#uses=1] > %6 = getelementptr inbounds %33* %5, i32 0, i32 2, i32 0 ; <i64*> [#uses=1] > %7 = invoke i8* (...)* bitcast (i32 (%struct._Unwind_Exception*)* @_Unwind_RaiseException to i8* (...)*)(i64* %6) > to label %8 unwind label %.finally_pad ; <i8*> [#uses=0] > > ; <label>:8 ; preds = %.try_body > br label %.finally_handler > > .finally_pad: ; preds = %.try_body > %9 = call i8* @llvm.eh.exception() ; <i8*> [#uses=2] > store i8* %9, i8** %.ex_value > %10 = call i64 (i8*, i8*, ...)* @llvm.eh.selector.i64(i8* %9, i8* bitcast (i32 (i32, i32, i64, %struct._Unwind_Exception*, %struct._Unwind_Context*)* @__l_personality to i8*)) ; <i64> [#uses=1]I think you'll need a "i8* null" at the end of this @llvm.eh.selector.i64 call. -bw -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20100121/22ac72f3/attachment.html>
Hi Bill,> I think you'll need a "i8* null" at the end of this > @llvm.eh.selector.i64 call.that is what you would do if (1) you were using the C++ personality function, and (2) you want invoke to have correct LLVM semantics (i.e. invoke always branches to the landing pad if an exception is unwinding through it). Using a selector with no catch info, like this one, should result in a cleanup entry going in the dwarf eh table and the personality function being recorded IIRC. This may be all that is needed for a personality function that works differently to the C++ one. Ciao, Duncan.
Hi James,> I've been trying to get a minimal test function to work, which simply > invokes _Unwind_RaiseException with a single clean-up landing pad. > However. when I run it my personality function is not getting called - > _Unwind_RaiseException simply returns apparently doing nothing. Looking > at the x86-64 assembly output from llc, I can see this is happening > because the personality function is not getting into the DWARF eh table > (the landing pad is there though).do you mean that the personality function doesn't turn up in the assembler at all? It should be! Consider the following simplified example: declare void @g() define void @f() { e: invoke void @g() to label %c unwind label %u c: ; preds = %e ret void u: ; preds = %e %ptr = tail call i8* @llvm.eh.exception() nounwind ; <i8*> [#uses=1] %select = tail call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* %ptr, i8* bitcast (i32 (...)* @personality to i8*)) nounwind ; <i32> [#uses=0] ret void } declare i8* @llvm.eh.exception() nounwind readonly declare i32 @llvm.eh.selector(i8*, i8*, ...) nounwind declare i32 @personality(...) This compiles down to the following, which has a "cleanup" noted in the dwarf eh table, and has the personality function recorded in the CIE. This is with llc from top-of-tree. Do you see something different? Ciao, Duncan. .file "selector.ll" .text .align 16 .globl f .type f, at function f: # @f .Leh_func_begin1: # BB#0: # %e subq $8, %rsp .Llabel4: .Llabel1: callq g .Llabel2: # BB#1: # %c addq $8, %rsp ret .LBB1_2: # %u .Llabel3: addq $8, %rsp ret .size f, .-f .Leh_func_end1: .section .gcc_except_table,"a", at progbits .align 4 GCC_except_table1: .byte 0 # Padding .byte 0 # Padding .Lexception1: .byte 255 # @LPStart format (omit) .byte 0 # @TType format (absptr) .uleb128 15 # @TType base offset .byte 3 # Call site format (udata4) .uleb128 13 # Call site table size .long .Llabel1-.Leh_func_begin1 # Region start .long .Llabel2-.Llabel1 # Region length .long .Llabel3-.Leh_func_begin1 # Landing pad .uleb128 0 # Action .align 4 .section .eh_frame,"aw", at progbits .LEH_frame0: .Lsection_eh_frame: .Leh_frame_common: .long .Leh_frame_common_end-.Leh_frame_common_begin # Length of Common Information Entry .Leh_frame_common_begin: .long 0 # CIE Identifier Tag .byte 1 # CIE Version .asciz "zPLR" # CIE Augmentation .uleb128 1 # CIE Code Alignment Factor .sleb128 -8 # CIE Data Alignment Factor .byte 16 # CIE Return Address Column .uleb128 7 # Augmentation Size .byte 27 # Personality (pcrel sdata4) .Lpersonalityref_addr1_0: .long personality-.Lpersonalityref_addr1_0 # Personality .byte 27 # LSDA Encoding (pcrel sdata4) .byte 27 # FDE Encoding (pcrel sdata4) .byte 12 # DW_CFA_def_cfa .uleb128 7 # Register .uleb128 8 # Offset .byte 144 # DW_CFA_offset + Reg (16) .uleb128 1 # Offset .align 8 .Leh_frame_common_end: .Lf.eh: .long .Leh_frame_end1-.Leh_frame_begin1 # Length of Frame Information Entry .Leh_frame_begin1: .long .Leh_frame_begin1-.Leh_frame_common # FDE CIE offset .long .Leh_func_begin1-. # FDE initial location .long .Leh_func_end1-.Leh_func_begin1 # FDE address range .uleb128 8 # Augmentation size .quad .Lexception1-. # Language Specific Data Area .byte 4 # DW_CFA_advance_loc4 .long .Llabel4-.Leh_func_begin1 .byte 14 # DW_CFA_def_cfa_offset .uleb128 16 # Offset .align 8 .Leh_frame_end1: .section .note.GNU-stack,"", at progbits
2010/1/22 Duncan Sands <baldrick at free.fr>> Hi James, > > > I've been trying to get a minimal test function to work, which simply >> invokes _Unwind_RaiseException with a single clean-up landing pad. However. >> when I run it my personality function is not getting called - >> _Unwind_RaiseException simply returns apparently doing nothing. Looking at >> the x86-64 assembly output from llc, I can see this is happening because the >> personality function is not getting into the DWARF eh table (the landing pad >> is there though). >> > > do you mean that the personality function doesn't turn up in the assembler > at all? It should be! Consider the following simplified example: >Yes - no reference to the personality function at all. I tried Bill Wendling's suggestion to add an i8* null to the llvm.eh.selector.i64 parameter list but I still get no reference to the personality function. Compared to your example my eh table seems to be missing a load of stuff. The complete LLVM generated x86-64 assembler for my function including eh table is: .text .align 16 .globl _ZN4N0014Main5test5EN2IO6WriterEiA_l .type _ZN4N0014Main5test5EN2IO6WriterEiA_l, at function _ZN4N0014Main5test5EN2IO6WriterEiA_l: # @_ZN4N0014Main5test5EN2IO6WriterEiA_l .Leh_func_begin153: .Lfunc_begin153: .LBB153_0: # %entry subq $56, %rsp .Llabel294: .LBB153_1: movq %rdi, 24(%rsp) movq %rsi, 48(%rsp) movl %edx, 44(%rsp) movq %rcx, 32(%rsp) .LBB153_2: # %.try_body movq 32(%rsp), %rdi .Llabel291: addq $16, %rdi xorb %al, %al call _Unwind_RaiseException .Llabel292: jmp .LBB153_4 .LBB153_3: # %.finally_pad .Llabel293: movq %rax, 16(%rsp) testq %rdx, %rdx setne %al movzbl %al, %eax movq %rax, (%rsp) .LBB153_4: # %.finally_handler movl $.L__string_27, %edi xorb %al, %al call printf xorl %eax, %eax addq $56, %rsp ret .size _ZN4N0014Main5test5EN2IO6WriterEiA_l, .-_ZN4N0014Main5test5EN2IO6WriterEiA_l .Lfunc_end153: .Leh_func_end153: .section .gcc_except_table,"a", at progbits .align 4 GCC_except_table153: .byte 0x0 # Padding .Lexception153: .byte 0xFF # @LPStart format (DW_EH_PE_omit) .byte 0x0 # @TType format (DW_EH_PE_absptr) .uleb128 28 # @TType base offset .byte 0x3 # Call site format (DW_EH_PE_udata4) .uleb128 26 # Call site table size .long .Llabel291-.Leh_func_begin153 # Region start .long .Llabel292-.Llabel291 # Region length .long .Llabel293-.Leh_func_begin153 # Landing pad .uleb128 0 # Action .long .Llabel292-.Leh_func_begin153 # Region start .long .Leh_func_end153-.Llabel292 # Region length .long 0x0 # Landing pad .uleb128 0 # Action .align 4> declare void @g() > > define void @f() { > e: > invoke void @g() > to label %c unwind label %u > > c: ; preds = %e > ret void > > u: ; preds = %e > %ptr = tail call i8* @llvm.eh.exception() nounwind ; <i8*> [#uses=1] > %select = tail call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* %ptr, i8* > bitcast (i32 (...)* @personality to i8*)) nounwind ; <i32> [#uses=0] > ret void > } > > declare i8* @llvm.eh.exception() nounwind readonly > > declare i32 @llvm.eh.selector(i8*, i8*, ...) nounwind > > declare i32 @personality(...) > > > > This compiles down to the following, which has a "cleanup" noted in the > dwarf eh table, and has the personality function recorded in the CIE. > This is with llc from top-of-tree. Do you see something different? > > Ciao, > > Duncan. > > > > .file "selector.ll" > > > .text > .align 16 > .globl f > .type f, at function > f: # @f > .Leh_func_begin1: > # BB#0: # %e > subq $8, %rsp > .Llabel4: > .Llabel1: > callq g > .Llabel2: > # BB#1: # %c > addq $8, %rsp > ret > .LBB1_2: > # %u > .Llabel3: > addq $8, %rsp > ret > .size f, .-f > .Leh_func_end1: > > .section .gcc_except_table,"a", at progbits > .align 4 > GCC_except_table1: > .byte 0 > # Padding > .byte 0 > # Padding > .Lexception1: > .byte 255 > # @LPStart > format (omit) > .byte 0 > # @TType format > (absptr) > .uleb128 15 # @TType base > offset > .byte 3 > # Call site > format (udata4) > .uleb128 13 # Call site > table size > .long .Llabel1-.Leh_func_begin1 # Region start > .long .Llabel2-.Llabel1 # Region length > .long .Llabel3-.Leh_func_begin1 # Landing pad > .uleb128 0 # Action > .align 4 > .section .eh_frame,"aw", at progbits > .LEH_frame0: > .Lsection_eh_frame: > .Leh_frame_common: > .long .Leh_frame_common_end-.Leh_frame_common_begin # Length of > Common Information Entry > .Leh_frame_common_begin: > .long 0 > # CIE Identifier > Tag > .byte 1 > # CIE Version > .asciz "zPLR" # CIE > Augmentation > .uleb128 1 # CIE Code > Alignment Factor > .sleb128 -8 # CIE Data > Alignment Factor > .byte 16 > # CIE Return > Address Column > .uleb128 7 # Augmentation > Size > .byte 27 > # Personality > (pcrel sdata4) > .Lpersonalityref_addr1_0: > .long personality-.Lpersonalityref_addr1_0 # Personality > .byte 27 > # LSDA Encoding > (pcrel sdata4) > .byte 27 > # FDE Encoding > (pcrel sdata4) > .byte 12 > # DW_CFA_def_cfa > .uleb128 7 # Register > .uleb128 8 # Offset > .byte 144 > # DW_CFA_offset > + Reg (16) > .uleb128 1 # Offset > .align 8 > .Leh_frame_common_end: > > .Lf.eh: > .long .Leh_frame_end1-.Leh_frame_begin1 # Length of > Frame Information Entry > .Leh_frame_begin1: > .long .Leh_frame_begin1-.Leh_frame_common # FDE CIE offset > .long .Leh_func_begin1-. # FDE initial > location > .long .Leh_func_end1-.Leh_func_begin1 # FDE address > range > .uleb128 8 # Augmentation > size > .quad .Lexception1-. # Language > Specific Data Area > .byte 4 > # > DW_CFA_advance_loc4 > .long .Llabel4-.Leh_func_begin1 > .byte 14 > # > DW_CFA_def_cfa_offset > .uleb128 16 # Offset > .align 8 > .Leh_frame_end1: > > > .section .note.GNU-stack,"", at progbits > >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20100122/d89d4ce9/attachment.html>