[PATCH] C++ space optimization: omit EH info for thunks
Stuart Hastings
stuart@apple.com
Tue Aug 20 16:27:00 GMT 2002
On Monday, Aug 19, 2002, at 15:53 US/Pacific, Richard Henderson wrote:
> On Fri, Aug 16, 2002 at 03:53:42PM -0700, Stuart Hastings wrote:
>> /* Don't emit EH unwind info for leaf functions that don't
>> need it. */
>> - if (!flag_asynchronous_unwind_tables && for_eh && fde->nothrow
>> - && ! fde->uses_eh_lsda)
>> + if (!flag_asynchronous_unwind_tables && for_eh &&
>> + (fde->all_throwers_are_sibcalls || (fde->nothrow && !
>> fde->uses_eh_lsda)))
>> continue;
>
> This is incorrect. You want:
>
> if (!flag_asynchronous_unwind_tables && for_eh
> && (fde->nothrow || fde->all_throwers_are_sibcalls)
> && !fde->uses_eh_lsda)
>
> Just because a function doesn't throw doesn't mean it doesn't
> handle exceptions. For instance, given
>
> void foo()
> {
> try
> bar();
> catch (...)
> ;
> }
>
> both nothrow and all_throwers_are_sibcalls are true, since
> can_throw_external is false for the call to bar.
Actually, the catch try/catch block is implemented with some CALL_INSNS
that aren't sibcalled, so the existing code would emit EH info for your
example.
However, your version seems more robust, so I've changed my sources to
match.
> However, uses_eh_lsda will be true since we need to catch the
> exception.
>
>> for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
>> if (can_throw_external (insn))
>> ! {
>> ! current_function_nothrow = 0;
>> ! cfun->all_throwers_are_sibcalls &= (GET_CODE (insn) == CALL_INSN
>> && SIBLING_CALL_P (insn));
>> ! /* If the current function has a possible thrower that isn't a
>> sibcall, we're done. */
>> ! if (!cfun->all_throwers_are_sibcalls)
>> ! return;
>
> This is incorrect.
> You're clearing leaving all_throwers_are_sibcalls set when CALL_INSN
> is false.
I'm sorry, I don't understand this statement.
> Something that cannot happen with C++
> by default, but does happen with Java or with -fnon-call-exceptions.
>
> In any case, I'd rather see this written:
>
> if (GET_CODE (insn) == CALL_INSN && !SIBLING_CALL_P (insn))
> {
> cfun->all_throwers_are_sibcalls = 0;
> return;
> }
You seem to be suggesting a more aggressive approach. My previous
version would abandon the optimization when it encountered any insn
that could throw. The whole idea was to recognize that a CALL_INSN
marked SIBLING_CALL_P can't.
Yours appears to ignore any instruction that isn't a CALL_INSN. For
example, given a thunk with one sibcall-optimized CALL_INSN, if a load
instruction was marked as "can_throw_exception()", my version would
abandon the optimization and emit EH info as usual, and yours appears
to sustain the optimization and omit the EH info. If this is
intentional, I'd be happy to include it in my next submission; I just
wanted to be sure I understood it first.
Perhaps you meant
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
if (can_throw_external (insn))
{
current_function_nothrow = 0;
if (GET_CODE (insn) != CALL_INSN || !SIBLING_CALL_P (insn))
{
cfun->all_throwers_are_sibcalls = 0;
return;
}
}
Or perhaps this is more comprehensible (?):
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
if (can_throw_external (insn))
{
current_function_nothrow = 0;
if (GET_CODE (insn) == CALL_INSN && SIBLING_CALL_P (insn))
;
else
{
cfun->all_throwers_are_sibcalls = 0;
return;
}
}
stuart hastings
Apple Computer
More information about the Gcc-patches
mailing list