diff options
-rw-r--r-- | gas/ChangeLog | 11 | ||||
-rw-r--r-- | gas/config/tc-xtensa.c | 42 | ||||
-rw-r--r-- | gas/config/tc-xtensa.h | 16 | ||||
-rw-r--r-- | gas/config/xtensa-relax.c | 37 |
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. */ |