[cfe-dev] Code generation for noexcept functions

Richard Smith richard at metafoo.co.uk
Tue May 13 14:26:26 PDT 2014


On Tue, May 13, 2014 at 12:36 PM, Stephan Tolksdorf <st at quanttec.com> wrote:

> On 2014-05-11 Richard Smith wrote:
>
>> On Sun, May 11, 2014 at 8:19 AM, Stephan Tolksdorf <st at quanttec.com
>> <mailto:st at quanttec.com>> wrote:
>>
>>     Hi,
>>
>>     When clang/LLVM can't prove that a noexcept function only contains
>>     non-throwing code, it seems to insert an explicit exception handler
>>     that calls std::terminate. Why doesn't clang leave it to the eh
>>     personality function to call std::terminate when an exception is
>>     thrown inside a noexcept function, as GCC does?
>>
>>
>> As far as I can see, this is impossible to represent in LLVM IR. (If
>> there is a way, I'm sure we'd be happy to make clang emit that IR.)
>>
>
> Thanks for the reply! Do you or maybe somebody else have an opinion on
> what the best way would be to efficiently support this case in LLVM IR?
>

Here's a reduced testcase:

void f();
void g() noexcept { f(); }

One obvious approach would be to emit the call to 'f' as a 'call', not an
'invoke', with some attribute indicating that the program is terminated if
it unwinds. (We can't use 'nounwind' for this, because that gives us UB on
unwind, not a call to terminate.)

Not-very-well-thought-through strawman: add a function attribute to
indicate that that the function does not return if a call unwinds (and pass
it the personality function so that we can generate the right CFI stuff).

call void @_Z1fv() terminateonunwind(i32 (...)* @__gxx_personality_v0)

This would result in a call that is not covered by any range in the call
site table in the calling function's LSDA.


Another case:

void h() noexcept { try { f(); } catch (int) {} }

Here, I don't think there's a better representation than the one we're
currently using (though we should at least omit the pointless
__cxa_begin_catch immediately before our synthesized call to
std::terminate).

    For example, GCC generates more efficient code for this test case:
>>
>>        using FP = void(*)();
>>
>>        inline void test(FP fp) noexcept {
>>          fp();
>>        }
>>
>>        void test2(FP fp) {
>>          test(fp);
>>          test(fp);
>>        }
>>
>>     The code generated by GCC (ToT, -O3, Linux x64) is:
>>
>>     .LHOTB0:
>>              .p2align 4,,15
>>              .globl  _Z5test2PFvvE
>>              .type   _Z5test2PFvvE, @function
>>     _Z5test2PFvvE:
>>     .LFB1:
>>              .cfi_startproc
>>              .cfi_personality 0x3,__gxx_personality_v0
>>              .cfi_lsda 0x3,.LLSDA1
>>              pushq   %rbx
>>              .cfi_def_cfa_offset 16
>>              .cfi_offset 3, -16
>>              movq    %rdi, %rbx
>>              call    *%rdi
>>              movq    %rbx, %rax
>>              popq    %rbx
>>              .cfi_def_cfa_offset 8
>>              jmp     *%rax
>>              .cfi_endproc
>>     .LFE1:
>>              .globl  __gxx_personality_v0
>>              .section        .gcc_except_table,"a", at __progbits
>>
>>     .LLSDA1:
>>              .byte   0xff
>>              .byte   0xff
>>              .byte   0x1
>>              .uleb128 .LLSDACSE1-.LLSDACSB1
>>     .LLSDACSB1:
>>     .LLSDACSE1:
>>              .text
>>              .size   _Z5test2PFvvE, .-_Z5test2PFvvE
>>              .section        .text.unlikely
>>
>>
>>     The code generated by clang (ToT, -O3, Linux x64) is:
>>
>>     .globl  _Z5test2PFvvE
>>              .align  16, 0x90
>>              .type   _Z5test2PFvvE, at function
>>     _Z5test2PFvvE:                          # @_Z5test2PFvvE
>>              .cfi_startproc
>>              .cfi_personality 3, __gxx_personality_v0
>>     .Leh_func_begin0:
>>              .cfi_lsda 3, .Lexception0
>>     # BB#0:                                 # %entry
>>              pushq   %rbx
>>     .Ltmp6:
>>              .cfi_def_cfa_offset 16
>>     .Ltmp7:
>>              .cfi_offset %rbx, -16
>>              movq    %rdi, %rbx
>>     .Ltmp0:
>>              callq   *%rbx
>>     .Ltmp1:
>>     # BB#1:                                 # %_Z4testPFvvE.exit
>>     .Ltmp3:
>>              callq   *%rbx
>>     .Ltmp4:
>>     # BB#2:                                 # %_Z4testPFvvE.exit3
>>              popq    %rbx
>>              retq
>>     .LBB0_3:                                # %terminate.lpad.i
>>     .Ltmp2:
>>              movq    %rax, %rdi
>>              callq   __clang_call_terminate
>>     .LBB0_4:                                # %terminate.lpad.i2
>>     .Ltmp5:
>>              movq    %rax, %rdi
>>              callq   __clang_call_terminate
>>     .Ltmp8:
>>              .size   _Z5test2PFvvE, .Ltmp8-_Z5test2PFvvE
>>              .cfi_endproc
>>     .Leh_func_end0:
>>              .section        .gcc_except_table,"a", at __progbits
>>
>>              .align  4
>>     GCC_except_table0:
>>     .Lexception0:
>>              .byte   255                     # @LPStart Encoding = omit
>>              .byte   3                       # @TType Encoding = udata4
>>              .asciz  "\242\200\200"          # @TType base offset
>>              .byte   3                       # Call site Encoding = udata4
>>              .byte   26                      # Call site table length
>>     .Lset0 = .Ltmp0-.Leh_func_begin0        # >> Call Site 1 <<
>>              .long   .Lset0
>>     .Lset1 = .Ltmp1-.Ltmp0                  #   Call between .Ltmp0 and
>>     .Ltmp1
>>              .long   .Lset1
>>     .Lset2 = .Ltmp2-.Leh_func_begin0        #     jumps to .Ltmp2
>>              .long   .Lset2
>>              .byte   1                       #   On action: 1
>>     .Lset3 = .Ltmp3-.Leh_func_begin0        # >> Call Site 2 <<
>>              .long   .Lset3
>>     .Lset4 = .Ltmp4-.Ltmp3                  #   Call between .Ltmp3 and
>>     .Ltmp4
>>              .long   .Lset4
>>     .Lset5 = .Ltmp5-.Leh_func_begin0        #     jumps to .Ltmp5
>>              .long   .Lset5
>>              .byte   1                       #   On action: 1
>>              .byte   1                       # >> Action Record 1 <<
>>                                              #   Catch TypeInfo 1
>>              .byte   0                       #   No further actions
>>                                              # >> Catch TypeInfos <<
>>              .long   0                       # TypeInfo 1
>>              .align  4
>>
>>              .section
>>     .text.__clang_call_terminate,"__axG", at progbits,__clang_call_
>> __terminate,comdat
>>
>>              .hidden __clang_call_terminate
>>              .weak   __clang_call_terminate
>>              .align  16, 0x90
>>              .type   __clang_call_terminate, at __function
>>
>>     __clang_call_terminate:                 # @__clang_call_terminate
>>     # BB#0:
>>              pushq   %rax
>>              callq   __cxa_begin_catch
>>              callq   _ZSt9terminatev
>>     .Ltmp9:
>>              .size   __clang_call_terminate, .Ltmp9-__clang_call_terminate
>>
>>     - Stephan
>>     _________________________________________________
>>     cfe-dev mailing list
>>     cfe-dev at cs.uiuc.edu <mailto:cfe-dev at cs.uiuc.edu>
>>     http://lists.cs.uiuc.edu/__mailman/listinfo/cfe-dev
>>     <http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev>
>>
>>
>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20140513/dd0106c7/attachment.html>


More information about the cfe-dev mailing list