aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gas/ChangeLog11
-rw-r--r--gas/config/tc-xtensa.c42
-rw-r--r--gas/config/tc-xtensa.h16
-rw-r--r--gas/config/xtensa-relax.c37
4 files changed, 89 insertions, 17 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog
index c79e63b..c713436 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,3 +1,14 @@
+2007-06-22 Sterling Augustine <sterling@tensilica.com>
+
+ * config/tc-xtensa.c (xg_assembly_relax): Comment termination rules.
+ (frag_format_size): Handle RELAX_IMMED_STEP3.
+ (xtensa_relax_frag, md_convert_frag): Likewise.
+ * config/tc-xtensa.h (xtensa_relax_statesE): Add RELAX_IMMED_STEP3.
+ (RELAX_IMMED_MAXSTEPS): Adjust.
+ * config/xtensa-relax.c (widen_spec_list): Add transitions from
+ wide branches to branch-over-jumps.
+ (build_transition): Handle wide branches in transition patterns.
+
2007-06-22 H.J. Lu <hongjiu.lu@intel.com>
* config/tc-i386.c (disp_size): New.
diff --git a/gas/config/tc-xtensa.c b/gas/config/tc-xtensa.c
index 7011a17..aef6b65 100644
--- a/gas/config/tc-xtensa.c
+++ b/gas/config/tc-xtensa.c
@@ -3498,7 +3498,33 @@ xg_expand_to_stack (IStack *istack, TInsn *insn, int lateral_steps)
/* Relax the assembly instruction at least "min_steps".
- Return the number of steps taken. */
+ Return the number of steps taken.
+
+ For relaxation to correctly terminate, every relaxation chain must
+ terminate in one of two ways:
+
+ 1. If the chain from one instruction to the next consists entirely of
+ single instructions, then the chain *must* handle all possible
+ immediates without failing. It must not ever fail because an
+ immediate is out of range. The MOVI.N -> MOVI -> L32R relaxation
+ chain is one example. L32R loads 32 bits, and there cannot be an
+ immediate larger than 32 bits, so it satisfies this condition.
+ Single instruction relaxation chains are as defined by
+ xg_is_single_relaxable_instruction.
+
+ 2. Otherwise, the chain must end in a multi-instruction expansion: e.g.,
+ BNEZ.N -> BNEZ -> BNEZ.W15 -> BENZ.N/J
+
+ Strictly speaking, in most cases you can violate condition 1 and be OK
+ -- in particular when the last two instructions have the same single
+ size. But nevertheless, you should guarantee the above two conditions.
+
+ We could fix this so that single-instruction expansions correctly
+ terminate when they can't handle the range, but the error messages are
+ worse, and it actually turns out that in every case but one (18-bit wide
+ branches), you need a multi-instruction expansion to get the full range
+ anyway. And because 18-bit branches are handled identically to 15-bit
+ branches, there isn't any point in changing it. */
static int
xg_assembly_relax (IStack *istack,
@@ -3511,12 +3537,9 @@ xg_assembly_relax (IStack *istack,
{
int steps_taken = 0;
- /* assert (has no symbolic operands)
- Some of its immeds don't fit.
- Try to build a relaxed version.
- This may go through a couple of stages
- of single instruction transformations before
- we get there. */
+ /* Some of its immeds don't fit. Try to build a relaxed version.
+ This may go through a couple of stages of single instruction
+ transformations before we get there. */
TInsn single_target;
TInsn current_insn;
@@ -4384,7 +4407,8 @@ frag_format_size (const fragS *fragP)
/* If an instruction is about to grow, return the longer size. */
if (fragP->tc_frag_data.slot_subtypes[0] == RELAX_IMMED_STEP1
- || fragP->tc_frag_data.slot_subtypes[0] == RELAX_IMMED_STEP2)
+ || fragP->tc_frag_data.slot_subtypes[0] == RELAX_IMMED_STEP2
+ || fragP->tc_frag_data.slot_subtypes[0] == RELAX_IMMED_STEP3)
return 3;
if (fragP->tc_frag_data.slot_subtypes[0] == RELAX_NARROW)
@@ -8324,6 +8348,7 @@ xtensa_relax_frag (fragS *fragP, long stretch, int *stretched_p)
case RELAX_IMMED:
case RELAX_IMMED_STEP1:
case RELAX_IMMED_STEP2:
+ case RELAX_IMMED_STEP3:
/* Place the immediate. */
new_stretch += relax_frag_immed
(now_seg, fragP, stretch,
@@ -9041,6 +9066,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT sec, fragS *fragp)
case RELAX_IMMED:
case RELAX_IMMED_STEP1:
case RELAX_IMMED_STEP2:
+ case RELAX_IMMED_STEP3:
/* Place the immediate. */
convert_frag_immed
(sec, fragp,
diff --git a/gas/config/tc-xtensa.h b/gas/config/tc-xtensa.h
index 251105e..4065321 100644
--- a/gas/config/tc-xtensa.h
+++ b/gas/config/tc-xtensa.h
@@ -131,18 +131,20 @@ enum xtensa_relax_statesE
RELAX_IMMED,
/* The last instruction in this fragment (at->fr_opcode) contains
- the value defined by fr_symbol (fr_offset = 0). If the value
- does not fit, use the specified expansion. This is similar to
- "NARROW", except that these may not be expanded in order to align
- code. */
+ an immediate or symbol. If the value does not fit, relax the
+ opcode using expansions from the relax table. */
RELAX_IMMED_STEP1,
/* The last instruction in this fragment (at->fr_opcode) contains a
- literal. It has already been expanded at least 1 step. */
+ literal. It has already been expanded 1 step. */
RELAX_IMMED_STEP2,
/* The last instruction in this fragment (at->fr_opcode) contains a
- literal. It has already been expanded at least 2 steps. */
+ literal. It has already been expanded 2 steps. */
+
+ RELAX_IMMED_STEP3,
+ /* The last instruction in this fragment (at->fr_opcode) contains a
+ literal. It has already been expanded 3 steps. */
RELAX_SLOTS,
/* There are instructions within the last VLIW instruction that need
@@ -179,7 +181,7 @@ enum xtensa_relax_statesE
/* This is used as a stopper to bound the number of steps that
can be taken. */
-#define RELAX_IMMED_MAXSTEPS (RELAX_IMMED_STEP2 - RELAX_IMMED)
+#define RELAX_IMMED_MAXSTEPS (RELAX_IMMED_STEP3 - RELAX_IMMED)
struct xtensa_frag_type
{
diff --git a/gas/config/xtensa-relax.c b/gas/config/xtensa-relax.c
index 09c29ad..779c907 100644
--- a/gas/config/xtensa-relax.c
+++ b/gas/config/xtensa-relax.c
@@ -247,7 +247,10 @@ struct string_pattern_pair_struct
addi.n a4, 0x1010
=> addi a4, 0x1010
=> addmi a4, 0x1010
- => addmi a4, 0x1000, addi a4, 0x10. */
+ => addmi a4, 0x1000, addi a4, 0x10.
+
+ See the comments in xg_assembly_relax for some important details
+ regarding how these chains must be built. */
static string_pattern_pair widen_spec_list[] =
{
@@ -380,6 +383,10 @@ static string_pattern_pair widen_spec_list[] =
{"bnez %as,%label ? IsaUseDensityInstruction", "beqz.n %as,%LABEL;j %label;LABEL"},
{"beqz %as,%label", "bnez %as,%LABEL;j %label;LABEL"},
{"bnez %as,%label", "beqz %as,%LABEL;j %label;LABEL"},
+ {"WIDE.beqz %as,%label ? IsaUseDensityInstruction", "bnez.n %as,%LABEL;j %label;LABEL"},
+ {"WIDE.bnez %as,%label ? IsaUseDensityInstruction", "beqz.n %as,%LABEL;j %label;LABEL"},
+ {"WIDE.beqz %as,%label", "bnez %as,%LABEL;j %label;LABEL"},
+ {"WIDE.bnez %as,%label", "beqz %as,%LABEL;j %label;LABEL"},
/* Widening expect-taken branches. */
{"beqzt %as,%label ? IsaUsePredictedBranches", "bnez %as,%LABEL;j %label;LABEL"},
@@ -415,6 +422,29 @@ static string_pattern_pair widen_spec_list[] =
{"bbc %as,%at,%label", "bbs %as,%at,%LABEL;j %label;LABEL"},
{"bbs %as,%at,%label", "bbc %as,%at,%LABEL;j %label;LABEL"},
+ {"WIDE.bgez %as,%label", "bltz %as,%LABEL;j %label;LABEL"},
+ {"WIDE.bltz %as,%label", "bgez %as,%LABEL;j %label;LABEL"},
+ {"WIDE.beqi %as,%imm,%label", "bnei %as,%imm,%LABEL;j %label;LABEL"},
+ {"WIDE.bnei %as,%imm,%label", "beqi %as,%imm,%LABEL;j %label;LABEL"},
+ {"WIDE.bgei %as,%imm,%label", "blti %as,%imm,%LABEL;j %label;LABEL"},
+ {"WIDE.blti %as,%imm,%label", "bgei %as,%imm,%LABEL;j %label;LABEL"},
+ {"WIDE.bgeui %as,%imm,%label", "bltui %as,%imm,%LABEL;j %label;LABEL"},
+ {"WIDE.bltui %as,%imm,%label", "bgeui %as,%imm,%LABEL;j %label;LABEL"},
+ {"WIDE.bbci %as,%imm,%label", "bbsi %as,%imm,%LABEL;j %label;LABEL"},
+ {"WIDE.bbsi %as,%imm,%label", "bbci %as,%imm,%LABEL;j %label;LABEL"},
+ {"WIDE.beq %as,%at,%label", "bne %as,%at,%LABEL;j %label;LABEL"},
+ {"WIDE.bne %as,%at,%label", "beq %as,%at,%LABEL;j %label;LABEL"},
+ {"WIDE.bge %as,%at,%label", "blt %as,%at,%LABEL;j %label;LABEL"},
+ {"WIDE.blt %as,%at,%label", "bge %as,%at,%LABEL;j %label;LABEL"},
+ {"WIDE.bgeu %as,%at,%label", "bltu %as,%at,%LABEL;j %label;LABEL"},
+ {"WIDE.bltu %as,%at,%label", "bgeu %as,%at,%LABEL;j %label;LABEL"},
+ {"WIDE.bany %as,%at,%label", "bnone %as,%at,%LABEL;j %label;LABEL"},
+ {"WIDE.bnone %as,%at,%label", "bany %as,%at,%LABEL;j %label;LABEL"},
+ {"WIDE.ball %as,%at,%label", "bnall %as,%at,%LABEL;j %label;LABEL"},
+ {"WIDE.bnall %as,%at,%label", "ball %as,%at,%LABEL;j %label;LABEL"},
+ {"WIDE.bbc %as,%at,%label", "bbs %as,%at,%LABEL;j %label;LABEL"},
+ {"WIDE.bbs %as,%at,%label", "bbc %as,%at,%LABEL;j %label;LABEL"},
+
/* Expanding calls with literals. */
{"call0 %label,%ar0 ? IsaUseL32R",
"LITERAL %label; l32r a0,%LITERAL; callx0 a0,%ar0"},
@@ -1571,7 +1601,10 @@ build_transition (insn_pattern *initial_insn,
precond_e *precond;
insn_repl_e *r;
- opcode = xtensa_opcode_lookup (isa, initial_insn->t.opcode_name);
+ if (!wide_branch_opcode (initial_insn->t.opcode_name, ".w18", &opcode)
+ && !wide_branch_opcode (initial_insn->t.opcode_name, ".w15", &opcode))
+ opcode = xtensa_opcode_lookup (isa, initial_insn->t.opcode_name);
+
if (opcode == XTENSA_UNDEFINED)
{
/* It is OK to not be able to translate some of these opcodes. */