[cfe-dev] Code generation for noexcept functions
Stephan Tolksdorf
st at quanttec.com
Wed May 14 08:38:12 PDT 2014
On 2014-05-13 23:26, Richard Smith wrote:
> On Tue, May 13, 2014 at 12:36 PM, Stephan Tolksdorf <st at quanttec.com
> <mailto: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>
> <mailto: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.
I suppose the principal alternative would be to introduce a "terminate"
clause to the landingpad instruction.
One difficulty of implementing either approach seems to be that LLVM
will need to synthesize an actual terminate call when it inlines a
"terminateonunwind" call to a function that contains an invoke without a
catch-all clause and there's no direct way to represent the terminate
action in the 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).
If landingpad had a terminate clause, you could leave the synthesizing
of the terminate call to LLVM in this case too.
The call to __cxa_begin_catch seems to be due to llvm.org/PR11893. The
libsupc++ and libc++abi personality functions also call
__cxa_begin_catch before calling std::terminate when possible.
One (ugly) way to prevent clang/LLVM from generating bloated code for
noexcept functions that contain calls to functions which are known to be
non-throwing for the specified arguments but which aren't annotated as
noexcept is to move the calls to an inline wrapper function with
__attribute__((nothrow)). I'll probably resort to this workaround for my
code.
- Stephan
>
> 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>
> <mailto: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>
> <http://lists.cs.uiuc.edu/__mailman/listinfo/cfe-dev
> <http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev>>
>
>
>
More information about the cfe-dev
mailing list