This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[Xtensa] Correct relax a very unusual instruction sequence
- From: Sterling Augustine <sterling at tensilica dot com>
- To: <binutils at sourceware dot org>
- Date: Tue, 9 Feb 2010 11:39:32 -0800
- Subject: [Xtensa] Correct relax a very unusual instruction sequence
On Xtensa, it is hard to imagine two consecutive zero-overhead-loop
instructions as an actually useful construct, but it is legal according
to the ISA, and therefore the assembler should handle relaxing them
correctly. The attached patch, which I have committed, does that.
Sterling
2010-02-09 Sterling Augustine <sterling@tensilica.com>
* config/tc-xtensa.c (RELAXED_LOOP_INSN_BYTES): New.
(next_frag_pre_opcode_bytes): Use RELAXED_LOOP_INSN_BYTES.
(xtensa_mark_zcl_first_insns): Rewrite to handle corner case.
Index: config/tc-xtensa.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-xtensa.c,v
retrieving revision 1.120
diff -u -p -r1.120 tc-xtensa.c
--- config/tc-xtensa.c 8 Feb 2010 18:45:05 -0000 1.120
+++ config/tc-xtensa.c 9 Feb 2010 19:26:22 -0000
@@ -4649,6 +4649,12 @@ next_frag_is_loop_target (const fragS *f
}
+/* As specified in the relaxation table, when a loop instruction is
+ relaxed, there are 24 bytes between the loop instruction itself and
+ the first instruction in the loop. */
+
+#define RELAXED_LOOP_INSN_BYTES 24
+
static addressT
next_frag_pre_opcode_bytes (const fragS *fragp)
{
@@ -4671,7 +4677,7 @@ next_frag_pre_opcode_bytes (const fragS
been relaxed. Note that we can assume that the LOOP
instruction is in slot 0 because loops aren't bundleable. */
if (next_fragp->tc_frag_data.slot_subtypes[0] > RELAX_IMMED)
- return get_expanded_loop_offset (next_opcode);
+ return get_expanded_loop_offset (next_opcode) + RELAXED_LOOP_INSN_BYTES;
return 0;
}
@@ -7401,9 +7407,36 @@ xtensa_mark_zcl_first_insns (void)
|| fragP->fr_subtype == RELAX_CHECK_ALIGN_NEXT_OPCODE))
{
/* Find the loop frag. */
- fragS *targ_frag = next_non_empty_frag (fragP);
+ fragS *loop_frag = next_non_empty_frag (fragP);
/* Find the first insn frag. */
- targ_frag = next_non_empty_frag (targ_frag);
+ fragS *targ_frag = next_non_empty_frag (loop_frag);
+
+ /* Handle a corner case that comes up in hardware
+ diagnostics. The original assembly looks like this:
+
+ loop aX, LabelA
+ <empty_frag>--not found by next_non_empty_frag
+ loop aY, LabelB
+
+ Depending on the start address, the assembler may or
+ may not change it to look something like this:
+
+ loop aX, LabelA
+ nop--frag isn't empty anymore
+ loop aY, LabelB
+
+ So set up to check the alignment of the nop if it
+ exists */
+ while (loop_frag != targ_frag)
+ {
+ if (loop_frag->fr_type == rs_machine_dependent
+ && (loop_frag->fr_subtype == RELAX_ALIGN_NEXT_OPCODE
+ || loop_frag->fr_subtype
+ == RELAX_CHECK_ALIGN_NEXT_OPCODE))
+ targ_frag = loop_frag;
+ else
+ loop_frag = loop_frag->fr_next;
+ }
/* Of course, sometimes (mostly for toy test cases) a
zero-cost loop instruction is the last in a section. */