[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