This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] prevent breakage of eh call/return@ assumption on hppa


Olivier Hainque wrote:
Hello,

The Ada testcase attached is expected to compile and run silently.

Built with "gnatmake -O2 -gnatp handle_and_return.adb" with a
hppa1.1-hp-hpux11.00 compiler, it loops infinitely.

The bad thing concentrates in this sequence:

   begin
      Raise_CE;
      return;
   exception
      when others => null;
   end;

   begin
      Raise_CE;
      return;
   exception
      when others => null;
   end;

Each block features a call to a subprogram which raises an exception, expected
to be caught by the associated block handler. What is happening is that the
second exception propagates up to the first handler.

This is related to an optimization performed by pa.c:output_call, in
particular:

  /* This call has an unconditional jump in its delay slot.  */
  xoperands[0] = XEXP (PATTERN (NEXT_INSN (insn)), 1);

  if (!delay_slot_filled && INSN_ADDRESSES_SET_P ())
    {
      /* See if the return address can be adjusted.  Use the containing
         sequence insn's address.  */
      ...

It optimizes a case where a call is immediatly followed by a jump, adjusting
the return address to directly designate the jump destination.

Comparing the assembly outputs for handle_and_return.adb for cases
where this optimization is deactivated or performed, we observe a
change like:

L$EHB0000:
L$CFI0003:
.CALL
bl _ada_raise_ce,%r2 <== First call/raise
stw %r4,-120(%r30)
L$EHE0000:
L$0009:
L$EHB0001:
ldw -148(%r30),%r2 <== First return
...
bv %r0(%r2)
[...]
L$EHB0004:
.CALL
bl _ada_raise_ce,%r2 <== Second raise
- nop
- b,n L$0009 <== Second return, branch to the First return sequence - replaced
by ...
+ ldo L$0009-L$0023(%r2),%r2 <== return address adjustment in
+L$0023: the call delay slot
L$EHE0004:


The initial post call branch aimed at the common return sequence is optimized
into a return address adjustment. This badly confuses the unwinder while it
propagates the second exception: it determines the region to which the second
call is attached from the adjusted return address it sees and lands into the
first call region.

The attached patch addresses this by disabling the optimization as
soon as we're generating eh frame tables, on the grounds that we need
to maintain the usual return-address/corresponding-call-address
relationship for table based exception propagation. We have been using
a minor variant internally for a while.

Instead of triggering this on call-frame information, trigger it on


can_throw_internal(call_insn) || can_throw_external(call_insn)

Though I suppose we could introduce a cheaper predicate that tests both, at present almost everything in the compiler only really cares about the former test.


r~



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]