[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