Hi!
The attached testcase fails on ia64-linux at -O2, both with GCC trunk and
4.1.1.
The problem is a br.call not at the end of a bundle where the EH region
ends right after it:
.mbb
ld8 r39 = [r15]
br.call.sptk.many b0 = _ZN1F3barEPvR1B#
[.LEHE0:]
nop 0
;;
As br.call sets rp to the address of the next bundle, when the personality
routine is called it doesn't think this call is inside of the .LEHB0 .. .LEHE0
EH region and calls std::terminate, as _Unwind_GetIP (context) is
.LEHE0 - 2 + 16, so even when we subtract one it still is far above .LEHE0.
The only 2 bundles which have a branch slot not in the last position are
.mbb and .bbb. GCC generates an explicit stop after a br.call if it is
followed by some branch instruction or another call, so I think br.call
not in the last slot is only possible if the rest of the .mbb or .bbb bundle
is filled with nops.
When not emitting explicit bundling (-O0 or -fno-schedule-insns2),
we are IMHO safe, as GCC then doesn't emit nops after br.call instructions
(and there is explicit ;; between br.call and another br or br.call),
so for
br.call.sptk.many b0 = something#
[.LEHEN:]
the br.call will be either in the last slot of a bundle (therefore
(.LEHEN & 15) == 0, or the assembler will emit one or two nop.b's between
the br.call and the label.
The following patch should cure it when emitting explicit bundling
(-O2, -fschedule-insns2). When adding a bundle selector for the
.mbb or .bbb bundles, it checks for a br.call insn with REG_EH_REGION
note followed by nops in the same bundle and in that case adds REG_EH_REGION
notes to the nops as well. This tells except.c to move the region end label
to the end of the bundle.
On the attached testcase, the difference is just:
.mbb
ld8 r39 = [r15]
br.call.sptk.many b0 = _ZN1F3barEPvR1B#
-[.LEHE0:]
nop 0
+[.LEHE0:]
;;
Bootstrapped/regtested on ia64-linux, ok for trunk/4.2/4.1?