This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: SH3 problem with switch branch tables
- To: AArnold at ELSA dot de
- Subject: Re: SH3 problem with switch branch tables
- From: Toshiyasu Morita <tm at netcom dot com>
- Date: Thu, 25 Mar 1999 11:44:59 -0800 (PST)
- Cc: egcs-bugs at egcs dot cygnus dot com, egcs-patches at egcs dot cygnus dot com
I think I understand the real problem now. It seems the "braf"
instruction is used incorrectly.
To explain:
1) The SH manual indicates BRAF Rn performs "PC + 4 + Rn => PC".
2) The offset is calculated relative to the table start (L1302)
This isn't the proper calculation. Since BRAF is PC relative, the proper
displacements should be calculated relative to the BRAF instruction
itself, not the table start.
The current code works fine as long as the "braf" instruction is
generated on a 4 byte alignment. If this happens, then the table is
generated at braf_pc + 4 (due to the following nop) and the first ".align 2"
directive generates no padding.
The problem occurs when the "braf" instruction is generated at an address
that's not 4 byte aligned. What this happens, the following nop generates
two bytes, then the ".align 2" directive generates 2 bytes of padding.
The table winds up at PC + 6 and the offsets are incorrect, because
they're generated relative to the table start (PC + 6) instead
relative to the correct address (PC + 4):
2988 1aa2 0123 braf r1 <- braf @ 0x1aa2
2989 1aa4 0009 nop
2990 1aa6 0009 .align 2
2991 L1302:
2992 .align 2
2993 L1300:
2994 1aa8 0A .byte L1289-L1302 <- table @ 0x1aa8
2995 1aa9 58 .byte L1292-L1302
2996 1aaa A8 .byte L1295-L1302
2997 1aab D8 .byte L1299-L1302
2998 1aac E8 .byte L1287-L1302
2999 1aad E8 .byte L1287-L1302
3000 1aae 08 .byte L1288-L1302
In this instance, the table winds up at braf_pc + 6 so all the offsets
are off by two bytes.
I can think of two ways to fix this problem:
1) The right way. Generate label for the "braf" instruction, and calculate
the table values relative to the "braf" label.
2) The kludgy way. Disable the "braf" usage.
I'll let Joern fix it properly, but here's a kludge which will hopefully
fix your problem:
*** sh.md.bak Thu Mar 25 11:34:40 1999
--- sh.md Thu Mar 25 11:35:20 1999
***************
*** 3292,3298 ****
emit_insn (gen_casesi_0 (operands[0], operands[1], operands[2],
operands[4],
reg));
emit_insn (gen_casesi_worker_0 (reg2, reg, operands[3]));
! if (TARGET_SH2)
{
rtx lab = gen_label_rtx ();
emit_jump_insn (gen_casesi_jump_2 (reg2,
--- 3292,3301 ----
emit_insn (gen_casesi_0 (operands[0], operands[1], operands[2],
operands[4],
reg));
emit_insn (gen_casesi_worker_0 (reg2, reg, operands[3]));
!
! /* Temporarily disabled because "braf" is used incorrectly in
! the casesi_jump_2 insn (no label) */
! if (0)
{
rtx lab = gen_label_rtx ();
emit_jump_insn (gen_casesi_jump_2 (reg2,
Toshi