X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-xtensa.c;h=a44c28093efaedfe64d089c984d397cde0cfa77b;hb=7f3dfb9cf74da197cfe71fb0490a90613269ca0f;hp=11bd8723850a5dbad3f587c478c42f58bf096b14;hpb=1d19a7709abb08ce59eaa2ee0e1e0db3c93189e2;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-xtensa.c b/gas/config/tc-xtensa.c index 11bd872385..a44c28093e 100644 --- a/gas/config/tc-xtensa.c +++ b/gas/config/tc-xtensa.c @@ -1,5 +1,5 @@ /* tc-xtensa.c -- Assemble Xtensa instructions. - Copyright 2003, 2004 Free Software Foundation, Inc. + Copyright 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -15,8 +15,8 @@ You should have received a copy of the GNU General Public License along with GAS; see the file COPYING. If not, write to - the Free Software Foundation, 59 Temple Place - Suite 330, Boston, - MA 02111-1307, USA. */ + the Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ #include #include @@ -76,12 +76,12 @@ bfd_boolean absolute_literals_supported = XSHAL_USE_ABSOLUTE_LITERALS; static vliw_insn cur_vinsn; -size_t xtensa_fetch_width = XCHAL_INST_FETCH_WIDTH; +unsigned xtensa_fetch_width = XCHAL_INST_FETCH_WIDTH; static enum debug_info_type xt_saved_debug_type = DEBUG_NONE; /* Some functions are only valid in the front end. This variable - allows us to assert that we haven't crossed over into the + allows us to assert that we haven't crossed over into the back end. */ static bfd_boolean past_xtensa_end = FALSE; @@ -322,20 +322,14 @@ typedef struct op_placement_info_struct int num_formats; /* A number describing how restrictive the issue is for this opcode. For example, an opcode that fits lots of different - formats has a high freedom, as does an opcode that fits + formats has a high freedom, as does an opcode that fits only one format but many slots in that format. The most - restrictive is the opcode that fits only one slot in one + restrictive is the opcode that fits only one slot in one format. */ int issuef; - /* The single format (i.e., if the op can live in a bundle by itself), - narrowest format, and widest format the op can be bundled in - and their sizes: */ - xtensa_format single; xtensa_format narrowest; - xtensa_format widest; char narrowest_size; - char widest_size; - char single_size; + char narrowest_slot; /* formats is a bitfield with the Nth bit set if the opcode fits in the Nth xtensa_format. */ @@ -422,7 +416,6 @@ bfd_boolean directive_state[] = static void xtensa_begin_directive (int); static void xtensa_end_directive (int); -static void xtensa_dwarf2_directive_loc (int); static void xtensa_literal_prefix (char const *, int); static void xtensa_literal_position (int); static void xtensa_literal_pseudo (int); @@ -435,6 +428,8 @@ static bfd_reloc_code_real_type xtensa_elf_suffix (char **, expressionS *); /* Various Other Internal Functions. */ +extern bfd_boolean xg_is_single_relaxable_insn (TInsn *, TInsn *, bfd_boolean); +static bfd_boolean xg_build_to_insn (TInsn *, TInsn *, BuildInstr *); static void xtensa_mark_literal_pool_location (void); static addressT get_expanded_loop_offset (xtensa_opcode); static fragS *get_literal_pool_location (segT); @@ -446,8 +441,9 @@ static int total_frag_text_expansion (fragS *); /* Alignment Functions. */ -static size_t get_text_align_power (int); -static addressT get_text_align_max_fill_size (int, bfd_boolean, bfd_boolean); +static int get_text_align_power (unsigned); +static int get_text_align_max_fill_size (int, bfd_boolean, bfd_boolean); +static int branch_align_power (segT); /* Helpers for xtensa_relax_frag(). */ @@ -482,6 +478,7 @@ static void init_op_placement_info_table (void); extern bfd_boolean opcode_fits_format_slot (xtensa_opcode, xtensa_format, int); static int xg_get_single_size (xtensa_opcode); static xtensa_format xg_get_single_format (xtensa_opcode); +static int xg_get_single_slot (xtensa_opcode); /* TInsn and IStack functions. */ @@ -513,8 +510,6 @@ void set_expr_const (expressionS *, offsetT); bfd_boolean expr_is_register (const expressionS *); offsetT get_expr_register (const expressionS *); void set_expr_symbol_offset (expressionS *, symbolS *, offsetT); -static void set_expr_symbol_offset_diff - (expressionS *, symbolS *, symbolS *, offsetT); bfd_boolean expr_is_equal (expressionS *, expressionS *); static void copy_expr (expressionS *, const expressionS *); @@ -841,7 +836,7 @@ md_parse_option (int c, char *arg) /* -Qy, -Qn: SVR4 arguments controlling whether a .comment section should be emitted or not. FIXME: Not implemented. */ return 1; - + case option_prefer_l32r: if (prefer_const16) as_fatal (_("prefer-l32r conflicts with prefer-const16")); @@ -854,7 +849,7 @@ md_parse_option (int c, char *arg) prefer_const16 = 1; return 1; - case option_target_hardware: + case option_target_hardware: { int earliest, latest = 0; if (*arg == 0 || *arg == '-') @@ -947,8 +942,8 @@ xtensa_clear_insn_labels (void) } -/* The "loops_ok" argument is provided to allow ignoring labels that - define loop ends. This fixes a bug where the NOPs to align a +/* The "loops_ok" argument is provided to allow ignoring labels that + define loop ends. This fixes a bug where the NOPs to align a loop opcode were included in a previous zero-cost loop: loop a0, loopend @@ -1013,7 +1008,6 @@ const pseudo_typeS md_pseudo_table[] = { "short", xtensa_elf_cons, 2 }, { "begin", xtensa_begin_directive, 0 }, { "end", xtensa_end_directive, 0 }, - { "loc", xtensa_dwarf2_directive_loc, 0 }, { "literal", xtensa_literal_pseudo, 0 }, { "frequency", xtensa_frequency_pseudo, 0 }, { NULL, 0, 0 }, @@ -1030,21 +1024,12 @@ use_transform (void) } -static bfd_boolean -use_longcalls (void) -{ - /* After md_end, you should be checking frag by frag, rather - than state directives. */ - assert (!past_xtensa_end); - return directive_state[directive_longcalls] && use_transform (); -} - - static bfd_boolean do_align_targets (void) { - /* After md_end, you should be checking frag by frag, rather - than state directives. */ + /* Do not use this function after md_end; just look at align_targets + instead. There is no target-align directive, so alignment is either + enabled for all frags or not done at all. */ assert (!past_xtensa_end); return align_targets && use_transform (); } @@ -1150,7 +1135,7 @@ get_directive (directiveE *directive, bfd_boolean *negated) /* This code is a hack to make .begin [no-][generics|relax] exactly equivalent to .begin [no-]transform. We should remove it when we stop accepting those options. */ - + if (strncmp (input_line_pointer, "generics", strlen ("generics")) == 0) { as_warn (_("[no-]generics is deprecated; use [no-]transform instead")); @@ -1160,7 +1145,7 @@ get_directive (directiveE *directive, bfd_boolean *negated) { as_warn (_("[no-]relax is deprecated; use [no-]transform instead")); directive_string = "transform"; - } + } else directive_string = input_line_pointer; @@ -1218,7 +1203,7 @@ xtensa_begin_directive (int ignore ATTRIBUTE_UNUSED) break; case directive_literal_prefix: - /* Have to flush pending output because a movi relaxed to an l32r + /* Have to flush pending output because a movi relaxed to an l32r might produce a literal. */ md_flush_pending_output (); /* Check to see if the current fragment is a literal @@ -1369,8 +1354,7 @@ xtensa_end_directive (int ignore ATTRIBUTE_UNUSED) s = (lit_state *) state; assert (s); - if (use_literal_section) - default_lit_sections = *s; + default_lit_sections = *s; /* free the state storage */ free (s); @@ -1391,28 +1375,6 @@ xtensa_end_directive (int ignore ATTRIBUTE_UNUSED) } -/* Wrap dwarf2 functions so that we correctly support the .loc directive. */ - -static bfd_boolean xtensa_loc_directive_seen = FALSE; - -static void -xtensa_dwarf2_directive_loc (int x) -{ - xtensa_loc_directive_seen = TRUE; - dwarf2_directive_loc (x); -} - - -static void -xtensa_dwarf2_emit_insn (int size, struct dwarf2_line_info *loc) -{ - if (debug_type != DEBUG_DWARF2 && ! xtensa_loc_directive_seen) - return; - xtensa_loc_directive_seen = FALSE; - dwarf2_gen_line_info (frag_now_fix () - size, loc); -} - - /* Place an aligned literal fragment at the current location. */ static void @@ -1933,9 +1895,9 @@ tokenize_arguments (char **args, char *str) input_line_pointer = arg_end; num_args += 1; - saw_comma = FALSE; + saw_comma = FALSE; saw_colon = FALSE; - saw_arg = TRUE; + saw_arg = TRUE; break; } } @@ -1952,7 +1914,7 @@ err: else if (saw_colon) as_bad (_("extra colon")); else if (!saw_arg) - as_bad (_("missing argument")); + as_bad (_("missing argument")); else as_bad (_("missing comma or colon")); input_line_pointer = old_input_line_pointer; @@ -2052,7 +2014,7 @@ parse_arguments (TInsn *insn, int num_args, char **arg_strings) goto err; insn->ntok = tok - insn->tok; - had_error = FALSE; + had_error = FALSE; err: input_line_pointer = old_input_line_pointer; @@ -2255,7 +2217,7 @@ xg_translate_sysreg_op (char **popname, int *pnum_args, char **arg_strings) if (sr == XTENSA_UNDEFINED) { as_bad (_("invalid register number (%ld) for '%s' instruction"), - val, opname); + (long) val, opname); return -1; } } @@ -2324,7 +2286,7 @@ xtensa_translate_old_userreg_ops (char **popname) if (sr == XTENSA_UNDEFINED) { as_bad (_("invalid register number (%ld) for '%s'"), - val, opname); + (long) val, opname); return -1; } } @@ -2533,7 +2495,7 @@ get_opcode_from_buf (const char *buf, int slot) slotbuf = xtensa_insnbuf_alloc (isa); } - xtensa_insnbuf_from_chars (isa, insnbuf, buf, 0); + xtensa_insnbuf_from_chars (isa, insnbuf, (const unsigned char *) buf, 0); fmt = xtensa_format_decode (isa, insnbuf); if (fmt == XTENSA_UNDEFINED) return XTENSA_UNDEFINED; @@ -2713,12 +2675,16 @@ xtensa_insnbuf_set_operand (xtensa_insnbuf slotbuf, if (xtensa_operand_is_PCrelative (xtensa_default_isa, opcode, operand) == 1) as_bad_where ((char *) file, line, - _("operand %u is out of range for '%s'"), value, - xtensa_opcode_name (xtensa_default_isa, opcode)); + _("operand %d of '%s' has out of range value '%u'"), + operand + 1, + xtensa_opcode_name (xtensa_default_isa, opcode), + value); else as_bad_where ((char *) file, line, - _("operand %u is invalid for '%s'"), value, - xtensa_opcode_name (xtensa_default_isa, opcode)); + _("operand %d of '%s' has invalid value '%u'"), + operand + 1, + xtensa_opcode_name (xtensa_default_isa, opcode), + value); return; } @@ -2992,52 +2958,23 @@ is_unique_insn_expansion (TransitionRule *r) } -static int -xg_get_build_instr_size (BuildInstr *insn) -{ - assert (insn->typ == INSTR_INSTR); - return xg_get_single_size (insn->opcode); -} - +/* Check if there is exactly one relaxation for INSN that converts it to + another instruction of equal or larger size. If so, and if TARG is + non-null, go ahead and generate the relaxed instruction into TARG. If + NARROW_ONLY is true, then only consider relaxations that widen a narrow + instruction, i.e., ignore relaxations that convert to an instruction of + equal size. In some contexts where this function is used, only + a single widening is allowed and the NARROW_ONLY argument is used to + exclude cases like ADDI being "widened" to an ADDMI, which may + later be relaxed to an ADDMI/ADDI pair. */ -static bfd_boolean -xg_is_narrow_insn (TInsn *insn) +bfd_boolean +xg_is_single_relaxable_insn (TInsn *insn, TInsn *targ, bfd_boolean narrow_only) { TransitionTable *table = xg_build_widen_table (&transition_rule_cmp); TransitionList *l; - int num_match = 0; - assert (insn->insn_type == ITYPE_INSN); - assert (insn->opcode < table->num_opcodes); - - for (l = table->table[insn->opcode]; l != NULL; l = l->next) - { - TransitionRule *rule = l->rule; - - if (xg_instruction_matches_rule (insn, rule) - && is_unique_insn_expansion (rule)) - { - /* It only generates one instruction... */ - assert (insn->insn_type == ITYPE_INSN); - /* ...and it is a larger instruction. */ - if (xg_get_single_size (insn->opcode) - < xg_get_build_instr_size (rule->to_instr)) - { - num_match++; - if (num_match > 1) - return FALSE; - } - } - } - return (num_match == 1); -} - + TransitionRule *match = 0; -static bfd_boolean -xg_is_single_relaxable_insn (TInsn *insn) -{ - TransitionTable *table = xg_build_widen_table (&transition_rule_cmp); - TransitionList *l; - int num_match = 0; assert (insn->insn_type == ITYPE_INSN); assert (insn->opcode < table->num_opcodes); @@ -3046,21 +2983,21 @@ xg_is_single_relaxable_insn (TInsn *insn) TransitionRule *rule = l->rule; if (xg_instruction_matches_rule (insn, rule) - && is_unique_insn_expansion (rule)) + && is_unique_insn_expansion (rule) + && (xg_get_single_size (insn->opcode) + (narrow_only ? 1 : 0) + <= xg_get_single_size (rule->to_instr->opcode))) { - /* It only generates one instruction... */ - assert (insn->insn_type == ITYPE_INSN); - /* ... and it is a larger instruction. */ - if (xg_get_single_size (insn->opcode) - <= xg_get_build_instr_size (rule->to_instr)) - { - num_match++; - if (num_match > 1) - return FALSE; - } + if (match) + return FALSE; + match = rule; } } - return (num_match == 1); + if (!match) + return FALSE; + + if (targ) + xg_build_to_insn (targ, insn, match->to_instr); + return TRUE; } @@ -3312,22 +3249,28 @@ xg_symbolic_immeds_fit (const TInsn *insn, break; case O_symbol: - /* We only allow symbols for pc-relative stuff. + /* We only allow symbols for PC-relative references. If pc_frag == 0, then we don't have frag locations yet. */ - if (pc_frag == 0) + if (pc_frag == 0 + || xtensa_operand_is_PCrelative (isa, insn->opcode, i) == 0) return FALSE; - /* If it is PC-relative and the symbol is not in the same - segment as the PC.... */ - if (xtensa_operand_is_PCrelative (isa, insn->opcode, i) == 0 - || S_GET_SEGMENT (expr->X_add_symbol) != pc_seg) + /* If it is a weak symbol, then assume it won't reach. */ + if (S_IS_WEAK (expr->X_add_symbol)) return FALSE; - /* If it is a weak symbol, then assume it won't reach. This will - only affect calls when longcalls are enabled, because if - longcalls are disabled, then the call is marked as a specific - opcode. */ - if (S_IS_WEAK (expr->X_add_symbol)) + if (is_direct_call_opcode (insn->opcode) + && ! pc_frag->tc_frag_data.use_longcalls) + { + /* If callee is undefined or in a different segment, be + optimistic and assume it will be in range. */ + if (S_GET_SEGMENT (expr->X_add_symbol) != pc_seg) + return TRUE; + } + + /* Only references within a segment can be known to fit in the + operands at assembly time. */ + if (S_GET_SEGMENT (expr->X_add_symbol) != pc_seg) return FALSE; symbolP = expr->X_add_symbol; @@ -3347,7 +3290,7 @@ xg_symbolic_immeds_fit (const TInsn *insn, { target += stretch; } - + new_offset = target; xtensa_operand_do_reloc (isa, insn->opcode, i, &new_offset, pc); if (xg_check_operand (new_offset, insn->opcode, i)) @@ -3373,7 +3316,7 @@ xg_build_to_insn (TInsn *targ, TInsn *insn, BuildInstr *bi) symbolS *sym; memset (targ, 0, sizeof (TInsn)); - targ->loc = insn->loc; + targ->linenum = insn->linenum; switch (bi->typ) { case INSTR_INSTR: @@ -3582,34 +3525,6 @@ xg_expand_to_stack (IStack *istack, TInsn *insn, int lateral_steps) return FALSE; } - -static bfd_boolean -xg_expand_narrow (TInsn *targ, TInsn *insn) -{ - TransitionTable *table = xg_build_widen_table (&transition_rule_cmp); - TransitionList *l; - - assert (insn->insn_type == ITYPE_INSN); - assert (insn->opcode < table->num_opcodes); - - for (l = table->table[insn->opcode]; l != NULL; l = l->next) - { - TransitionRule *rule = l->rule; - if (xg_instruction_matches_rule (insn, rule) - && is_unique_insn_expansion (rule)) - { - /* Is it a larger instruction? */ - if (xg_get_single_size (insn->opcode) - <= xg_get_build_instr_size (rule->to_instr)) - { - xg_build_to_insn (targ, insn, rule->to_instr); - return FALSE; - } - } - } - return TRUE; -} - /* Relax the assembly instruction at least "min_steps". Return the number of steps taken. */ @@ -3645,17 +3560,13 @@ xg_assembly_relax (IStack *istack, } current_insn = *insn; - /* Walk through all of the single instruction expansions. */ - while (xg_is_single_relaxable_insn (¤t_insn)) + /* Walk through all of the single instruction expansions. */ + while (xg_is_single_relaxable_insn (¤t_insn, &single_target, FALSE)) { - int error_val = xg_expand_narrow (&single_target, ¤t_insn); - - assert (!error_val); - + steps_taken++; if (xg_symbolic_immeds_fit (&single_target, pc_seg, pc_frag, pc_offset, stretch)) { - steps_taken++; if (steps_taken >= min_steps) { istack_push (istack, &single_target); @@ -3804,7 +3715,7 @@ is_branch_jmp_to_next (TInsn *insn, fragS *fragP) if (target_frag == NULL) return FALSE; - if (is_next_frag_target (fragP->fr_next, target_frag) + if (is_next_frag_target (fragP->fr_next, target_frag) && S_GET_VALUE (sym) == target_frag->fr_address) return TRUE; @@ -3861,13 +3772,13 @@ xg_build_token_insn (BuildInstr *instr_spec, TInsn *old_insn, TInsn *new_insn) new_insn->insn_type = ITYPE_INSN; new_insn->opcode = instr_spec->opcode; new_insn->is_specific_opcode = FALSE; - new_insn->loc = old_insn->loc; + new_insn->linenum = old_insn->linenum; break; case INSTR_LITERAL_DEF: new_insn->insn_type = ITYPE_LITERAL; new_insn->opcode = XTENSA_UNDEFINED; new_insn->is_specific_opcode = FALSE; - new_insn->loc = old_insn->loc; + new_insn->linenum = old_insn->linenum; break; case INSTR_LABEL_DEF: as_bad (_("INSTR_LABEL_DEF not supported yet")); @@ -3943,15 +3854,16 @@ xg_simplify_insn (TInsn *old_insn, TInsn *new_insn) /* xg_expand_assembly_insn: (1) Simplify the instruction, i.e., l32i -> l32i.n. (2) Check the number of operands. (3) Place the instruction - tokens into the stack or if we can relax it at assembly time, place - multiple instructions/literals onto the stack. Return FALSE if no - error. */ + tokens into the stack or relax it and place multiple + instructions/literals onto the stack. Return FALSE if no error. */ static bfd_boolean xg_expand_assembly_insn (IStack *istack, TInsn *orig_insn) { int noperands; TInsn new_insn; + bfd_boolean do_expand; + memset (&new_insn, 0, sizeof (TInsn)); /* Narrow it if we can. xg_simplify_insn now does all the @@ -3977,50 +3889,37 @@ xg_expand_assembly_insn (IStack *istack, TInsn *orig_insn) /* If there are not enough operands, we will assert above. If there are too many, just cut out the extras here. */ - orig_insn->ntok = noperands; - /* Cases: - - Instructions with all constant immeds: - Assemble them and relax the instruction if possible. - Give error if not possible; no fixup needed. - - Instructions with symbolic immeds: - Assemble them with a Fix up (that may cause instruction expansion). - Also close out the fragment if the fixup may cause instruction expansion. - - There are some other special cases where we need alignment. - 1) before certain instructions with required alignment (OPCODE_ALIGN) - 2) before labels that have jumps (LABEL_ALIGN) - 3) after call instructions (RETURN_ALIGN) - Multiple of these may be possible on the same fragment. - If so, make sure to satisfy the required alignment. - Then try to get the desired alignment. */ - if (tinsn_has_invalid_symbolic_operands (orig_insn)) return TRUE; - if (orig_insn->is_specific_opcode || !use_transform ()) - { - istack_push (istack, orig_insn); - return FALSE; - } + /* If the instruction will definitely need to be relaxed, it is better + to expand it now for better scheduling. Decide whether to expand + now.... */ + do_expand = (!orig_insn->is_specific_opcode && use_transform ()); + + /* Calls should be expanded to longcalls only in the backend relaxation + so that the assembly scheduler will keep the L32R/CALLX instructions + adjacent. */ + if (is_direct_call_opcode (orig_insn->opcode)) + do_expand = FALSE; if (tinsn_has_symbolic_operands (orig_insn)) { - if (tinsn_has_complex_operands (orig_insn)) - xg_assembly_relax (istack, orig_insn, 0, 0, 0, 0, 0); - else - istack_push (istack, orig_insn); + /* The values of symbolic operands are not known yet, so only expand + now if an operand is "complex" (e.g., difference of symbols) and + will have to be stored as a literal regardless of the value. */ + if (!tinsn_has_complex_operands (orig_insn)) + do_expand = FALSE; } + else if (xg_immeds_fit (orig_insn)) + do_expand = FALSE; + + if (do_expand) + xg_assembly_relax (istack, orig_insn, 0, 0, 0, 0, 0); else - { - if (xg_immeds_fit (orig_insn)) - istack_push (istack, orig_insn); - else - xg_assembly_relax (istack, orig_insn, 0, 0, 0, 0, 0); - } + istack_push (istack, orig_insn); return FALSE; } @@ -4119,7 +4018,7 @@ xg_assemble_literal (/* const */ TInsn *insn) if (size > litsize) { /* This happens when someone writes a "movi a2, big_number". */ - as_bad_where (frag_now->fr_file, frag_now->fr_line, + as_bad_where (frag_now->fr_file, frag_now->fr_line, _("invalid immediate")); xtensa_restore_emit_state (&state); return NULL; @@ -4232,7 +4131,7 @@ xg_add_opcode_fix (TInsn *tinsn, if (opnum != get_relaxable_immed (opcode)) { as_bad (_("invalid relocation for operand %i of '%s'"), - opnum, xtensa_opcode_name (xtensa_default_isa, opcode)); + opnum + 1, xtensa_opcode_name (xtensa_default_isa, opcode)); return FALSE; } @@ -4242,7 +4141,7 @@ xg_add_opcode_fix (TInsn *tinsn, if (expr->X_op == O_lo16 || expr->X_op == O_hi16) { as_bad (_("invalid expression for operand %i of '%s'"), - opnum, xtensa_opcode_name (xtensa_default_isa, opcode)); + opnum + 1, xtensa_opcode_name (xtensa_default_isa, opcode)); return FALSE; } @@ -4266,6 +4165,7 @@ xg_add_opcode_fix (TInsn *tinsn, fmt_length = xtensa_format_length (xtensa_default_isa, fmt); the_fix = fix_new_exp (fragP, offset, fmt_length, expr, howto->pc_relative, reloc); + the_fix->fx_no_overflow = 1; if (expr->X_add_symbol && (S_IS_EXTERNAL (expr->X_add_symbol) @@ -4275,14 +4175,13 @@ xg_add_opcode_fix (TInsn *tinsn, the_fix->tc_fix_data.X_add_symbol = expr->X_add_symbol; the_fix->tc_fix_data.X_add_number = expr->X_add_number; the_fix->tc_fix_data.slot = slot; - + return TRUE; } static bfd_boolean xg_emit_insn_to_buf (TInsn *tinsn, - xtensa_format fmt, char *buf, fragS *fragP, offsetT offset, @@ -4291,6 +4190,7 @@ xg_emit_insn_to_buf (TInsn *tinsn, static xtensa_insnbuf insnbuf = NULL; bfd_boolean has_symbolic_immed = FALSE; bfd_boolean ok = TRUE; + if (!insnbuf) insnbuf = xtensa_insnbuf_alloc (xtensa_default_isa); @@ -4298,14 +4198,17 @@ xg_emit_insn_to_buf (TInsn *tinsn, if (has_symbolic_immed && build_fix) { /* Add a fixup. */ + xtensa_format fmt = xg_get_single_format (tinsn->opcode); + int slot = xg_get_single_slot (tinsn->opcode); int opnum = get_relaxable_immed (tinsn->opcode); expressionS *exp = &tinsn->tok[opnum]; - if (!xg_add_opcode_fix (tinsn, opnum, fmt, 0, exp, fragP, offset)) + if (!xg_add_opcode_fix (tinsn, opnum, fmt, slot, exp, fragP, offset)) ok = FALSE; } fragP->tc_frag_data.is_insn = TRUE; - xtensa_insnbuf_to_chars (xtensa_default_isa, insnbuf, buf, 0); + xtensa_insnbuf_to_chars (xtensa_default_isa, insnbuf, + (unsigned char *) buf, 0); return ok; } @@ -4395,7 +4298,7 @@ is_bad_loopend_opcode (const TInsn *tinsn) || opcode == xtensa_waiti_opcode || opcode == xtensa_rsr_lcount_opcode) return TRUE; - + return FALSE; } @@ -4437,7 +4340,7 @@ next_non_empty_frag (const fragS *fragP) { fragS *next_fragP = fragP->fr_next; - /* Sometimes an empty will end up here due storage allocation issues. + /* Sometimes an empty will end up here due storage allocation issues. So we have to skip until we find something legit. */ while (next_fragP && next_fragP->fr_fix == 0) next_fragP = next_fragP->fr_next; @@ -4474,7 +4377,7 @@ frag_format_size (const fragS *fragP) static xtensa_insnbuf insnbuf = NULL; xtensa_isa isa = xtensa_default_isa; xtensa_format fmt; - int fmt_size; + int fmt_size; if (!insnbuf) insnbuf = xtensa_insnbuf_alloc (isa); @@ -4482,7 +4385,8 @@ frag_format_size (const fragS *fragP) if (fragP == NULL) return XTENSA_UNDEFINED; - xtensa_insnbuf_from_chars (isa, insnbuf, fragP->fr_literal, 0); + xtensa_insnbuf_from_chars (isa, insnbuf, + (unsigned char *) fragP->fr_literal, 0); fmt = xtensa_format_decode (isa, insnbuf); if (fmt == XTENSA_UNDEFINED) @@ -4494,7 +4398,7 @@ frag_format_size (const fragS *fragP) if (fragP->fr_opcode != fragP->fr_literal) return fmt_size; - /* If during relaxation we have to pull an instruction out of a + /* If during relaxation we have to pull an instruction out of a multi-slot instruction, we will return the more conservative number. This works because alignment on bigger instructions is more restrictive than alignment on smaller instructions. @@ -4515,7 +4419,7 @@ frag_format_size (const fragS *fragP) if (fragP->tc_frag_data.slot_subtypes[0] == RELAX_IMMED_STEP1 || fragP->tc_frag_data.slot_subtypes[0] == RELAX_IMMED_STEP2) return 3; - + if (fragP->tc_frag_data.slot_subtypes[0] == RELAX_NARROW) return 2 + fragP->tc_frag_data.text_expansion[0]; @@ -4540,7 +4444,7 @@ update_next_frag_state (fragS *fragP) fragS *next_fragP = fragP->fr_next; fragS *new_target = NULL; - if (align_targets) + if (align_targets) { /* We are guaranteed there will be one of these... */ while (!(next_fragP->fr_type == rs_machine_dependent @@ -4597,7 +4501,7 @@ next_frag_is_branch_target (const fragS *fragP) static bfd_boolean next_frag_is_loop_target (const fragS *fragP) { - /* Sometimes an empty will end up here due storage allocation issues. + /* Sometimes an empty will end up here due storage allocation issues. So we have to skip until we find something legit. */ for (fragP = fragP->fr_next; fragP; fragP = fragP->fr_next) { @@ -4656,15 +4560,15 @@ xtensa_mark_literal_pool_location (void) frag_align (2, 0, 0); record_alignment (now_seg, 2); - /* We stash info in the fr_var of these frags - so we can later move the literal's fixes into this - frchain's fix list. We can use fr_var because fr_var's - interpretation depends solely on the fr_type and subtype. */ + /* We stash info in these frags so we can later move the literal's + fixes into this frchain's fix list. */ pool_location = frag_now; - frag_variant (rs_machine_dependent, 0, (int) frchain_now, + frag_now->tc_frag_data.lit_frchain = frchain_now; + frag_variant (rs_machine_dependent, 0, 0, RELAX_LITERAL_POOL_BEGIN, NULL, 0, NULL); xtensa_set_frag_assembly_state (frag_now); - frag_variant (rs_machine_dependent, 0, (int) now_seg, + frag_now->tc_frag_data.lit_seg = now_seg; + frag_variant (rs_machine_dependent, 0, 0, RELAX_LITERAL_POOL_END, NULL, 0, NULL); xtensa_set_frag_assembly_state (frag_now); @@ -4720,7 +4624,7 @@ build_nop (TInsn *tinsn, int size) allocated "buf" with at least "size" bytes. */ static void -assemble_nop (size_t size, char *buf) +assemble_nop (int size, char *buf) { static xtensa_insnbuf insnbuf = NULL; TInsn tinsn; @@ -4731,7 +4635,8 @@ assemble_nop (size_t size, char *buf) insnbuf = xtensa_insnbuf_alloc (xtensa_default_isa); tinsn_to_insnbuf (&tinsn, insnbuf); - xtensa_insnbuf_to_chars (xtensa_default_isa, insnbuf, buf, 0); + xtensa_insnbuf_to_chars (xtensa_default_isa, insnbuf, + (unsigned char *) buf, 0); } @@ -4784,10 +4689,12 @@ xtensa_set_frag_assembly_state (fragS *fragP) fragP->tc_frag_data.is_no_density = TRUE; /* This function is called from subsegs_finish, which is called - after xtensa_end, so we can't use "use_transform" or + after xtensa_end, so we can't use "use_transform" or "use_schedule" here. */ if (!directive_state[directive_transform]) fragP->tc_frag_data.is_no_transform = TRUE; + if (directive_state[directive_longcalls]) + fragP->tc_frag_data.use_longcalls = TRUE; fragP->tc_frag_data.use_absolute_literals = directive_state[directive_absolute_literals]; fragP->tc_frag_data.is_assembly_state_set = TRUE; @@ -4846,6 +4753,8 @@ xtensa_find_unmarked_state_frags (void) last_fragP->tc_frag_data.is_no_density; fragP->tc_frag_data.is_no_transform = last_fragP->tc_frag_data.is_no_transform; + fragP->tc_frag_data.use_longcalls = + last_fragP->tc_frag_data.use_longcalls; fragP->tc_frag_data.use_absolute_literals = last_fragP->tc_frag_data.use_absolute_literals; } @@ -4866,9 +4775,9 @@ xtensa_find_unaligned_branch_targets (bfd *abfd ATTRIBUTE_UNUSED, flagword flags = bfd_get_section_flags (abfd, sec); segment_info_type *seginfo = seg_info (sec); fragS *frag = seginfo->frchainP->frch_root; - + if (flags & SEC_CODE) - { + { xtensa_isa isa = xtensa_default_isa; xtensa_insnbuf insnbuf = xtensa_insnbuf_alloc (isa); while (frag != NULL) @@ -4876,17 +4785,19 @@ xtensa_find_unaligned_branch_targets (bfd *abfd ATTRIBUTE_UNUSED, if (frag->tc_frag_data.is_branch_target) { int op_size; - int frag_addr; + addressT branch_align, frag_addr; xtensa_format fmt; - xtensa_insnbuf_from_chars (isa, insnbuf, frag->fr_literal, 0); + xtensa_insnbuf_from_chars + (isa, insnbuf, (unsigned char *) frag->fr_literal, 0); fmt = xtensa_format_decode (isa, insnbuf); op_size = xtensa_format_length (isa, fmt); - frag_addr = frag->fr_address % xtensa_fetch_width; - if (frag_addr + op_size > (int) xtensa_fetch_width) + branch_align = 1 << branch_align_power (sec); + frag_addr = frag->fr_address % branch_align; + if (frag_addr + op_size > branch_align) as_warn_where (frag->fr_file, frag->fr_line, _("unaligned branch target: %d bytes at 0x%lx"), - op_size, frag->fr_address); + op_size, (long) frag->fr_address); } frag = frag->fr_next; } @@ -4904,27 +4815,28 @@ xtensa_find_unaligned_loops (bfd *abfd ATTRIBUTE_UNUSED, segment_info_type *seginfo = seg_info (sec); fragS *frag = seginfo->frchainP->frch_root; xtensa_isa isa = xtensa_default_isa; - + if (flags & SEC_CODE) - { + { xtensa_insnbuf insnbuf = xtensa_insnbuf_alloc (isa); while (frag != NULL) { if (frag->tc_frag_data.is_first_loop_insn) { int op_size; - int frag_addr; + addressT frag_addr; xtensa_format fmt; - xtensa_insnbuf_from_chars (isa, insnbuf, frag->fr_literal, 0); + xtensa_insnbuf_from_chars + (isa, insnbuf, (unsigned char *) frag->fr_literal, 0); fmt = xtensa_format_decode (isa, insnbuf); op_size = xtensa_format_length (isa, fmt); frag_addr = frag->fr_address % xtensa_fetch_width; - if (frag_addr + op_size > (signed) xtensa_fetch_width) + if (frag_addr + op_size > xtensa_fetch_width) as_warn_where (frag->fr_file, frag->fr_line, _("unaligned loop: %d bytes at 0x%lx"), - op_size, frag->fr_address); + op_size, (long) frag->fr_address); } frag = frag->fr_next; } @@ -4933,8 +4845,8 @@ xtensa_find_unaligned_loops (bfd *abfd ATTRIBUTE_UNUSED, } -static void -xg_apply_tentative_value (fixS *fixP, valueT val) +static int +xg_apply_fix_value (fixS *fixP, valueT val) { xtensa_isa isa = xtensa_default_isa; static xtensa_insnbuf insnbuf = NULL; @@ -4955,7 +4867,7 @@ xg_apply_tentative_value (fixS *fixP, valueT val) slotbuf = xtensa_insnbuf_alloc (isa); } - xtensa_insnbuf_from_chars (isa, insnbuf, fixpos, 0); + xtensa_insnbuf_from_chars (isa, insnbuf, (unsigned char *) fixpos, 0); fmt = xtensa_format_decode (isa, insnbuf); if (fmt == XTENSA_UNDEFINED) as_fatal (_("undecodable fix")); @@ -4966,18 +4878,18 @@ xg_apply_tentative_value (fixS *fixP, valueT val) /* CONST16 immediates are not PC-relative, despite the fact that we reuse the normal PC-relative operand relocations for the low part - of a CONST16 operand. The code in tc_gen_reloc does not decode - the opcodes so it is more convenient to detect this special case - here. */ + of a CONST16 operand. */ if (opcode == xtensa_const16_opcode) - return; + return 0; xtensa_insnbuf_set_operand (slotbuf, fmt, slot, opcode, get_relaxable_immed (opcode), val, fixP->fx_file, fixP->fx_line); xtensa_format_set_slot (isa, fmt, slot, insnbuf, slotbuf); - xtensa_insnbuf_to_chars (isa, insnbuf, fixpos, 0); + xtensa_insnbuf_to_chars (isa, insnbuf, (unsigned char *) fixpos, 0); + + return 1; } @@ -5088,6 +5000,16 @@ xtensa_init_fix_data (fixS *x) void xtensa_frob_label (symbolS *sym) { + float freq; + + if (cur_vinsn.inside_bundle) + { + as_bad (_("labels are not valid inside bundles")); + return; + } + + freq = get_subseg_target_freq (now_seg, now_subseg); + /* Since the label was already attached to a frag associated with the previous basic block, it now needs to be reset to the current frag. */ symbol_set_frag (sym, frag_now); @@ -5098,10 +5020,19 @@ xtensa_frob_label (symbolS *sym) else xtensa_add_insn_label (sym); - if (symbol_get_tc (sym)->is_loop_target - && (get_last_insn_flags (now_seg, now_subseg) + if (symbol_get_tc (sym)->is_loop_target) + { + if ((get_last_insn_flags (now_seg, now_subseg) & FLAG_IS_BAD_LOOPEND) != 0) - as_bad (_("invalid last instruction for a zero-overhead loop")); + as_bad (_("invalid last instruction for a zero-overhead loop")); + + xtensa_set_frag_assembly_state (frag_now); + frag_var (rs_machine_dependent, 4, 4, RELAX_LOOP_END, + frag_now->fr_symbol, frag_now->fr_offset, NULL); + + xtensa_set_frag_assembly_state (frag_now); + xtensa_move_labels (frag_now, 0, TRUE); + } /* No target aligning in the absolute section. */ if (now_seg != absolute_section @@ -5109,26 +5040,10 @@ xtensa_frob_label (symbolS *sym) && !is_unaligned_label (sym) && !generating_literals) { - float freq = get_subseg_target_freq (now_seg, now_subseg); xtensa_set_frag_assembly_state (frag_now); - /* The only time this type of frag grows is when there is a - negatable branch that needs to be relaxed as the last - instruction in a zero-overhead loop. Because alignment frags - are so common, marking them all as possibly growing four - bytes makes any worst-case analysis appear much worse than it - is. So, we make fr_var not actually reflect the amount of - memory allocated at the end of this frag, but rather the - amount of memory this frag might grow. The "4, 0" below - allocates four bytes at the end of the frag for room to grow - if we need to relax a loop end with a NOP. Frags prior to - this one might grow to align this one, but the frag itself - won't grow unless it meets the condition above. */ - -#define RELAX_LOOP_END_BYTES 4 - frag_var (rs_machine_dependent, - RELAX_LOOP_END_BYTES, (int) freq, + 0, (int) freq, RELAX_DESIRE_ALIGN_IF_TARGET, frag_now->fr_symbol, frag_now->fr_offset, NULL); xtensa_set_frag_assembly_state (frag_now); @@ -5146,6 +5061,8 @@ xtensa_frob_label (symbolS *sym) /* Loops only go forward, so they can be identified here. */ if (symbol_get_tc (sym)->is_loop_target) symbol_get_frag (sym)->tc_frag_data.is_loop_target = TRUE; + + dwarf2_emit_label (sym); } @@ -5238,7 +5155,7 @@ void md_assemble (char *str) { xtensa_isa isa = xtensa_default_isa; - char *opname; + char *opname, *file_name; unsigned opnamelen; bfd_boolean has_underbar = FALSE; char *arg_strings[MAX_INSN_ARGS]; @@ -5299,11 +5216,6 @@ md_assemble (char *str) return; } - /* Special case: The call instructions should be marked "specific opcode" - to keep them from expanding. */ - if (!use_longcalls () && is_direct_call_opcode (orig_insn.opcode)) - orig_insn.is_specific_opcode = TRUE; - /* Parse the arguments. */ if (parse_arguments (&orig_insn, num_args, arg_strings)) { @@ -5332,28 +5244,20 @@ md_assemble (char *str) return; } - dwarf2_where (&orig_insn.loc); - + /* A FLIX bundle may be spread across multiple input lines. We want to + report the first such line in the debug information. Record the line + number for each TInsn (assume the file name doesn't change), so the + first line can be found later. */ + as_where (&file_name, &orig_insn.linenum); + xg_add_branch_and_loop_targets (&orig_insn); - /* Special-case for "entry" instruction. */ - if (orig_insn.opcode == xtensa_entry_opcode) + /* Check that immediate value for ENTRY is >= 16. */ + if (orig_insn.opcode == xtensa_entry_opcode && orig_insn.ntok >= 3) { - /* Check that the third opcode (#2) is >= 16. */ - if (orig_insn.ntok >= 3) - { - expressionS *exp = &orig_insn.tok[2]; - switch (exp->X_op) - { - case O_constant: - if (exp->X_add_number < 16) - as_warn (_("entry instruction with stack decrement < 16")); - break; - - default: - as_warn (_("entry instruction with non-constant decrement")); - } - } + expressionS *exp = &orig_insn.tok[2]; + if (exp->X_op == O_constant && exp->X_add_number < 16) + as_warn (_("entry instruction with stack decrement < 16")); } /* Finish it off: @@ -5405,7 +5309,7 @@ xtensa_handle_align (fragS *fragP) int count; count = fragP->fr_next->fr_address - fragP->fr_address - fragP->fr_fix; if (count != 0) - as_bad_where (fragP->fr_file, fragP->fr_line, + as_bad_where (fragP->fr_file, fragP->fr_line, _("unaligned entry instruction")); } } @@ -5451,11 +5355,8 @@ md_pcrel_from (fixS *fixP) valueT addr = fixP->fx_where + fixP->fx_frag->fr_address; bfd_boolean alt_reloc; - if (fixP->fx_done) - return addr; - if (fixP->fx_r_type == BFD_RELOC_XTENSA_ASM_EXPAND) - return addr; + return 0; if (!insnbuf) { @@ -5464,7 +5365,7 @@ md_pcrel_from (fixS *fixP) } insn_p = &fixP->fx_frag->fr_literal[fixP->fx_where]; - xtensa_insnbuf_from_chars (isa, insnbuf, insn_p, 0); + xtensa_insnbuf_from_chars (isa, insnbuf, (unsigned char *) insn_p, 0); fmt = xtensa_format_decode (isa, insnbuf); if (fmt == XTENSA_UNDEFINED) @@ -5476,14 +5377,15 @@ md_pcrel_from (fixS *fixP) xtensa_format_get_slot (isa, fmt, slot, insnbuf, slotbuf); opcode = xtensa_opcode_decode (isa, fmt, slot, slotbuf); - /* Check for "alternate" relocation (operand not specified). */ + /* Check for "alternate" relocations (operand not specified). None + of the current uses for these are really PC-relative. */ if (alt_reloc || opcode == xtensa_const16_opcode) { if (opcode != xtensa_l32r_opcode && opcode != xtensa_const16_opcode) as_fatal (_("invalid relocation for '%s' instruction"), xtensa_opcode_name (isa, opcode)); - return addr; + return 0; } opnum = get_relaxable_immed (opcode); @@ -5495,7 +5397,7 @@ md_pcrel_from (fixS *fixP) fixP->fx_line, _("invalid relocation for operand %d of '%s'"), opnum, xtensa_opcode_name (isa, opcode)); - return addr; + return 0; } return 0 - opnd_value; } @@ -5507,7 +5409,8 @@ int xtensa_force_relocation (fixS *fix) { switch (fix->fx_r_type) - { + { + case BFD_RELOC_XTENSA_ASM_EXPAND: case BFD_RELOC_XTENSA_SLOT0_ALT: case BFD_RELOC_XTENSA_SLOT1_ALT: case BFD_RELOC_XTENSA_SLOT2_ALT: @@ -5523,8 +5426,6 @@ xtensa_force_relocation (fixS *fix) case BFD_RELOC_XTENSA_SLOT12_ALT: case BFD_RELOC_XTENSA_SLOT13_ALT: case BFD_RELOC_XTENSA_SLOT14_ALT: - case BFD_RELOC_VTABLE_INHERIT: - case BFD_RELOC_VTABLE_ENTRY: return 1; default: break; @@ -5538,6 +5439,33 @@ xtensa_force_relocation (fixS *fix) } +/* TC_VALIDATE_FIX_SUB hook */ + +int +xtensa_validate_fix_sub (fixS *fix) +{ + segT add_symbol_segment, sub_symbol_segment; + + /* The difference of two symbols should be resolved by the assembler when + linkrelax is not set. If the linker may relax the section containing + the symbols, then an Xtensa DIFF relocation must be generated so that + the linker knows to adjust the difference value. */ + if (!linkrelax || fix->fx_addsy == NULL) + return 0; + + /* Make sure both symbols are in the same segment, and that segment is + "normal" and relaxable. If the segment is not "normal", then the + fix is not valid. If the segment is not "relaxable", then the fix + should have been handled earlier. */ + add_symbol_segment = S_GET_SEGMENT (fix->fx_addsy); + if (! SEG_NORMAL (add_symbol_segment) || + ! relaxable_section (add_symbol_segment)) + return 0; + sub_symbol_segment = S_GET_SEGMENT (fix->fx_subsy); + return (sub_symbol_segment == add_symbol_segment); +} + + /* NO_PSEUDO_DOT hook */ /* This function has nothing to do with pseudo dots, but this is the @@ -5585,59 +5513,142 @@ xtensa_fix_adjustable (fixS *fixP) || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY) return 0; - if (fixP->fx_addsy - && (S_IS_EXTERNAL (fixP->fx_addsy) || S_IS_WEAK (fixP->fx_addsy))) - return 0; - -#if 0 - /* We may someday want to enable this code to preserve relocations for - non-PC-relative fixes, possibly under control of a PIC flag. */ - return (fixP->fx_pcrel - || (fixP->fx_subsy != NULL - && (S_GET_SEGMENT (fixP->fx_subsy) - == S_GET_SEGMENT (fixP->fx_addsy))) - || S_IS_LOCAL (fixP->fx_addsy)); -#else return 1; -#endif } void -md_apply_fix3 (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) +md_apply_fix (fixS *fixP, valueT *valP, segT seg) { - if (fixP->fx_pcrel == 0 && fixP->fx_addsy == 0) - { - char *const fixpos = fixP->fx_frag->fr_literal + fixP->fx_where; + char *const fixpos = fixP->fx_frag->fr_literal + fixP->fx_where; + valueT val = 0; - switch (fixP->fx_r_type) + /* Subtracted symbols are only allowed for a few relocation types, and + unless linkrelax is enabled, they should not make it to this point. */ + if (fixP->fx_subsy && !(linkrelax && (fixP->fx_r_type == BFD_RELOC_32 + || fixP->fx_r_type == BFD_RELOC_16 + || fixP->fx_r_type == BFD_RELOC_8))) + as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex")); + + switch (fixP->fx_r_type) + { + case BFD_RELOC_32: + case BFD_RELOC_16: + case BFD_RELOC_8: + if (fixP->fx_subsy) { - case BFD_RELOC_XTENSA_ASM_EXPAND: - fixP->fx_done = 1; - break; + switch (fixP->fx_r_type) + { + case BFD_RELOC_8: + fixP->fx_r_type = BFD_RELOC_XTENSA_DIFF8; + break; + case BFD_RELOC_16: + fixP->fx_r_type = BFD_RELOC_XTENSA_DIFF16; + break; + case BFD_RELOC_32: + fixP->fx_r_type = BFD_RELOC_XTENSA_DIFF32; + break; + default: + break; + } - case BFD_RELOC_XTENSA_ASM_SIMPLIFY: - as_bad (_("unhandled local relocation fix %s"), - bfd_get_reloc_code_name (fixP->fx_r_type)); - break; + /* An offset is only allowed when it results from adjusting a + local symbol into a section-relative offset. If the offset + came from the original expression, tc_fix_adjustable will have + prevented the fix from being converted to a section-relative + form so that we can flag the error here. */ + if (fixP->fx_offset != 0 && !symbol_section_p (fixP->fx_addsy)) + as_bad_where (fixP->fx_file, fixP->fx_line, + _("cannot represent subtraction with an offset")); - case BFD_RELOC_32: - case BFD_RELOC_16: - case BFD_RELOC_8: - /* The only one we support that isn't an instruction field. */ - md_number_to_chars (fixpos, *valP, fixP->fx_size); + val = (S_GET_VALUE (fixP->fx_addsy) + fixP->fx_offset + - S_GET_VALUE (fixP->fx_subsy)); + + /* The difference value gets written out, and the DIFF reloc + identifies the address of the subtracted symbol (i.e., the one + with the lowest address). */ + *valP = val; + fixP->fx_offset -= val; + fixP->fx_subsy = NULL; + } + else if (! fixP->fx_addsy) + { + val = *valP; fixP->fx_done = 1; - break; + } + /* fall through */ - case BFD_RELOC_VTABLE_INHERIT: - case BFD_RELOC_VTABLE_ENTRY: - fixP->fx_done = 0; - break; + case BFD_RELOC_XTENSA_PLT: + md_number_to_chars (fixpos, val, fixP->fx_size); + fixP->fx_no_overflow = 0; /* Use the standard overflow check. */ + break; - default: - as_bad (_("unhandled local relocation fix %s"), - bfd_get_reloc_code_name (fixP->fx_r_type)); + case BFD_RELOC_XTENSA_SLOT0_OP: + case BFD_RELOC_XTENSA_SLOT1_OP: + case BFD_RELOC_XTENSA_SLOT2_OP: + case BFD_RELOC_XTENSA_SLOT3_OP: + case BFD_RELOC_XTENSA_SLOT4_OP: + case BFD_RELOC_XTENSA_SLOT5_OP: + case BFD_RELOC_XTENSA_SLOT6_OP: + case BFD_RELOC_XTENSA_SLOT7_OP: + case BFD_RELOC_XTENSA_SLOT8_OP: + case BFD_RELOC_XTENSA_SLOT9_OP: + case BFD_RELOC_XTENSA_SLOT10_OP: + case BFD_RELOC_XTENSA_SLOT11_OP: + case BFD_RELOC_XTENSA_SLOT12_OP: + case BFD_RELOC_XTENSA_SLOT13_OP: + case BFD_RELOC_XTENSA_SLOT14_OP: + if (linkrelax) + { + /* Write the tentative value of a PC-relative relocation to a + local symbol into the instruction. The value will be ignored + by the linker, and it makes the object file disassembly + readable when all branch targets are encoded in relocations. */ + + assert (fixP->fx_addsy); + if (S_GET_SEGMENT (fixP->fx_addsy) == seg && !fixP->fx_plt + && !S_FORCE_RELOC (fixP->fx_addsy, 1)) + { + val = (S_GET_VALUE (fixP->fx_addsy) + fixP->fx_offset + - md_pcrel_from (fixP)); + (void) xg_apply_fix_value (fixP, val); + } + } + else if (! fixP->fx_addsy) + { + val = *valP; + if (xg_apply_fix_value (fixP, val)) + fixP->fx_done = 1; } + break; + + case BFD_RELOC_XTENSA_ASM_EXPAND: + case BFD_RELOC_XTENSA_SLOT0_ALT: + case BFD_RELOC_XTENSA_SLOT1_ALT: + case BFD_RELOC_XTENSA_SLOT2_ALT: + case BFD_RELOC_XTENSA_SLOT3_ALT: + case BFD_RELOC_XTENSA_SLOT4_ALT: + case BFD_RELOC_XTENSA_SLOT5_ALT: + case BFD_RELOC_XTENSA_SLOT6_ALT: + case BFD_RELOC_XTENSA_SLOT7_ALT: + case BFD_RELOC_XTENSA_SLOT8_ALT: + case BFD_RELOC_XTENSA_SLOT9_ALT: + case BFD_RELOC_XTENSA_SLOT10_ALT: + case BFD_RELOC_XTENSA_SLOT11_ALT: + case BFD_RELOC_XTENSA_SLOT12_ALT: + case BFD_RELOC_XTENSA_SLOT13_ALT: + case BFD_RELOC_XTENSA_SLOT14_ALT: + /* These all need to be resolved at link-time. Do nothing now. */ + break; + + case BFD_RELOC_VTABLE_INHERIT: + case BFD_RELOC_VTABLE_ENTRY: + fixP->fx_done = 0; + break; + + default: + as_bad (_("unhandled local relocation fix %s"), + bfd_get_reloc_code_name (fixP->fx_r_type)); } } @@ -5696,10 +5707,9 @@ md_estimate_size_before_relax (fragS *fragP, segT seg ATTRIBUTE_UNUSED) format. */ arelent * -tc_gen_reloc (asection *section, fixS *fixp) +tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp) { arelent *reloc; - bfd_boolean apply_tentative_value = FALSE; reloc = (arelent *) xmalloc (sizeof (arelent)); reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); @@ -5710,128 +5720,7 @@ tc_gen_reloc (asection *section, fixS *fixp) They'd better have been fully resolved by this point. */ assert ((int) fixp->fx_r_type > 0); - if (linkrelax && fixp->fx_subsy - && (fixp->fx_r_type == BFD_RELOC_8 - || fixp->fx_r_type == BFD_RELOC_16 - || fixp->fx_r_type == BFD_RELOC_32)) - { - int diff_size = 0; - bfd_vma diff_value, diff_mask = 0; - - switch (fixp->fx_r_type) - { - case BFD_RELOC_8: - fixp->fx_r_type = BFD_RELOC_XTENSA_DIFF8; - diff_size = 1; - diff_mask = 0xff; - break; - case BFD_RELOC_16: - fixp->fx_r_type = BFD_RELOC_XTENSA_DIFF16; - diff_size = 2; - diff_mask = 0xffff; - break; - case BFD_RELOC_32: - fixp->fx_r_type = BFD_RELOC_XTENSA_DIFF32; - diff_size = 4; - diff_mask = 0xffffffff; - break; - default: - break; - } - - /* An offset is only allowed when it results from adjusting a local - symbol into a section-relative offset. If the offset came from the - original expression, tc_fix_adjustable will have prevented the fix - from being converted to a section-relative form so that we can flag - the error here. */ - if (fixp->fx_offset != 0 && !symbol_section_p (fixp->fx_addsy)) - { - as_bad_where (fixp->fx_file, fixp->fx_line, - _("cannot represent subtraction with an offset")); - free (reloc->sym_ptr_ptr); - free (reloc); - return NULL; - } - - assert (S_GET_SEGMENT (fixp->fx_addsy) - == S_GET_SEGMENT (fixp->fx_subsy)); - - diff_value = (S_GET_VALUE (fixp->fx_addsy) + fixp->fx_offset - - S_GET_VALUE (fixp->fx_subsy)); - - /* Check for overflow. */ - if ((diff_value & ~diff_mask) != 0) - { - as_bad_where (fixp->fx_file, fixp->fx_line, - _("value of %ld too large"), diff_value); - free (reloc->sym_ptr_ptr); - free (reloc); - return NULL; - } - - md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where, - diff_value, diff_size); - reloc->addend = fixp->fx_offset - diff_value; - } - else - { - reloc->addend = fixp->fx_offset; - - switch (fixp->fx_r_type) - { - case BFD_RELOC_XTENSA_SLOT0_OP: - case BFD_RELOC_XTENSA_SLOT1_OP: - case BFD_RELOC_XTENSA_SLOT2_OP: - case BFD_RELOC_XTENSA_SLOT3_OP: - case BFD_RELOC_XTENSA_SLOT4_OP: - case BFD_RELOC_XTENSA_SLOT5_OP: - case BFD_RELOC_XTENSA_SLOT6_OP: - case BFD_RELOC_XTENSA_SLOT7_OP: - case BFD_RELOC_XTENSA_SLOT8_OP: - case BFD_RELOC_XTENSA_SLOT9_OP: - case BFD_RELOC_XTENSA_SLOT10_OP: - case BFD_RELOC_XTENSA_SLOT11_OP: - case BFD_RELOC_XTENSA_SLOT12_OP: - case BFD_RELOC_XTENSA_SLOT13_OP: - case BFD_RELOC_XTENSA_SLOT14_OP: - /* As a special case, the immediate value for a CONST16 opcode - should not be applied, since this kind of relocation is - handled specially for CONST16 and is not really PC-relative. - Rather than decode the opcode here, just wait and handle it - in xg_apply_tentative_value. */ - apply_tentative_value = TRUE; - break; - - case BFD_RELOC_XTENSA_SLOT0_ALT: - case BFD_RELOC_XTENSA_SLOT1_ALT: - case BFD_RELOC_XTENSA_SLOT2_ALT: - case BFD_RELOC_XTENSA_SLOT3_ALT: - case BFD_RELOC_XTENSA_SLOT4_ALT: - case BFD_RELOC_XTENSA_SLOT5_ALT: - case BFD_RELOC_XTENSA_SLOT6_ALT: - case BFD_RELOC_XTENSA_SLOT7_ALT: - case BFD_RELOC_XTENSA_SLOT8_ALT: - case BFD_RELOC_XTENSA_SLOT9_ALT: - case BFD_RELOC_XTENSA_SLOT10_ALT: - case BFD_RELOC_XTENSA_SLOT11_ALT: - case BFD_RELOC_XTENSA_SLOT12_ALT: - case BFD_RELOC_XTENSA_SLOT13_ALT: - case BFD_RELOC_XTENSA_SLOT14_ALT: - case BFD_RELOC_XTENSA_ASM_EXPAND: - case BFD_RELOC_32: - case BFD_RELOC_XTENSA_PLT: - case BFD_RELOC_VTABLE_INHERIT: - case BFD_RELOC_VTABLE_ENTRY: - break; - - case BFD_RELOC_XTENSA_ASM_SIMPLIFY: - as_warn (_("emitting simplification relocation")); - break; - - default: - as_warn (_("emitting unknown relocation")); - } - } + reloc->addend = fixp->fx_offset; reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type); if (reloc->howto == NULL) @@ -5848,35 +5737,17 @@ tc_gen_reloc (asection *section, fixS *fixp) as_fatal (_("internal error? cannot generate `%s' relocation"), bfd_get_reloc_code_name (fixp->fx_r_type)); - /* Write the tentative value of a PC-relative relocation to a local symbol - into the instruction. The value will be ignored by the linker, and it - makes the object file disassembly readable when the linkrelax flag is - set and all branch targets are encoded in relocations. */ - - if (linkrelax && apply_tentative_value && fixp->fx_pcrel) - { - valueT val; - assert (fixp->fx_addsy); - if (S_GET_SEGMENT (fixp->fx_addsy) == section && !fixp->fx_plt - && !S_FORCE_RELOC (fixp->fx_addsy, 1)) - { - val = (S_GET_VALUE (fixp->fx_addsy) + fixp->fx_offset - - md_pcrel_from (fixp)); - xg_apply_tentative_value (fixp, val); - } - } - - return reloc; -} + return reloc; +} /* Checks for resource conflicts between instructions. */ -/* The func unit stuff could be implemented as bit-vectors rather - than the iterative approach here. If it ends up being too +/* The func unit stuff could be implemented as bit-vectors rather + than the iterative approach here. If it ends up being too slow, we will switch it. */ -resource_table * +resource_table * new_resource_table (void *data, int cycles, int nu, @@ -5896,15 +5767,15 @@ new_resource_table (void *data, rt->opcode_unit_use = ouuf; rt->opcode_unit_stage = ousf; - rt->units = (char **) xcalloc (cycles, sizeof (char *)); + rt->units = (unsigned char **) xcalloc (cycles, sizeof (unsigned char *)); for (i = 0; i < cycles; i++) - rt->units[i] = (char *) xcalloc (nu, sizeof (char)); + rt->units[i] = (unsigned char *) xcalloc (nu, sizeof (unsigned char)); return rt; } -void +void clear_resource_table (resource_table *rt) { int i, j; @@ -5916,7 +5787,7 @@ clear_resource_table (resource_table *rt) /* We never shrink it, just fake it into thinking so. */ -void +void resize_resource_table (resource_table *rt, int cycles) { int i, old_cycles; @@ -5928,21 +5799,23 @@ resize_resource_table (resource_table *rt, int cycles) old_cycles = rt->allocated_cycles; rt->allocated_cycles = cycles; - rt->units = xrealloc (rt->units, sizeof (char *) * rt->allocated_cycles); + rt->units = xrealloc (rt->units, + rt->allocated_cycles * sizeof (unsigned char *)); for (i = 0; i < old_cycles; i++) - rt->units[i] = xrealloc (rt->units[i], sizeof (char) * rt->num_units); + rt->units[i] = xrealloc (rt->units[i], + rt->num_units * sizeof (unsigned char)); for (i = old_cycles; i < cycles; i++) - rt->units[i] = xcalloc (rt->num_units, sizeof (char)); + rt->units[i] = xcalloc (rt->num_units, sizeof (unsigned char)); } -bfd_boolean +bfd_boolean resources_available (resource_table *rt, xtensa_opcode opcode, int cycle) { int i; int uses = (rt->opcode_num_units) (rt->data, opcode); - for (i = 0; i < uses; i++) + for (i = 0; i < uses; i++) { xtensa_funcUnit unit = (rt->opcode_unit_use) (rt->data, opcode, i); int stage = (rt->opcode_unit_stage) (rt->data, opcode, i); @@ -5953,20 +5826,20 @@ resources_available (resource_table *rt, xtensa_opcode opcode, int cycle) } return TRUE; } - -void + +void reserve_resources (resource_table *rt, xtensa_opcode opcode, int cycle) { int i; int uses = (rt->opcode_num_units) (rt->data, opcode); - for (i = 0; i < uses; i++) + for (i = 0; i < uses; i++) { xtensa_funcUnit unit = (rt->opcode_unit_use) (rt->data, opcode, i); int stage = (rt->opcode_unit_stage) (rt->data, opcode, i); - /* Note that this allows resources to be oversubscribed. That's - essential to the way the optional scheduler works. + /* Note that this allows resources to be oversubscribed. That's + essential to the way the optional scheduler works. resources_available reports when a resource is over-subscribed, so it's easy to tell. */ rt->units[stage + cycle][unit]++; @@ -5974,34 +5847,34 @@ reserve_resources (resource_table *rt, xtensa_opcode opcode, int cycle) } -void +void release_resources (resource_table *rt, xtensa_opcode opcode, int cycle) { int i; int uses = (rt->opcode_num_units) (rt->data, opcode); - for (i = 0; i < uses; i++) + for (i = 0; i < uses; i++) { xtensa_funcUnit unit = (rt->opcode_unit_use) (rt->data, opcode, i); int stage = (rt->opcode_unit_stage) (rt->data, opcode, i); + assert (rt->units[stage + cycle][unit] > 0); rt->units[stage + cycle][unit]--; - assert (rt->units[stage + cycle][unit] >= 0); } } - + /* Wrapper functions make parameterized resource reservation more convenient. */ -int +int opcode_funcUnit_use_unit (void *data, xtensa_opcode opcode, int idx) { xtensa_funcUnit_use *use = xtensa_opcode_funcUnit_use (data, opcode, idx); - return use->unit; + return use->unit; } -int +int opcode_funcUnit_use_stage (void *data, xtensa_opcode opcode, int idx) { xtensa_funcUnit_use *use = xtensa_opcode_funcUnit_use (data, opcode, idx); @@ -6011,9 +5884,9 @@ opcode_funcUnit_use_stage (void *data, xtensa_opcode opcode, int idx) /* Note that this function does not check issue constraints, but solely whether the hardware is available to execute the given - instructions together. It also doesn't check if the tinsns + instructions together. It also doesn't check if the tinsns write the same state, or access the same tieports. That is - checked by check_t1_t2_read_write. */ + checked by check_t1_t2_reads_and_writes. */ static bfd_boolean resources_conflict (vliw_insn *vinsn) @@ -6025,7 +5898,7 @@ resources_conflict (vliw_insn *vinsn) if (vinsn->num_slots == 1) return FALSE; - if (rt == NULL) + if (rt == NULL) { xtensa_isa isa = xtensa_default_isa; rt = new_resource_table @@ -6054,7 +5927,6 @@ resources_conflict (vliw_insn *vinsn) static bfd_boolean find_vinsn_conflicts (vliw_insn *); static xtensa_format xg_find_narrowest_format (vliw_insn *); -static void bundle_single_op (TInsn *); static void xg_assemble_vliw_tokens (vliw_insn *); @@ -6066,10 +5938,13 @@ finish_vinsn (vliw_insn *vinsn) IStack slotstack; int i; char *file_name; - int line; + unsigned line; if (find_vinsn_conflicts (vinsn)) - return; + { + xg_clear_vinsn (vinsn); + return; + } /* First, find a format that works. */ if (vinsn->format == XTENSA_UNDEFINED) @@ -6101,7 +5976,7 @@ finish_vinsn (vliw_insn *vinsn) return; } - if (resources_conflict (vinsn)) + if (resources_conflict (vinsn)) { as_where (&file_name, &line); as_bad_where (file_name, line, _("illegal resource usage in bundle")); @@ -6151,7 +6026,7 @@ finish_vinsn (vliw_insn *vinsn) return; } - for (j = 0; j < slotstack.ninsn - 1; j++) + for (j = 0; j < slotstack.ninsn; j++) { TInsn *insn = &slotstack.insn[j]; if (insn->insn_type == ITYPE_LITERAL) @@ -6161,9 +6036,11 @@ finish_vinsn (vliw_insn *vinsn) } else { + assert (insn->insn_type == ITYPE_INSN); if (lit_sym) xg_resolve_literals (insn, lit_sym); - emit_single_op (insn); + if (j != slotstack.ninsn - 1) + emit_single_op (insn); } } @@ -6177,11 +6054,11 @@ finish_vinsn (vliw_insn *vinsn) } else { - bundle_single_op (&slotstack.insn[slotstack.ninsn - 1]); + emit_single_op (&slotstack.insn[slotstack.ninsn - 1]); if (vinsn->format == XTENSA_UNDEFINED) vinsn->slots[i].opcode = xtensa_nop_opcode; else - vinsn->slots[i].opcode + vinsn->slots[i].opcode = xtensa_format_slot_nop_opcode (xtensa_default_isa, vinsn->format, i); @@ -6197,7 +6074,7 @@ finish_vinsn (vliw_insn *vinsn) } /* Now check resource conflicts on the modified bundle. */ - if (resources_conflict (vinsn)) + if (resources_conflict (vinsn)) { as_where (&file_name, &line); as_bad_where (file_name, line, _("illegal resource usage in bundle")); @@ -6297,12 +6174,12 @@ find_vinsn_conflicts (vliw_insn *vinsn) xtensa_opcode_name (isa, op2->opcode), j); return TRUE; case 'e': - as_bad (_("opcodes '%s' (slot %d) and '%s' (slot %d) write the same queue"), + as_bad (_("opcodes '%s' (slot %d) and '%s' (slot %d) write the same port"), xtensa_opcode_name (isa, op1->opcode), i, xtensa_opcode_name (isa, op2->opcode), j); return TRUE; case 'f': - as_bad (_("opcodes '%s' (slot %d) and '%s' (slot %d) both have volatile queue accesses"), + as_bad (_("opcodes '%s' (slot %d) and '%s' (slot %d) both have volatile port accesses"), xtensa_opcode_name (isa, op1->opcode), i, xtensa_opcode_name (isa, op2->opcode), j); return TRUE; @@ -6326,17 +6203,17 @@ find_vinsn_conflicts (vliw_insn *vinsn) } -/* Check how the result registers of t1 and t2 relate. +/* Check how the state used by t1 and t2 relate. Cases found are: case A: t1 reads a register t2 writes (an antidependency within a bundle) case B: no relationship between what is read and written (both could read the same reg though) - case C: t1 writes a register t2 writes (a register conflict within a + case C: t1 writes a register t2 writes (a register conflict within a bundle) case D: t1 writes a state that t2 also writes case E: t1 writes a tie queue that t2 also writes - case F: two volatile queue writes + case F: two volatile queue accesses */ static char @@ -6432,7 +6309,7 @@ check_t1_t2_reads_and_writes (TInsn *t1, TInsn *t2) { xtensa_state t1_so = xtensa_stateOperand_state (isa, t1->opcode, i); t1_inout = xtensa_stateOperand_inout (isa, t1->opcode, i); - if (t1_so != t2_so) + if (t1_so != t2_so) continue; if (t2_inout == 'i' && (t1_inout == 'm' || t1_inout == 'o')) @@ -6440,61 +6317,64 @@ check_t1_t2_reads_and_writes (TInsn *t1, TInsn *t2) conflict = 'a'; continue; } - + if (t1_inout == 'i' && (t2_inout == 'm' || t2_inout == 'o')) { conflict = 'a'; continue; } - + if (t1_inout != 'i' && t2_inout != 'i') return 'd'; - } + } } /* Check tieports. */ t1_interfaces = xtensa_opcode_num_interfaceOperands (isa, t1->opcode); t2_interfaces = xtensa_opcode_num_interfaceOperands (isa, t2->opcode); - for (j = 0; j < t2_interfaces; j++) + for (j = 0; j < t2_interfaces; j++) { xtensa_interface t2_int = xtensa_interfaceOperand_interface (isa, t2->opcode, j); - t2_inout = xtensa_interface_inout (isa, j); - if (xtensa_interface_has_side_effect (isa, t2_int) == 1 - && t2_inout != 'i') + int t2_class = xtensa_interface_class_id (isa, t2_int); + + t2_inout = xtensa_interface_inout (isa, t2_int); + if (xtensa_interface_has_side_effect (isa, t2_int) == 1) t2_volatile = TRUE; + for (i = 0; i < t1_interfaces; i++) { xtensa_interface t1_int = xtensa_interfaceOperand_interface (isa, t1->opcode, j); - t1_inout = xtensa_interface_inout (isa, i); - if (xtensa_interface_has_side_effect (isa, t1_int) == 1 - && t1_inout != 'i') + int t1_class = xtensa_interface_class_id (isa, t1_int); + + t1_inout = xtensa_interface_inout (isa, t1_int); + if (xtensa_interface_has_side_effect (isa, t1_int) == 1) t1_volatile = TRUE; - + + if (t1_volatile && t2_volatile && (t1_class == t2_class)) + return 'f'; + if (t1_int != t2_int) continue; - + if (t2_inout == 'i' && t1_inout == 'o') { conflict = 'a'; continue; } - + if (t1_inout == 'i' && t2_inout == 'o') { conflict = 'a'; continue; } - + if (t1_inout != 'i' && t2_inout != 'i') return 'e'; } } - if (t1_volatile && t2_volatile) - return 'f'; - return conflict; } @@ -6512,6 +6392,9 @@ xg_find_narrowest_format (vliw_insn *vinsn) vliw_insn v_copy = *vinsn; xtensa_opcode nop_opcode = xtensa_nop_opcode; + if (vinsn->num_slots == 1) + return xg_get_single_format (vinsn->slots[0].opcode); + for (format = 0; format < xtensa_isa_num_formats (isa); format++) { v_copy = *vinsn; @@ -6537,22 +6420,11 @@ xg_find_narrowest_format (vliw_insn *vinsn) /* Try the widened version. */ if (!v_copy.slots[slot].keep_wide && !v_copy.slots[slot].is_specific_opcode - && xg_is_narrow_insn (&v_copy.slots[slot]) - && !xg_expand_narrow (&widened, &v_copy.slots[slot]) + && xg_is_single_relaxable_insn (&v_copy.slots[slot], + &widened, TRUE) && opcode_fits_format_slot (widened.opcode, format, slot)) { - /* The xg_is_narrow clause requires some explanation: - - addi can be "widened" to an addmi, which is then - expanded to an addmi/addi pair if the immediate - requires it, but here we must have a single widen - only. - - xg_is_narrow tells us that addi isn't really - narrow. The widen_spec_list says that there are - other cases. */ - v_copy.slots[slot] = widened; fit++; } @@ -6581,8 +6453,9 @@ xg_find_narrowest_format (vliw_insn *vinsn) each tinsn in the vinsn. */ static int -relaxation_requirements (vliw_insn *vinsn) +relaxation_requirements (vliw_insn *vinsn, bfd_boolean *pfinish_frag) { + bfd_boolean finish_frag = FALSE; int extra_space = 0; int slot; @@ -6593,20 +6466,13 @@ relaxation_requirements (vliw_insn *vinsn) { /* A narrow instruction could be widened later to help alignment issues. */ - if (xg_is_narrow_insn (tinsn) + if (xg_is_single_relaxable_insn (tinsn, 0, TRUE) && !tinsn->is_specific_opcode && vinsn->num_slots == 1) { /* Difference in bytes between narrow and wide insns... */ extra_space += 1; tinsn->subtype = RELAX_NARROW; - tinsn->record_fix = TRUE; - break; - } - else - { - tinsn->record_fix = FALSE; - /* No extra_space needed. */ } } else @@ -6619,7 +6485,7 @@ relaxation_requirements (vliw_insn *vinsn) extra_space += 3; /* for the nop size */ tinsn->subtype = RELAX_ADD_NOP_IF_PRE_LOOP_END; } - + /* Need to assemble it with space for the relocation. */ if (xg_is_relaxable_insn (tinsn, 0) && !tinsn->is_specific_opcode) @@ -6627,59 +6493,48 @@ relaxation_requirements (vliw_insn *vinsn) int max_size = xg_get_max_insn_widen_size (tinsn->opcode); int max_literal_size = xg_get_max_insn_widen_literal_size (tinsn->opcode); - + tinsn->literal_space = max_literal_size; - + tinsn->subtype = RELAX_IMMED; - tinsn->record_fix = FALSE; extra_space += max_size; } else { - tinsn->record_fix = TRUE; - /* No extra space needed. */ + /* A fix record will be added for this instruction prior + to relaxation, so make it end the frag. */ + finish_frag = TRUE; } } } + *pfinish_frag = finish_frag; return extra_space; } static void -bundle_single_op (TInsn *orig_insn) +bundle_tinsn (TInsn *tinsn, vliw_insn *vinsn) { xtensa_isa isa = xtensa_default_isa; - vliw_insn v; - int slot; - - xg_init_vinsn (&v); - v.format = op_placement_table[orig_insn->opcode].narrowest; - assert (v.format != XTENSA_UNDEFINED); - v.num_slots = xtensa_format_num_slots (isa, v.format); + int slot, chosen_slot; - for (slot = 0; - !opcode_fits_format_slot (orig_insn->opcode, v.format, slot); - slot++) - { - v.slots[slot].opcode = - xtensa_format_slot_nop_opcode (isa, v.format, slot); - v.slots[slot].ntok = 0; - v.slots[slot].insn_type = ITYPE_INSN; - } - - v.slots[slot] = *orig_insn; - slot++; + vinsn->format = xg_get_single_format (tinsn->opcode); + assert (vinsn->format != XTENSA_UNDEFINED); + vinsn->num_slots = xtensa_format_num_slots (isa, vinsn->format); - for ( ; slot < v.num_slots; slot++) + chosen_slot = xg_get_single_slot (tinsn->opcode); + for (slot = 0; slot < vinsn->num_slots; slot++) { - v.slots[slot].opcode = - xtensa_format_slot_nop_opcode (isa, v.format, slot); - v.slots[slot].ntok = 0; - v.slots[slot].insn_type = ITYPE_INSN; + if (slot == chosen_slot) + vinsn->slots[slot] = *tinsn; + else + { + vinsn->slots[slot].opcode = + xtensa_format_slot_nop_opcode (isa, vinsn->format, slot); + vinsn->slots[slot].ntok = 0; + vinsn->slots[slot].insn_type = ITYPE_INSN; + } } - - finish_vinsn (&v); - xg_free_vinsn (&v); } @@ -6694,10 +6549,10 @@ emit_single_op (TInsn *orig_insn) istack_init (&istack); /* Special-case for "movi aX, foo" which is guaranteed to need relaxing. - Because the scheduling and bundling characteristics of movi and - l32r or const16 are so different, we can do much better if we relax + Because the scheduling and bundling characteristics of movi and + l32r or const16 are so different, we can do much better if we relax it prior to scheduling and bundling, rather than after. */ - if ((orig_insn->opcode == xtensa_movi_opcode + if ((orig_insn->opcode == xtensa_movi_opcode || orig_insn->opcode == xtensa_movi_n_opcode) && !cur_vinsn.inside_bundle && (orig_insn->tok[1].X_op == O_symbol @@ -6710,7 +6565,7 @@ emit_single_op (TInsn *orig_insn) for (i = 0; i < istack.ninsn; i++) { TInsn *insn = &istack.insn[i]; - switch (insn->insn_type) + switch (insn->insn_type) { case ITYPE_LITERAL: assert (lit_sym == NULL); @@ -6729,11 +6584,17 @@ emit_single_op (TInsn *orig_insn) } break; case ITYPE_INSN: - if (lit_sym) - xg_resolve_literals (insn, lit_sym); - if (label_sym) - xg_resolve_labels (insn, label_sym); - bundle_single_op (insn); + { + vliw_insn v; + if (lit_sym) + xg_resolve_literals (insn, lit_sym); + if (label_sym) + xg_resolve_labels (insn, label_sym); + xg_init_vinsn (&v); + bundle_tinsn (insn, &v); + finish_vinsn (&v); + xg_free_vinsn (&v); + } break; default: assert (0); @@ -6762,7 +6623,7 @@ total_frag_text_expansion (fragS *fragP) static void xg_assemble_vliw_tokens (vliw_insn *vinsn) { - bfd_boolean finish_frag = FALSE; + bfd_boolean finish_frag; bfd_boolean is_jump = FALSE; bfd_boolean is_branch = FALSE; xtensa_isa isa = xtensa_default_isa; @@ -6771,9 +6632,10 @@ xg_assemble_vliw_tokens (vliw_insn *vinsn) int extra_space; char *f = NULL; int slot; - struct dwarf2_line_info best_loc; + unsigned current_line, best_linenum; + char *current_file; - best_loc.line = INT_MAX; + best_linenum = UINT_MAX; if (generating_literals) { @@ -6791,6 +6653,8 @@ xg_assemble_vliw_tokens (vliw_insn *vinsn) && (! frag_now->tc_frag_data.is_insn || (vinsn_has_specific_opcodes (vinsn) && use_transform ()) || !use_transform () != frag_now->tc_frag_data.is_no_transform + || (directive_state[directive_longcalls] + != frag_now->tc_frag_data.use_longcalls) || (directive_state[directive_absolute_literals] != frag_now->tc_frag_data.use_absolute_literals))) { @@ -6831,21 +6695,21 @@ xg_assemble_vliw_tokens (vliw_insn *vinsn) /* See if the instruction implies an aligned section. */ if (xtensa_opcode_is_loop (isa, vinsn->slots[i].opcode) == 1) record_alignment (now_seg, 2); - + /* Also determine the best line number for debug info. */ - best_loc = vinsn->slots[i].loc.line < best_loc.line - ? vinsn->slots[i].loc : best_loc; + best_linenum = vinsn->slots[i].linenum < best_linenum + ? vinsn->slots[i].linenum : best_linenum; } /* Special cases for instructions that force an alignment... */ /* None of these opcodes are bundle-able. */ if (xtensa_opcode_is_loop (isa, vinsn->slots[0].opcode) == 1) { - size_t max_fill; - + int max_fill; + xtensa_set_frag_assembly_state (frag_now); frag_now->tc_frag_data.is_insn = TRUE; - + max_fill = get_text_align_max_fill_size (get_text_align_power (xtensa_fetch_width), TRUE, frag_now->tc_frag_data.is_no_density); @@ -6857,10 +6721,10 @@ xg_assemble_vliw_tokens (vliw_insn *vinsn) frag_now->fr_offset, NULL); else - frag_var (rs_machine_dependent, 0, 0, + frag_var (rs_machine_dependent, 0, 0, RELAX_CHECK_ALIGN_NEXT_OPCODE, 0, 0, NULL); xtensa_set_frag_assembly_state (frag_now); - + xtensa_move_labels (frag_now, 0, FALSE); } @@ -6886,31 +6750,35 @@ xg_assemble_vliw_tokens (vliw_insn *vinsn) insn_size = xtensa_format_length (isa, vinsn->format); - extra_space = relaxation_requirements (vinsn); + extra_space = relaxation_requirements (vinsn, &finish_frag); /* vinsn_to_insnbuf will produce the error. */ if (vinsn->format != XTENSA_UNDEFINED) { - f = (char *) frag_more (insn_size + extra_space); + f = frag_more (insn_size + extra_space); xtensa_set_frag_assembly_state (frag_now); frag_now->tc_frag_data.is_insn = TRUE; } - vinsn_to_insnbuf (vinsn, f, frag_now, TRUE); + vinsn_to_insnbuf (vinsn, f, frag_now, FALSE); if (vinsn->format == XTENSA_UNDEFINED) return; - xtensa_insnbuf_to_chars (isa, vinsn->insnbuf, f, 0); - - xtensa_dwarf2_emit_insn (insn_size - extra_space, &best_loc); + xtensa_insnbuf_to_chars (isa, vinsn->insnbuf, (unsigned char *) f, 0); + + /* Temporarily set the logical line number to the one we want to appear + in the debug information. */ + as_where (¤t_file, ¤t_line); + new_logical_line (current_file, best_linenum); + dwarf2_emit_insn (insn_size + extra_space); + new_logical_line (current_file, current_line); for (slot = 0; slot < vinsn->num_slots; slot++) { TInsn *tinsn = &vinsn->slots[slot]; frag_now->tc_frag_data.slot_subtypes[slot] = tinsn->subtype; - frag_now->tc_frag_data.slot_symbols[slot] = tinsn->symbol; - frag_now->tc_frag_data.slot_sub_symbols[slot] = tinsn->sub_symbol; - frag_now->tc_frag_data.slot_offsets[slot] = tinsn->offset; + frag_now->tc_frag_data.slot_symbols[slot] = tinsn->symbol; + frag_now->tc_frag_data.slot_offsets[slot] = tinsn->offset; frag_now->tc_frag_data.literal_frags[slot] = tinsn->literal_frag; if (tinsn->literal_space != 0) xg_assemble_literal_space (tinsn->literal_space, slot); @@ -6922,8 +6790,8 @@ xg_assemble_vliw_tokens (vliw_insn *vinsn) if (xtensa_opcode_is_branch (isa, tinsn->opcode) == 1) is_branch = TRUE; - if (tinsn->subtype || tinsn->symbol || tinsn->record_fix - || tinsn->offset || tinsn->literal_frag || is_jump || is_branch) + if (tinsn->subtype || tinsn->symbol || tinsn->offset + || tinsn->literal_frag || is_jump || is_branch) finish_frag = TRUE; } @@ -6983,7 +6851,7 @@ xg_assemble_vliw_tokens (vliw_insn *vinsn) frag_now->fr_symbol, frag_now->fr_offset, NULL); xtensa_set_frag_assembly_state (frag_now); } - else if (is_branch && align_targets) + else if (is_branch && do_align_targets ()) { assert (finish_frag); frag_var (rs_machine_dependent, @@ -7099,7 +6967,7 @@ xtensa_cleanup_align_frags (void) && fragP->fr_subtype == RELAX_SLOTS && fragP->tc_frag_data.slot_subtypes[0] == RELAX_NARROW) frag_wane (fragP); - if (fragP->fr_type == rs_machine_dependent + if (fragP->fr_type == rs_machine_dependent && fragP->fr_subtype == RELAX_UNREACHABLE) fragP->tc_frag_data.is_unreachable = TRUE; } @@ -7110,11 +6978,7 @@ xtensa_cleanup_align_frags (void) /* Re-process all of the fragments looking to convert all of the RELAX_DESIRE_ALIGN_IF_TARGET fragments. If there is a branch target in the next fragment, convert this to RELAX_DESIRE_ALIGN. - If the next fragment starts with a loop target, AND the previous - fragment can be expanded to negate the branch, convert this to a - RELAX_LOOP_END. Otherwise, convert to a .fill 0. */ - -static bfd_boolean frag_can_negate_branch (fragS *); + Otherwise, convert to a .fill 0. */ static void xtensa_fix_target_frags (void) @@ -7125,7 +6989,6 @@ xtensa_fix_target_frags (void) so we walk over subsections instead of sections. */ for (frchP = frchain_root; frchP; frchP = frchP->frch_next) { - bfd_boolean prev_frag_can_negate_branch = FALSE; fragS *fragP; /* Walk over all of the fragments in a subsection. */ @@ -7134,61 +6997,16 @@ xtensa_fix_target_frags (void) if (fragP->fr_type == rs_machine_dependent && fragP->fr_subtype == RELAX_DESIRE_ALIGN_IF_TARGET) { - if (next_frag_is_loop_target (fragP)) - { - if (prev_frag_can_negate_branch) - { - fragP->fr_subtype = RELAX_LOOP_END; - /* See the comment near the frag_var with a - RELAX_DESIRE_ALIGN to see why we do this. */ - fragP->fr_var = RELAX_LOOP_END_BYTES; - } - else - { - if (next_frag_is_branch_target (fragP)) - fragP->fr_subtype = RELAX_DESIRE_ALIGN; - else - frag_wane (fragP); - } - } - else if (next_frag_is_branch_target (fragP)) + if (next_frag_is_branch_target (fragP)) fragP->fr_subtype = RELAX_DESIRE_ALIGN; else frag_wane (fragP); } - if (fragP->fr_fix != 0) - prev_frag_can_negate_branch = FALSE; - if (frag_can_negate_branch (fragP)) - prev_frag_can_negate_branch = TRUE; } } } -static bfd_boolean -frag_can_negate_branch (fragS *fragP) -{ - xtensa_isa isa = xtensa_default_isa; - vliw_insn vinsn; - int slot; - - if (fragP->fr_type != rs_machine_dependent - || fragP->fr_subtype != RELAX_SLOTS) - return FALSE; - - vinsn_from_chars (&vinsn, fragP->fr_opcode); - - for (slot = 0; slot < xtensa_format_num_slots (isa, vinsn.format); slot++) - { - if ((fragP->tc_frag_data.slot_subtypes[slot] == RELAX_IMMED) - && xtensa_opcode_is_branch (isa, vinsn.slots[slot].opcode) == 1) - return TRUE; - } - - return FALSE; -} - - static bfd_boolean is_narrow_branch_guaranteed_in_range (fragS *, TInsn *); static void @@ -7207,15 +7025,10 @@ xtensa_mark_narrow_branches (void) && fragP->tc_frag_data.slot_subtypes[0] == RELAX_IMMED) { vliw_insn vinsn; - const expressionS *expr; - symbolS *symbolP; vinsn_from_chars (&vinsn, fragP->fr_opcode); tinsn_immed_from_frag (&vinsn.slots[0], fragP, 0); - expr = &vinsn.slots[0].tok[1]; - symbolP = expr->X_add_symbol; - if (vinsn.num_slots == 1 && xtensa_opcode_is_branch (xtensa_default_isa, vinsn.slots[0].opcode) @@ -7225,6 +7038,7 @@ xtensa_mark_narrow_branches (void) { fragP->fr_subtype = RELAX_SLOTS; fragP->tc_frag_data.slot_subtypes[0] = RELAX_NARROW; + fragP->tc_frag_data.is_aligning_branch = 1; } } } @@ -7242,18 +7056,27 @@ xtensa_mark_narrow_branches (void) use for alignment narrow branches that definitely will not expand to a jump and a branch. These functions find and mark these cases. */ -/* the range in bytes of a bnez.n and beqz.n */ -#define MAX_IMMED6 68 +/* The range in bytes of BNEZ.N and BEQZ.N. The target operand is encoded + as PC + 4 + imm6, where imm6 is a 6-bit immediate ranging from 0 to 63. + We start counting beginning with the frag after the 2-byte branch, so the + maximum offset is (4 - 2) + 63 = 65. */ +#define MAX_IMMED6 65 -static size_t unrelaxed_frag_max_size (fragS *); +static offsetT unrelaxed_frag_max_size (fragS *); static bfd_boolean is_narrow_branch_guaranteed_in_range (fragS *fragP, TInsn *tinsn) { const expressionS *expr = &tinsn->tok[1]; symbolS *symbolP = expr->X_add_symbol; - fragS *target_frag = symbol_get_frag (symbolP); - size_t max_distance = expr->X_add_number; + offsetT max_distance = expr->X_add_number; + fragS *target_frag; + + if (expr->X_op != O_symbol) + return FALSE; + + target_frag = symbol_get_frag (symbolP); + max_distance += (S_GET_VALUE (symbolP) - target_frag->fr_address); if (is_branch_jmp_to_next (tinsn, fragP)) return FALSE; @@ -7294,12 +7117,10 @@ xtensa_mark_zcl_first_insns (void) /* Of course, sometimes (mostly for toy test cases) a zero-cost loop instruction is the last in a section. */ - if (targ_frag) - { - targ_frag->tc_frag_data.is_first_loop_insn = TRUE; - if (fragP->fr_subtype == RELAX_CHECK_ALIGN_NEXT_OPCODE) - frag_wane (fragP); - } + if (targ_frag) + targ_frag->tc_frag_data.is_first_loop_insn = TRUE; + if (fragP->fr_subtype == RELAX_CHECK_ALIGN_NEXT_OPCODE) + frag_wane (fragP); } } } @@ -7367,7 +7188,8 @@ next_instrs_are_b_retw (fragS *fragP) return FALSE; /* Check for the conditional branch. */ - xtensa_insnbuf_from_chars (isa, insnbuf, &next_fragP->fr_literal[offset], 0); + xtensa_insnbuf_from_chars + (isa, insnbuf, (unsigned char *) &next_fragP->fr_literal[offset], 0); fmt = xtensa_format_decode (isa, insnbuf); if (fmt == XTENSA_UNDEFINED) return FALSE; @@ -7395,7 +7217,8 @@ next_instrs_are_b_retw (fragS *fragP) return FALSE; /* Check for the retw/retw.n. */ - xtensa_insnbuf_from_chars (isa, insnbuf, &next_fragP->fr_literal[offset], 0); + xtensa_insnbuf_from_chars + (isa, insnbuf, (unsigned char *) &next_fragP->fr_literal[offset], 0); fmt = xtensa_format_decode (isa, insnbuf); /* Because RETW[.N] is not bundleable, a VLIW bundle here means that we @@ -7482,7 +7305,8 @@ next_instr_is_loop_end (fragS *fragP) make it at least 12 bytes away. In any case close it off with a .fill 0. */ -static size_t min_bytes_to_other_loop_end (fragS *, fragS *, offsetT, size_t); +static offsetT min_bytes_to_other_loop_end + (fragS *, fragS *, offsetT, offsetT); static void xtensa_fix_close_loop_end_frags (void) @@ -7527,8 +7351,8 @@ xtensa_fix_close_loop_end_frags (void) && fragP->fr_type == rs_machine_dependent && fragP->fr_subtype == RELAX_ADD_NOP_IF_CLOSE_LOOP_END) { - size_t min_bytes; - size_t bytes_added = 0; + offsetT min_bytes; + int bytes_added = 0; #define REQUIRED_LOOP_DIVIDING_BYTES 12 /* Max out at 12. */ @@ -7546,10 +7370,10 @@ xtensa_fix_close_loop_end_frags (void) < REQUIRED_LOOP_DIVIDING_BYTES) { int length = 3; - + if (fragP->fr_var < length) as_fatal (_("fr_var %lu < length %d"), - fragP->fr_var, length); + (long) fragP->fr_var, length); else { assemble_nop (length, @@ -7570,15 +7394,15 @@ xtensa_fix_close_loop_end_frags (void) } -static size_t unrelaxed_frag_min_size (fragS *); +static offsetT unrelaxed_frag_min_size (fragS *); -static size_t +static offsetT min_bytes_to_other_loop_end (fragS *fragP, fragS *current_target, offsetT current_offset, - size_t max_size) + offsetT max_size) { - size_t offset = 0; + offsetT offset = 0; fragS *current_fragP; for (current_fragP = fragP; @@ -7598,12 +7422,12 @@ min_bytes_to_other_loop_end (fragS *fragP, } -static size_t +static offsetT unrelaxed_frag_min_size (fragS *fragP) { - size_t size = fragP->fr_fix; + offsetT size = fragP->fr_fix; - /* add fill size */ + /* Add fill size. */ if (fragP->fr_type == rs_fill) size += fragP->fr_offset; @@ -7611,14 +7435,14 @@ unrelaxed_frag_min_size (fragS *fragP) } -static size_t +static offsetT unrelaxed_frag_max_size (fragS *fragP) { - size_t size = fragP->fr_fix; + offsetT size = fragP->fr_fix; switch (fragP->fr_type) { case 0: - /* Empty frags created by the obstack allocation scheme + /* Empty frags created by the obstack allocation scheme end up with type 0. */ break; case rs_fill: @@ -7664,7 +7488,7 @@ unrelaxed_frag_max_size (fragS *fragP) then convert this frag (and maybe the next one) to generate a NOP. In any case close it off with a .fill 0. */ -static size_t count_insns_to_loop_end (fragS *, bfd_boolean, size_t); +static int count_insns_to_loop_end (fragS *, bfd_boolean, int); static bfd_boolean branch_before_loop_end (fragS *); static void @@ -7712,9 +7536,7 @@ xtensa_fix_short_loop_frags (void) if (fragP->fr_type == rs_machine_dependent && fragP->fr_subtype == RELAX_ADD_NOP_IF_SHORT_LOOP) { - size_t insn_count = - count_insns_to_loop_end (fragP->fr_next, TRUE, 3); - if (insn_count < 3 + if (count_insns_to_loop_end (fragP->fr_next, TRUE, 3) < 3 && (branch_before_loop_end (fragP->fr_next) || (workaround_all_short_loops && current_opcode != XTENSA_UNDEFINED @@ -7732,15 +7554,15 @@ xtensa_fix_short_loop_frags (void) } -static size_t unrelaxed_frag_min_insn_count (fragS *); +static int unrelaxed_frag_min_insn_count (fragS *); -static size_t +static int count_insns_to_loop_end (fragS *base_fragP, bfd_boolean count_relax_add, - size_t max_count) + int max_count) { fragS *fragP = NULL; - size_t insn_count = 0; + int insn_count = 0; fragP = base_fragP; @@ -7768,12 +7590,12 @@ count_insns_to_loop_end (fragS *base_fragP, } -static size_t +static int unrelaxed_frag_min_insn_count (fragS *fragP) { xtensa_isa isa = xtensa_default_isa; static xtensa_insnbuf insnbuf = NULL; - size_t insn_count = 0; + int insn_count = 0; int offset = 0; if (!fragP->tc_frag_data.is_insn) @@ -7787,7 +7609,8 @@ unrelaxed_frag_min_insn_count (fragS *fragP) { xtensa_format fmt; - xtensa_insnbuf_from_chars (isa, insnbuf, fragP->fr_literal + offset, 0); + xtensa_insnbuf_from_chars + (isa, insnbuf, (unsigned char *) fragP->fr_literal + offset, 0); fmt = xtensa_format_decode (isa, insnbuf); if (fmt == XTENSA_UNDEFINED) @@ -7840,7 +7663,8 @@ unrelaxed_frag_has_b_j (fragS *fragP) xtensa_format fmt; int slot; - xtensa_insnbuf_from_chars (isa, insnbuf, fragP->fr_literal + offset, 0); + xtensa_insnbuf_from_chars + (isa, insnbuf, (unsigned char *) fragP->fr_literal + offset, 0); fmt = xtensa_format_decode (isa, insnbuf); if (fmt == XTENSA_UNDEFINED) return FALSE; @@ -7868,7 +7692,7 @@ static void xtensa_sanity_check (void) { char *file_name; - int line; + unsigned line; frchainS *frchP; @@ -8013,21 +7837,23 @@ is_local_forward_loop (const TInsn *insn, fragS *fragP) /* Alignment Functions. */ -static size_t -get_text_align_power (int target_size) +static int +get_text_align_power (unsigned target_size) { - size_t i = 0; - for (i = 0; i < sizeof (size_t); i++) + int i = 0; + unsigned power = 1; + + assert (target_size <= INT_MAX); + while (target_size > power) { - if (target_size <= (1 << i)) - return i; + power <<= 1; + i += 1; } - assert (0); - return 0; + return i; } -static addressT +static int get_text_align_max_fill_size (int align_pow, bfd_boolean use_nops, bfd_boolean use_no_density) @@ -8041,118 +7867,86 @@ get_text_align_max_fill_size (int align_pow, } -/* get_text_align_fill_size () - - Desired alignments: - give the address - target_size = size of next instruction - align_pow = get_text_align_power (target_size). - use_nops = 0 - use_no_density = 0; - Loop alignments: - address = current address + loop instruction size; - target_size = 3 (for 2 or 3 byte target) - = 4 (for 4 byte target) - = 8 (for 8 byte target) - align_pow = get_text_align_power (target_size); - use_nops = 1 - use_no_density = set appropriately - Text alignments: - address = current address + loop instruction size; - target_size = 0 - align_pow = get_text_align_power (target_size); - use_nops = 0 - use_no_density = 0. */ +/* Calculate the minimum bytes of fill needed at "address" to align a + target instruction of size "target_size" so that it does not cross a + power-of-two boundary specified by "align_pow". If "use_nops" is FALSE, + the fill can be an arbitrary number of bytes. Otherwise, the space must + be filled by NOP instructions. */ -static addressT +static int get_text_align_fill_size (addressT address, int align_pow, int target_size, bfd_boolean use_nops, bfd_boolean use_no_density) { - /* Input arguments: - - align_pow: log2 (required alignment). + addressT alignment, fill, fill_limit, fill_step; + bfd_boolean skip_one = FALSE; - target_size: alignment must allow the new_address and - new_address+target_size-1. + alignment = (1 << align_pow); + assert (target_size > 0 && alignment >= (addressT) target_size); - use_nops: if TRUE, then we can only use 2- or 3-byte nops. - - use_no_density: if use_nops and use_no_density, we can only use - 3-byte nops. - - Usually the align_pow is the power of 2 that is greater than - or equal to the target_size. This handles the 2-byte, 3-byte - and 8-byte instructions. - - Two cases: - - (1) aligning an instruction properly, but without using NOPs. - E.G.: a 3-byte instruction can go on any address where address mod 4 - is zero or one. The aligner uses this case to find the optimal - number of fill bytes for relax_frag_for_align. - - (2) aligning an instruction properly, but where we might need to use - extra NOPs. E.G.: when the aligner couldn't find enough widenings - or similar to get the optimal location. */ - - size_t alignment = (1 << align_pow); - - assert (target_size != 0); - if (!use_nops) { - unsigned fill_bytes; - for (fill_bytes = 0; fill_bytes < alignment; fill_bytes++) - { - addressT end_address = address + target_size - 1 + fill_bytes; - addressT start_address = address + fill_bytes; - if ((end_address >> align_pow) == (start_address >> align_pow)) - return fill_bytes; - } - assert (0); + fill_limit = alignment; + fill_step = 1; } - - /* This is the slightly harder case. */ - assert ((int) alignment >= target_size); - assert (target_size > 0); - if (!use_no_density) + else if (!use_no_density) { - size_t i; - for (i = 0; i < alignment * 2; i++) - { - if (i == 1) - continue; - if ((address + i) >> align_pow - == (address + i + target_size - 1) >> align_pow) - return i; - } + /* Combine 2- and 3-byte NOPs to fill anything larger than one. */ + fill_limit = alignment * 2; + fill_step = 1; + skip_one = TRUE; } else { - size_t i; + /* Fill with 3-byte NOPs -- can only fill multiples of 3. */ + fill_limit = alignment * 3; + fill_step = 3; + } - /* Can only fill multiples of 3. */ - for (i = 0; i <= alignment * 3; i += 3) - { - if ((address + i) >> align_pow - == (address + i + target_size - 1) >> align_pow) - return i; - } + /* Try all fill sizes until finding one that works. */ + for (fill = 0; fill < fill_limit; fill += fill_step) + { + if (skip_one && fill == 1) + continue; + if ((address + fill) >> align_pow + == (address + fill + target_size - 1) >> align_pow) + return fill; } assert (0); return 0; } +static int +branch_align_power (segT sec) +{ + /* If the Xtensa processor has a fetch width of 8 bytes, and the section + is aligned to at least an 8-byte boundary, then a branch target need + only fit within an 8-byte aligned block of memory to avoid a stall. + Otherwise, try to fit branch targets within 4-byte aligned blocks + (which may be insufficient, e.g., if the section has no alignment, but + it's good enough). */ + if (xtensa_fetch_width == 8) + { + if (get_recorded_alignment (sec) >= 3) + return 3; + } + else + assert (xtensa_fetch_width == 4); + + return 2; +} + + /* This will assert if it is not possible. */ -static size_t -get_text_align_nop_count (size_t fill_size, bfd_boolean use_no_density) +static int +get_text_align_nop_count (offsetT fill_size, bfd_boolean use_no_density) { - size_t count = 0; + int count = 0; + if (use_no_density) { assert (fill_size % 3 == 0); @@ -8163,7 +7957,7 @@ get_text_align_nop_count (size_t fill_size, bfd_boolean use_no_density) while (fill_size > 1) { - size_t insn_size = 3; + int insn_size = 3; if (fill_size == 2 || fill_size == 4) insn_size = 2; fill_size -= insn_size; @@ -8174,21 +7968,21 @@ get_text_align_nop_count (size_t fill_size, bfd_boolean use_no_density) } -static size_t -get_text_align_nth_nop_size (size_t fill_size, - size_t n, +static int +get_text_align_nth_nop_size (offsetT fill_size, + int n, bfd_boolean use_no_density) { - size_t count = 0; - - assert (get_text_align_nop_count (fill_size, use_no_density) > n); + int count = 0; if (use_no_density) return 3; + assert (fill_size != 1); /* Bad argument. */ + while (fill_size > 1) { - size_t insn_size = 3; + int insn_size = 3; if (fill_size == 2 || fill_size == 4) insn_size = 2; fill_size -= insn_size; @@ -8211,21 +8005,21 @@ get_noop_aligned_address (fragS *fragP, addressT address) the smallest number of bytes that need to be added to ensure that the next fragment's FIRST instruction will fit in a single word. - + E.G., 2 bytes : 0, 1, 2 mod 4 3 bytes: 0, 1 mod 4 - + If the FIRST instruction MIGHT be relaxed, assume that it will become a 3-byte instruction. - + Note again here that LOOP instructions are not bundleable, and this relaxation only applies to LOOP opcodes. */ - - size_t fill_size = 0; + + int fill_size = 0; int first_insn_size; int loop_insn_size; addressT pre_opcode_bytes; - size_t alignment; + int align_power; fragS *first_insn; xtensa_opcode opcode; bfd_boolean is_loop; @@ -8259,15 +8053,12 @@ get_noop_aligned_address (fragS *fragP, addressT address) first_insn_size = 3; /* ISA specifies this */ /* If it was 8, then we'll need a larger alignment for the section. */ - alignment = get_text_align_power (first_insn_size); + align_power = get_text_align_power (first_insn_size); + record_alignment (now_seg, align_power); - /* Is now_seg valid? */ - record_alignment (now_seg, alignment); - fill_size = get_text_align_fill_size - (address + pre_opcode_bytes, - get_text_align_power (first_insn_size), - first_insn_size, TRUE, fragP->tc_frag_data.is_no_density); + (address + pre_opcode_bytes, align_power, first_insn_size, TRUE, + fragP->tc_frag_data.is_no_density); return address + fill_size; } @@ -8290,15 +8081,16 @@ get_noop_aligned_address (fragS *fragP, addressT address) >=5 : 3-byte instruction + fn (n-3) widening - widen previous instructions. */ -static addressT -get_aligned_diff (fragS *fragP, addressT address, addressT *max_diff) +static offsetT +get_aligned_diff (fragS *fragP, addressT address, offsetT *max_diff) { addressT target_address, loop_insn_offset; int target_size; xtensa_opcode loop_opcode; bfd_boolean is_loop; - int text_align_power; - addressT opt_diff; + int align_power; + offsetT opt_diff; + offsetT branch_align; assert (fragP->fr_type == rs_machine_dependent); switch (fragP->fr_subtype) @@ -8307,12 +8099,16 @@ get_aligned_diff (fragS *fragP, addressT address, addressT *max_diff) target_size = next_frag_format_size (fragP); if (target_size == XTENSA_UNDEFINED) target_size = 3; - text_align_power = get_text_align_power (xtensa_fetch_width); - opt_diff = get_text_align_fill_size (address, text_align_power, + align_power = branch_align_power (now_seg); + branch_align = 1 << align_power; + /* Don't count on the section alignment being as large as the target. */ + if (target_size > branch_align) + target_size = branch_align; + opt_diff = get_text_align_fill_size (address, align_power, target_size, FALSE, FALSE); - *max_diff = opt_diff + xtensa_fetch_width - - (target_size + ((address + opt_diff) % xtensa_fetch_width)); + *max_diff = (opt_diff + branch_align + - (target_size + ((address + opt_diff) % branch_align))); assert (*max_diff >= opt_diff); return opt_diff; @@ -8337,8 +8133,8 @@ get_aligned_diff (fragS *fragP, addressT address, addressT *max_diff) will call get_noop_aligned_address. */ target_address = address + loop_insn_offset + xg_get_single_size (loop_opcode); - text_align_power = get_text_align_power (target_size), - opt_diff = get_text_align_fill_size (target_address, text_align_power, + align_power = get_text_align_power (target_size), + opt_diff = get_text_align_fill_size (target_address, align_power, target_size, FALSE, FALSE); *max_diff = xtensa_fetch_width @@ -8373,7 +8169,8 @@ xtensa_relax_frag (fragS *fragP, long stretch, int *stretched_p) int unreported = fragP->tc_frag_data.unreported_expansion; long new_stretch = 0; char *file_name; - int line, lit_size; + unsigned line; + int lit_size; static xtensa_insnbuf vbuf = NULL; int slot, num_slots; xtensa_format fmt; @@ -8424,7 +8221,8 @@ xtensa_relax_frag (fragS *fragP, long stretch, int *stretched_p) if (vbuf == NULL) vbuf = xtensa_insnbuf_alloc (isa); - xtensa_insnbuf_from_chars (isa, vbuf, fragP->fr_opcode, 0); + xtensa_insnbuf_from_chars + (isa, vbuf, (unsigned char *) fragP->fr_opcode, 0); fmt = xtensa_format_decode (isa, vbuf); num_slots = xtensa_format_num_slots (isa, fmt); @@ -8472,7 +8270,7 @@ xtensa_relax_frag (fragS *fragP, long stretch, int *stretched_p) } /* Tell gas we need another relaxation pass. */ - if (! fragP->tc_frag_data.relax_seen) + if (! fragP->tc_frag_data.relax_seen) { fragP->tc_frag_data.relax_seen = TRUE; *stretched_p = 1; @@ -8526,7 +8324,7 @@ relax_frag_add_nop (fragS *fragP) if (fragP->fr_var < length) { - as_fatal (_("fr_var (%ld) < length (%d)"), fragP->fr_var, length); + as_fatal (_("fr_var (%ld) < length (%d)"), (long) fragP->fr_var, length); return 0; } @@ -8607,7 +8405,7 @@ find_address_of_next_align_frag (fragS **fragPP, while (fragP) { /* Limit this to a small search. */ - if (*widens > 8) + if (*widens >= (int) xtensa_fetch_width) { *fragPP = fragP; return 0; @@ -8659,7 +8457,7 @@ find_address_of_next_align_frag (fragS **fragPP, return 0; } } - else + else { /* Just punt if we don't know the type. */ *fragPP = fragP; @@ -8675,11 +8473,6 @@ find_address_of_next_align_frag (fragS **fragPP, static long bytes_to_stretch (fragS *, int, int, int, int); -/* Undefine LOOKAHEAD_ALIGNER to get the older behavior. - I'll leave this in until I am more confident this works. */ - -#define LOOKAHEAD_ALIGNER 1 - static long future_alignment_required (fragS *fragP, long stretch ATTRIBUTE_UNUSED) { @@ -8699,34 +8492,41 @@ future_alignment_required (fragS *fragP, long stretch ATTRIBUTE_UNUSED) address = find_address_of_next_align_frag (&fragP, &wide_nops, &narrow_nops, &num_widens, &paddable); - if (address) + if (!address) + { + if (this_frag->tc_frag_data.is_aligning_branch) + this_frag->tc_frag_data.slot_subtypes[0] = RELAX_IMMED; + else + frag_wane (this_frag); + } + else { local_opt_diff = get_aligned_diff (fragP, address, &max_diff); opt_diff = local_opt_diff; assert (opt_diff >= 0); assert (max_diff >= opt_diff); - if (max_diff == 0) + if (max_diff == 0) return 0; -#ifdef LOOKAHEAD_ALIGNER + if (fragP) fragP = fragP->fr_next; while (fragP && opt_diff < max_diff && address) { /* We only use these to determine if we can exit early - because there will be plenty of ways to align future + because there will be plenty of ways to align future align frags. */ - unsigned int glob_widens = 0; + int glob_widens = 0; int dnn = 0; int dw = 0; bfd_boolean glob_pad = 0; address = find_address_of_next_align_frag (&fragP, &glob_widens, &dnn, &dw, &glob_pad); /* If there is a padable portion, then skip. */ - if (glob_pad || (glob_widens >= xtensa_fetch_width)) - break; + if (glob_pad || glob_widens >= (1 << branch_align_power (now_seg))) + address = 0; - if (address) + if (address) { offsetT next_m_diff; offsetT next_o_diff; @@ -8756,7 +8556,7 @@ future_alignment_required (fragS *fragP, long stretch ATTRIBUTE_UNUSED) fragP = fragP->fr_next; } } -#endif /* LOOKAHEAD_ALIGNER */ + /* If there are enough wideners in between, do it. */ if (paddable) { @@ -8767,24 +8567,21 @@ future_alignment_required (fragS *fragP, long stretch ATTRIBUTE_UNUSED) } return 0; } - local_stretch_amount + local_stretch_amount = bytes_to_stretch (this_frag, wide_nops, narrow_nops, num_widens, local_opt_diff); -#ifdef LOOKAHEAD_ALIGNER - global_stretch_amount - = bytes_to_stretch (this_frag, wide_nops, narrow_nops, + global_stretch_amount + = bytes_to_stretch (this_frag, wide_nops, narrow_nops, num_widens, opt_diff); - /* If the condition below is true, then the frag couldn't - stretch the correct amount for the global case, so we just - optimize locally. We'll rely on the subsequent frags to get + /* If the condition below is true, then the frag couldn't + stretch the correct amount for the global case, so we just + optimize locally. We'll rely on the subsequent frags to get the correct alignment in the global case. */ if (global_stretch_amount < local_stretch_amount) stretch_amount = local_stretch_amount; else stretch_amount = global_stretch_amount; -#else /* ! LOOKAHEAD_ALIGNER */ - stretch_amount = local_stretch_amount; -#endif /* ! LOOKAHEAD_ALIGNER */ + if (this_frag->fr_subtype == RELAX_SLOTS && this_frag->tc_frag_data.slot_subtypes[0] == RELAX_NARROW) assert (stretch_amount <= 1); @@ -8850,7 +8647,7 @@ bytes_to_stretch (fragS *this_frag, assert (desired_diff >= 0 && desired_diff < 8); if (desired_diff == 0) return 0; - + assert (wide_nops > 0 || num_widens > 0); /* Always prefer widening to NOP-filling. */ @@ -8860,7 +8657,7 @@ bytes_to_stretch (fragS *this_frag, to align the target without widening this frag in any way. */ return 0; } - + if (bytes_short == 0) { /* Widen every narrow between here and the align target @@ -8870,7 +8667,7 @@ bytes_to_stretch (fragS *this_frag, else return 1; } - + /* From here we will need at least one NOP to get an alignment. However, we may not be able to align at all, in which case, don't widen. */ @@ -8884,7 +8681,7 @@ bytes_to_stretch (fragS *this_frag, if (!this_frag->tc_frag_data.is_no_density && narrow_nops == 1) return 2; /* case 2 */ return 0; - case 3: + case 3: if (wide_nops > 1) return 0; else @@ -8898,7 +8695,7 @@ bytes_to_stretch (fragS *this_frag, case 5: if (num_widens >= 2 && wide_nops == 1) return 3; /* case 5a */ - /* We will need two nops. Are there enough nops + /* We will need two nops. Are there enough nops between here and the align target? */ if (wide_nops < 2 || narrow_nops == 0) return 0; @@ -8930,7 +8727,7 @@ bytes_to_stretch (fragS *this_frag, } else { - /* We will need a NOP no matter what, but should we widen + /* We will need a NOP no matter what, but should we widen this instruction to help? This is a RELAX_FRAG_NARROW frag. */ @@ -8983,7 +8780,6 @@ relax_frag_immed (segT segP, bfd_boolean estimate_only) { TInsn tinsn; - vliw_insn orig_vinsn; int old_size; bfd_boolean negatable_branch = FALSE; bfd_boolean branch_jmp_to_next = FALSE; @@ -8998,12 +8794,12 @@ relax_frag_immed (segT segP, assert (fragP->fr_opcode != NULL); - xg_init_vinsn (&orig_vinsn); - vinsn_from_chars (&orig_vinsn, fragP->fr_opcode); - if (xtensa_format_num_slots (isa, fmt) > 1) + xg_clear_vinsn (&cur_vinsn); + vinsn_from_chars (&cur_vinsn, fragP->fr_opcode); + if (cur_vinsn.num_slots > 1) wide_insn = TRUE; - tinsn = orig_vinsn.slots[slot]; + tinsn = cur_vinsn.slots[slot]; tinsn_immed_from_frag (&tinsn, fragP, slot); if (estimate_only && xtensa_opcode_is_loop (isa, tinsn.opcode)) @@ -9119,7 +8915,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT sec, fragS *fragp) int num_slots; xtensa_format fmt; char *file_name; - int line; + unsigned line; as_where (&file_name, &line); new_logical_line (fragp->fr_file, fragp->fr_line); @@ -9143,7 +8939,8 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT sec, fragS *fragp) if (vbuf == NULL) vbuf = xtensa_insnbuf_alloc (isa); - xtensa_insnbuf_from_chars (isa, vbuf, fragp->fr_opcode, 0); + xtensa_insnbuf_from_chars + (isa, vbuf, (unsigned char *) fragp->fr_opcode, 0); fmt = xtensa_format_decode (isa, vbuf); num_slots = xtensa_format_num_slots (isa, fmt); @@ -9228,11 +9025,10 @@ static void convert_frag_align_next_opcode (fragS *fragp) { char *nop_buf; /* Location for Writing. */ - size_t i; - bfd_boolean use_no_density = fragp->tc_frag_data.is_no_density; addressT aligned_address; - size_t fill_size, nop_count; + offsetT fill_size; + int nop, nop_count; aligned_address = get_noop_aligned_address (fragp, fragp->fr_address + fragp->fr_fix); @@ -9240,10 +9036,10 @@ convert_frag_align_next_opcode (fragS *fragp) nop_count = get_text_align_nop_count (fill_size, use_no_density); nop_buf = fragp->fr_literal + fragp->fr_fix; - for (i = 0; i < nop_count; i++) + for (nop = 0; nop < nop_count; nop++) { - size_t nop_size; - nop_size = get_text_align_nth_nop_size (fill_size, i, use_no_density); + int nop_size; + nop_size = get_text_align_nth_nop_size (fill_size, nop, use_no_density); assemble_nop (nop_size, nop_buf); nop_buf += nop_size; @@ -9258,14 +9054,13 @@ static void convert_frag_narrow (segT segP, fragS *fragP, xtensa_format fmt, int slot) { TInsn tinsn, single_target; - xtensa_format single_fmt; - int size, old_size, diff, error_val; + int size, old_size, diff; offsetT frag_offset; assert (slot == 0); tinsn_from_chars (&tinsn, fragP->fr_opcode, 0); - if (xtensa_opcode_is_branch (xtensa_default_isa, tinsn.opcode) == 1) + if (fragP->tc_frag_data.is_aligning_branch == 1) { assert (fragP->tc_frag_data.text_expansion[0] == 1 || fragP->tc_frag_data.text_expansion[0] == 0); @@ -9294,18 +9089,15 @@ convert_frag_narrow (segT segP, fragS *fragP, xtensa_format fmt, int slot) tinsn_init (&single_target); frag_offset = fragP->fr_opcode - fragP->fr_literal; - error_val = xg_expand_narrow (&single_target, &tinsn); - if (error_val) + if (! xg_is_single_relaxable_insn (&tinsn, &single_target, FALSE)) { as_bad (_("unable to widen instruction")); return; } size = xg_get_single_size (single_target.opcode); - single_fmt = xg_get_single_format (single_target.opcode); - - xg_emit_insn_to_buf (&single_target, single_fmt, fragP->fr_opcode, - fragP, frag_offset, TRUE); + xg_emit_insn_to_buf (&single_target, fragP->fr_opcode, fragP, + frag_offset, TRUE); diff = size - old_size; assert (diff >= 0); @@ -9356,7 +9148,6 @@ convert_frag_immed (segT segP, bfd_boolean expanded = FALSE; bfd_boolean branch_jmp_to_next = FALSE; char *fr_opcode = fragP->fr_opcode; - vliw_insn orig_vinsn; xtensa_isa isa = xtensa_default_isa; bfd_boolean wide_insn = FALSE; int bytes; @@ -9364,13 +9155,13 @@ convert_frag_immed (segT segP, assert (fr_opcode != NULL); - xg_init_vinsn (&orig_vinsn); + xg_clear_vinsn (&cur_vinsn); - vinsn_from_chars (&orig_vinsn, fr_opcode); - if (xtensa_format_num_slots (isa, fmt) > 1) + vinsn_from_chars (&cur_vinsn, fr_opcode); + if (cur_vinsn.num_slots > 1) wide_insn = TRUE; - orig_tinsn = orig_vinsn.slots[slot]; + orig_tinsn = cur_vinsn.slots[slot]; tinsn_immed_from_frag (&orig_tinsn, fragP, slot); is_loop = xtensa_opcode_is_loop (xtensa_default_isa, orig_tinsn.opcode) == 1; @@ -9384,22 +9175,23 @@ convert_frag_immed (segT segP, bytes = xtensa_format_length (isa, fmt); if (bytes >= 4) { - orig_vinsn.slots[slot].opcode = - xtensa_format_slot_nop_opcode (isa, orig_vinsn.format, slot); - orig_vinsn.slots[slot].ntok = 0; + cur_vinsn.slots[slot].opcode = + xtensa_format_slot_nop_opcode (isa, cur_vinsn.format, slot); + cur_vinsn.slots[slot].ntok = 0; } else { bytes += fragP->tc_frag_data.text_expansion[0]; assert (bytes == 2 || bytes == 3); - build_nop (&orig_vinsn.slots[0], bytes); + build_nop (&cur_vinsn.slots[0], bytes); fragP->fr_fix += fragP->tc_frag_data.text_expansion[0]; } - vinsn_to_insnbuf (&orig_vinsn, fr_opcode, frag_now, FALSE); - xtensa_insnbuf_to_chars (isa, orig_vinsn.insnbuf, fr_opcode, 0); + vinsn_to_insnbuf (&cur_vinsn, fr_opcode, frag_now, TRUE); + xtensa_insnbuf_to_chars + (isa, cur_vinsn.insnbuf, (unsigned char *) fr_opcode, 0); fragP->fr_var = 0; } - else if (!orig_tinsn.is_specific_opcode) + else { /* Here is the fun stuff: Get the immediate field from this instruction. If it fits, we're done. If not, find the next @@ -9529,68 +9321,32 @@ convert_frag_immed (segT segP, first = FALSE; if (opcode_fits_format_slot (tinsn->opcode, fmt, slot)) { - tinsn->record_fix = TRUE; - orig_vinsn.slots[slot] = *tinsn; + cur_vinsn.slots[slot] = *tinsn; } else { - orig_vinsn.slots[slot].opcode = + cur_vinsn.slots[slot].opcode = xtensa_format_slot_nop_opcode (isa, fmt, slot); - orig_vinsn.slots[slot].ntok = 0; - orig_vinsn.slots[slot].record_fix = FALSE; + cur_vinsn.slots[slot].ntok = 0; } - vinsn_to_insnbuf (&orig_vinsn, immed_instr, fragP, TRUE); - xtensa_insnbuf_to_chars (isa, orig_vinsn.insnbuf, - immed_instr, 0); + vinsn_to_insnbuf (&cur_vinsn, immed_instr, fragP, TRUE); + xtensa_insnbuf_to_chars (isa, cur_vinsn.insnbuf, + (unsigned char *) immed_instr, 0); fragP->tc_frag_data.is_insn = TRUE; size = xtensa_format_length (isa, fmt); if (!opcode_fits_format_slot (tinsn->opcode, fmt, slot)) { - xtensa_format single_fmt = - xg_get_single_format (tinsn->opcode); - xg_emit_insn_to_buf - (tinsn, single_fmt, immed_instr + size, fragP, + (tinsn, immed_instr + size, fragP, immed_instr - fragP->fr_literal + size, TRUE); size += xg_get_single_size (tinsn->opcode); } } else { - xtensa_format single_format; size = xg_get_single_size (tinsn->opcode); - single_format = xg_get_single_format (tinsn->opcode); - xg_emit_insn_to_buf (tinsn, single_format, immed_instr, - fragP, + xg_emit_insn_to_buf (tinsn, immed_instr, fragP, immed_instr - fragP->fr_literal, TRUE); -#if 0 - /* Code to recognize branch-around expansion - so the fragment is properly marked as ending in a - jump. */ - if ((((i == istack.ninsn - 2) - && (istack.insn[istack.ninsn-1].insn_type - == ITYPE_LABEL)) - || i == istack.ninsn -1) - && xtensa_opcode_is_jump (xtensa_default_isa, - tinsn->opcode) == 1 - && fragP->fr_next != NULL - && ! fragP->fr_next->tc_frag_data.is_unreachable) - { - /* Create a new unreachable frag of zero size. */ - size_t frag_size = sizeof (fragS); - fragS *new_fragP = (fragS *) xmalloc (frag_size); - memset (new_fragP, 0, frag_size); - new_fragP->fr_address = fragP->fr_next->fr_address; - new_fragP->fr_next = fragP->fr_next; - new_fragP->fr_fix = 0; - new_fragP->fr_var = 0; - new_fragP->fr_type = rs_fill; - new_fragP->tc_frag_data.is_unreachable = TRUE; - /* The rest are zeros.... */ - /* Link it in to the chain. */ - fragP->fr_next = new_fragP; - } -#endif } immed_instr += size; total_size += size; @@ -9607,9 +9363,6 @@ convert_frag_immed (segT segP, fragP->fr_fix += diff; } - /* Clean it up. */ - xg_free_vinsn (&orig_vinsn); - /* Check for undefined immediates in LOOP instructions. */ if (is_loop) { @@ -9698,7 +9451,7 @@ convert_frag_immed_finish_loop (segT segP, fragS *fragP, TInsn *tinsn) addressT addi_offset = 9; addressT addmi_offset = 12; fragS *next_fragP; - size_t target_count; + int target_count; if (!insnbuf) insnbuf = xtensa_insnbuf_alloc (isa); @@ -9763,11 +9516,13 @@ convert_frag_immed_finish_loop (segT segP, fragS *fragP, TInsn *tinsn) tinsn_to_insnbuf (&addi_insn, insnbuf); fragP->tc_frag_data.is_insn = TRUE; - xtensa_insnbuf_to_chars (isa, insnbuf, fragP->fr_opcode + addi_offset, 0); + xtensa_insnbuf_to_chars + (isa, insnbuf, (unsigned char *) fragP->fr_opcode + addi_offset, 0); set_expr_const (&addmi_insn.tok[2], loop_length_hi); tinsn_to_insnbuf (&addmi_insn, insnbuf); - xtensa_insnbuf_to_chars (isa, insnbuf, fragP->fr_opcode + addmi_offset, 0); + xtensa_insnbuf_to_chars + (isa, insnbuf, (unsigned char *) fragP->fr_opcode + addmi_offset, 0); /* Walk through all of the frags from here to the loop end and mark them as no_transform to keep them from being modified @@ -9899,38 +9654,6 @@ set_subseg_freq (segT seg, subsegT subseg, float total_f, float target_f) /* Segment Lists and emit_state Stuff. */ -/* Remove the segment from the global sections list. */ - -static void -xtensa_remove_section (segT sec) -{ - /* Handle brain-dead bfd_section_list_remove macro, which - expect the address of the prior section's "next" field, not - just the address of the section to remove. */ - - segT *ps_next_ptr = &stdoutput->sections; - while (*ps_next_ptr != sec && *ps_next_ptr != NULL) - ps_next_ptr = &(*ps_next_ptr)->next; - - assert (*ps_next_ptr != NULL); - - bfd_section_list_remove (stdoutput, ps_next_ptr); -} - - -static void -xtensa_insert_section (segT after_sec, segT sec) -{ - segT *after_sec_next; - if (after_sec == NULL) - after_sec_next = &stdoutput->sections; - else - after_sec_next = &after_sec->next; - - bfd_section_list_insert (stdoutput, after_sec_next, sec); -} - - static void xtensa_move_seg_list_to_beginning (seg_list *head) { @@ -9941,9 +9664,11 @@ xtensa_move_seg_list_to_beginning (seg_list *head) /* Move the literal section to the front of the section list. */ assert (literal_section); - xtensa_remove_section (literal_section); - xtensa_insert_section (NULL, literal_section); - + if (literal_section != stdoutput->sections) + { + bfd_section_list_remove (stdoutput, literal_section); + bfd_section_list_prepend (stdoutput, literal_section); + } head = head->next; } } @@ -10010,17 +9735,15 @@ xtensa_move_literals (void) { literal_pool = search_frag->tc_frag_data.literal_frag; assert (literal_pool->fr_subtype == RELAX_LITERAL_POOL_BEGIN); - /* Note that we set this fr_var to be a fix - chain when we created the literal pool location - as RELAX_LITERAL_POOL_BEGIN. */ - frchain_to = (frchainS *) literal_pool->fr_var; + frchain_to = literal_pool->tc_frag_data.lit_frchain; + assert (frchain_to); } insert_after = literal_pool; while (insert_after->fr_next->fr_subtype != RELAX_LITERAL_POOL_END) insert_after = insert_after->fr_next; - dest_seg = (segT) insert_after->fr_next->fr_var; + dest_seg = insert_after->fr_next->tc_frag_data.lit_seg; *frag_splice = next_frag; search_frag->fr_next = insert_after->fr_next; @@ -10086,7 +9809,7 @@ mark_literal_frags (seg_list *segment) { frchain_from = seg_info (segment->seg)->frchainP; search_frag = frchain_from->frch_root; - while (search_frag) + while (search_frag) { search_frag->tc_frag_data.is_literal = TRUE; search_frag = search_frag->fr_next; @@ -10111,8 +9834,8 @@ xtensa_reorder_seg_list (seg_list *head, segT after) assert (literal_section); if (literal_section != after) { - xtensa_remove_section (literal_section); - xtensa_insert_section (after, literal_section); + bfd_section_list_remove (stdoutput, literal_section); + bfd_section_list_insert_after (stdoutput, after, literal_section); } head = head->next; @@ -10183,10 +9906,10 @@ xtensa_switch_to_non_abs_literal_fragment (emit_state *result) static bfd_boolean recursive = FALSE; fragS *pool_location = get_literal_pool_location (now_seg); - bfd_boolean is_init = + bfd_boolean is_init = (now_seg && !strcmp (segment_name (now_seg), INIT_SECTION_NAME)); - bfd_boolean is_fini = + bfd_boolean is_fini = (now_seg && !strcmp (segment_name (now_seg), FINI_SECTION_NAME)); if (pool_location == NULL @@ -10257,7 +9980,7 @@ xtensa_switch_section_emit_state (emit_state *state, state->now_subseg = now_subseg; state->generating_literals = generating_literals; generating_literals++; - subseg_new (segment_name (new_now_seg), new_now_subseg); + subseg_set (new_now_seg, new_now_subseg); } @@ -10267,7 +9990,7 @@ static void xtensa_restore_emit_state (emit_state *state) { generating_literals = state->generating_literals; - subseg_new (state->name, state->now_subseg); + subseg_set (state->now_seg, state->now_subseg); } @@ -10438,7 +10161,7 @@ xtensa_create_property_segments (frag_predicate property_function, xtensa_block_info *cur_block; /* This is a section with some data. */ int num_recs = 0; - size_t rec_size; + bfd_size_type rec_size; for (cur_block = block; cur_block; cur_block = cur_block->next) num_recs++; @@ -10455,7 +10178,7 @@ xtensa_create_property_segments (frag_predicate property_function, { /* Allocate a fragment and leak it. */ fragS *fragP; - size_t frag_size; + bfd_size_type frag_size; fixS *fixes; frchainS *frchainP; int i; @@ -10534,9 +10257,9 @@ xtensa_create_xproperty_segments (frag_flags_fn flag_fn, flagword flags; flags = bfd_get_section_flags (stdoutput, sec); - if (flags & SEC_DEBUGGING) - continue; - if (!(flags & SEC_ALLOC)) + if ((flags & SEC_DEBUGGING) + || !(flags & SEC_ALLOC) + || (flags & SEC_MERGE)) continue; if (section_has_xproperty (sec, flag_fn)) @@ -10570,7 +10293,7 @@ xtensa_create_xproperty_segments (frag_flags_fn flag_fn, xtensa_block_info *cur_block; /* This is a section with some data. */ int num_recs = 0; - size_t rec_size; + bfd_size_type rec_size; for (cur_block = block; cur_block; cur_block = cur_block->next) num_recs++; @@ -10588,7 +10311,7 @@ xtensa_create_xproperty_segments (frag_flags_fn flag_fn, { /* Allocate a fragment and (unfortunately) leak it. */ fragS *fragP; - size_t frag_size; + bfd_size_type frag_size; fixS *fixes; frchainS *frchainP; int i; @@ -10666,18 +10389,7 @@ retrieve_segment_info (segT seg) seginfo->bfd_section = seg; seginfo->sym = 0; /* We will not be dealing with these, only our special ones. */ -#if 0 - if (seg == bfd_abs_section_ptr) - abs_seg_info = seginfo; - else if (seg == bfd_und_section_ptr) - und_seg_info = seginfo; - else -#endif - bfd_set_section_userdata (stdoutput, seg, (void *) seginfo); -#if 0 - seg_fix_rootP = &segment_info[seg].fix_root; - seg_fix_tailP = &segment_info[seg].fix_tail; -#endif + bfd_set_section_userdata (stdoutput, seg, (void *) seginfo); frchainP = (frchainS *) xmalloc (sizeof (frchainS)); frchainP->frch_root = NULL; @@ -10963,7 +10675,7 @@ static bfd_vma xt_block_aligned_size (const xtensa_block_info *xt_block) { bfd_vma end_addr; - size_t align_bits; + unsigned align_bits; if (!xt_block->flags.is_align) return xt_block->size; @@ -11103,12 +10815,9 @@ init_op_placement_info_table (void) /* FIXME: Make tinsn allocation dynamic. */ if (xtensa_opcode_num_operands (isa, opcode) >= MAX_INSN_ARGS) as_fatal (_("too many operands in instruction")); - opi->single = XTENSA_UNDEFINED; - opi->single_size = 0; - opi->widest = XTENSA_UNDEFINED; - opi->widest_size = 0; opi->narrowest = XTENSA_UNDEFINED; opi->narrowest_size = 0x7F; + opi->narrowest_slot = 0; opi->formats = 0; opi->num_formats = 0; opi->issuef = 0; @@ -11128,20 +10837,7 @@ init_op_placement_info_table (void) { opi->narrowest = fmt; opi->narrowest_size = fmt_length; - } - if (fmt_length > opi->widest_size) - { - opi->widest = fmt; - opi->widest_size = fmt_length; - } - if (xtensa_format_num_slots (isa, fmt) == 1) - { - if (opi->single_size == 0 - || fmt_length < opi->single_size) - { - opi->single = fmt; - opi->single_size = fmt_length; - } + opi->narrowest_slot = slot; } } } @@ -11165,15 +10861,21 @@ opcode_fits_format_slot (xtensa_opcode opcode, xtensa_format fmt, int slot) static int xg_get_single_size (xtensa_opcode opcode) { - assert (op_placement_table[opcode].single != XTENSA_UNDEFINED); - return op_placement_table[opcode].single_size; + return op_placement_table[opcode].narrowest_size; } static xtensa_format xg_get_single_format (xtensa_opcode opcode) { - return op_placement_table[opcode].single; + return op_placement_table[opcode].narrowest; +} + + +static int +xg_get_single_slot (xtensa_opcode opcode) +{ + return op_placement_table[opcode].narrowest_slot; } @@ -11326,18 +11028,12 @@ tinsn_has_invalid_symbolic_operands (const TInsn *insn) default: /* Symbolic immediates are only allowed on the last immediate operand. At this time, CONST16 is the only opcode where we - support non-PC-relative relocations. (It isn't necessary - to complain about non-PC-relative relocations here, but - otherwise, no error is reported until the relocations are - generated, and the assembler won't get that far if there - are any other errors. It's nice to see all the problems - at once.) */ + support non-PC-relative relocations. */ if (i != get_relaxable_immed (insn->opcode) || (xtensa_operand_is_PCrelative (isa, insn->opcode, i) != 1 && insn->opcode != xtensa_const16_opcode)) { - as_bad (_("invalid symbolic operand %d on '%s'"), - i, xtensa_opcode_name (isa, insn->opcode)); + as_bad (_("invalid symbolic operand")); return TRUE; } } @@ -11376,92 +11072,13 @@ tinsn_has_complex_operands (const TInsn *insn) } -/* Convert the constant operands in the tinsn to insnbuf. - Return TRUE if there is a symbol in the immediate field. - - Before this is called, - 1) the number of operands are correct - 2) the tinsn is a ITYPE_INSN - 3) ONLY the relaxable_ is built - 4) All operands are O_constant, O_symbol. All constants fit - The return value tells whether there are any remaining O_symbols. */ - -static bfd_boolean -tinsn_to_insnbuf (TInsn *tinsn, xtensa_insnbuf insnbuf) -{ - static xtensa_insnbuf slotbuf = 0; - xtensa_isa isa = xtensa_default_isa; - xtensa_opcode opcode = tinsn->opcode; - xtensa_format fmt = xg_get_single_format (opcode); - bfd_boolean has_fixup = FALSE; - int noperands = xtensa_opcode_num_operands (isa, opcode); - int i; - uint32 opnd_value; - char *file_name; - int line; - - if (!slotbuf) - slotbuf = xtensa_insnbuf_alloc (isa); - - assert (tinsn->insn_type == ITYPE_INSN); - if (noperands != tinsn->ntok) - as_fatal (_("operand number mismatch")); - - if (xtensa_opcode_encode (isa, fmt, 0, slotbuf, opcode)) - as_fatal (_("cannot encode opcode")); - - for (i = 0; i < noperands; ++i) - { - expressionS *expr = &tinsn->tok[i]; - switch (expr->X_op) - { - case O_register: - if (xtensa_operand_is_visible (isa, opcode, i) == 0) - break; - /* The register number has already been checked in - expression_maybe_register, so we don't need to check here. */ - opnd_value = expr->X_add_number; - (void) xtensa_operand_encode (isa, opcode, i, &opnd_value); - xtensa_operand_set_field (isa, opcode, i, fmt, 0, - slotbuf, opnd_value); - break; - - case O_constant: - if (xtensa_operand_is_visible (isa, opcode, i) == 0) - break; - as_where (&file_name, &line); - /* It is a constant and we called this function, - then we have to try to fit it. */ - xtensa_insnbuf_set_operand (slotbuf, fmt, 0, opcode, i, - expr->X_add_number, file_name, line); - break; - - default: - has_fixup = TRUE; - break; - } - } - - xtensa_format_encode (isa, fmt, insnbuf); - xtensa_format_set_slot (isa, fmt, 0, insnbuf, slotbuf); - - return has_fixup; -} - - -/* Convert the constant operands in the tinsn to slotbuf. - Return TRUE if there is a symbol in the immediate field. - (Eventually this should replace tinsn_to_insnbuf.) */ - -/* Before this is called, - 1) the number of operands are correct - 2) the tinsn is a ITYPE_INSN - 3) ONLY the relaxable_ is built - 4) All operands are - O_constant, O_symbol - All constants fit - - The return value tells whether there are any remaining O_symbols. */ +/* Encode a TInsn opcode and its constant operands into slotbuf. + Return TRUE if there is a symbol in the immediate field. This + function assumes that: + 1) The number of operands are correct. + 2) The insn_type is ITYPE_INSN. + 3) The opcode can be encoded in the specified format and slot. + 4) Operands are either O_constant or O_symbol, and all constants fit. */ static bfd_boolean tinsn_to_slotbuf (xtensa_format fmt, @@ -11475,8 +11092,6 @@ tinsn_to_slotbuf (xtensa_format fmt, int noperands = xtensa_opcode_num_operands (isa, opcode); int i; - *((int *) &slotbuf[0]) = 0; - *((int *) &slotbuf[1]) = 0; assert (tinsn->insn_type == ITYPE_INSN); if (noperands != tinsn->ntok) as_fatal (_("operand number mismatch")); @@ -11491,7 +11106,8 @@ tinsn_to_slotbuf (xtensa_format fmt, for (i = 0; i < noperands; i++) { expressionS *expr = &tinsn->tok[i]; - int rc, line; + int rc; + unsigned line; char *file_name; uint32 opnd_value; @@ -11530,6 +11146,44 @@ tinsn_to_slotbuf (xtensa_format fmt, } +/* Encode a single TInsn into an insnbuf. If the opcode can only be encoded + into a multi-slot instruction, fill the other slots with NOPs. + Return TRUE if there is a symbol in the immediate field. See also the + assumptions listed for tinsn_to_slotbuf. */ + +static bfd_boolean +tinsn_to_insnbuf (TInsn *tinsn, xtensa_insnbuf insnbuf) +{ + static xtensa_insnbuf slotbuf = 0; + static vliw_insn vinsn; + xtensa_isa isa = xtensa_default_isa; + bfd_boolean has_fixup = FALSE; + int i; + + if (!slotbuf) + { + slotbuf = xtensa_insnbuf_alloc (isa); + xg_init_vinsn (&vinsn); + } + + xg_clear_vinsn (&vinsn); + + bundle_tinsn (tinsn, &vinsn); + + xtensa_format_encode (isa, vinsn.format, insnbuf); + + for (i = 0; i < vinsn.num_slots; i++) + { + /* Only one slot may have a fix-up because the rest contains NOPs. */ + has_fixup |= + tinsn_to_slotbuf (vinsn.format, i, &vinsn.slots[i], vinsn.slotbuf[i]); + xtensa_format_set_slot (isa, vinsn.format, i, insnbuf, vinsn.slotbuf[i]); + } + + return has_fixup; +} + + /* Check the instruction arguments. Return TRUE on failure. */ static bfd_boolean @@ -11610,21 +11264,9 @@ tinsn_immed_from_frag (TInsn *tinsn, fragS *fragP, int slot) { opnum = get_relaxable_immed (opcode); assert (opnum >= 0); - if (fragP->tc_frag_data.slot_sub_symbols[slot]) - { - set_expr_symbol_offset_diff - (&tinsn->tok[opnum], - fragP->tc_frag_data.slot_symbols[slot], - fragP->tc_frag_data.slot_sub_symbols[slot], - fragP->tc_frag_data.slot_offsets[slot]); - } - else - { - set_expr_symbol_offset - (&tinsn->tok[opnum], - fragP->tc_frag_data.slot_symbols[slot], - fragP->tc_frag_data.slot_offsets[slot]); - } + set_expr_symbol_offset (&tinsn->tok[opnum], + fragP->tc_frag_data.slot_symbols[slot], + fragP->tc_frag_data.slot_offsets[slot]); } } @@ -11677,8 +11319,6 @@ xg_init_vinsn (vliw_insn *v) for (i = 0; i < MAX_SLOTS; i++) { - tinsn_init (&v->slots[i]); - v->slots[i].opcode = XTENSA_UNDEFINED; v->slotbuf[i] = xtensa_insnbuf_alloc (isa); if (v->slotbuf[i] == NULL) as_fatal (_("out of memory")); @@ -11690,6 +11330,9 @@ static void xg_clear_vinsn (vliw_insn *v) { int i; + + memset (v, 0, offsetof (vliw_insn, insnbuf)); + v->format = XTENSA_UNDEFINED; v->num_slots = 0; v->inside_bundle = FALSE; @@ -11698,10 +11341,7 @@ xg_clear_vinsn (vliw_insn *v) debug_type = xt_saved_debug_type; for (i = 0; i < MAX_SLOTS; i++) - { - memset (&v->slots[i], 0, sizeof (TInsn)); - v->slots[i].opcode = XTENSA_UNDEFINED; - } + v->slots[i].opcode = XTENSA_UNDEFINED; } @@ -11709,7 +11349,7 @@ static bfd_boolean vinsn_has_specific_opcodes (vliw_insn *v) { int i; - + for (i = 0; i < v->num_slots; i++) { if (v->slots[i].is_specific_opcode) @@ -11729,17 +11369,8 @@ xg_free_vinsn (vliw_insn *v) } -/* Before this is called, we should have - filled out the following fields: - - 1) the number of operands for each opcode are correct - 2) the tinsn in the slots are ITYPE_INSN - 3) ONLY the relaxable_ is built - 4) All operands are - O_constant, O_symbol - All constants fit - - The return value tells whether there are any remaining O_symbols. */ +/* Encode a vliw_insn into an insnbuf. Return TRUE if there are any symbolic + operands. See also the assumptions listed for tinsn_to_slotbuf. */ static bfd_boolean vinsn_to_insnbuf (vliw_insn *vinsn, @@ -11764,14 +11395,7 @@ vinsn_to_insnbuf (vliw_insn *vinsn, xtensa_format_set_slot (isa, fmt, slot, insnbuf, vinsn->slotbuf[slot]); - /* tinsn_has_fixup tracks if there is a fixup at all. - record_fixup controls globally. I.E., we use this - function from several places, some of which are after - fixups have already been recorded. Finally, - tinsn->record_fixup controls based on the individual ops, - which may or may not need it based on the relaxation - requirements. */ - if (tinsn_has_fixup && record_fixup) + if (tinsn_has_fixup) { int i; xtensa_opcode opcode = tinsn->opcode; @@ -11788,48 +11412,35 @@ vinsn_to_insnbuf (vliw_insn *vinsn, case O_hi16: if (get_relaxable_immed (opcode) == i) { - if (tinsn->record_fix || expr->X_op != O_symbol) + /* Add a fix record for the instruction, except if this + function is being called prior to relaxation, i.e., + if record_fixup is false, and the instruction might + be relaxed later. */ + if (record_fixup + || tinsn->is_specific_opcode + || !xg_is_relaxable_insn (tinsn, 0)) { - if (!xg_add_opcode_fix - (tinsn, i, fmt, slot, expr, fragP, - frag_offset - fragP->fr_literal)) - as_bad (_("instruction with constant operands does not fit")); + xg_add_opcode_fix (tinsn, i, fmt, slot, expr, fragP, + frag_offset - fragP->fr_literal); } else { + if (expr->X_op != O_symbol) + as_bad (_("invalid operand")); tinsn->symbol = expr->X_add_symbol; tinsn->offset = expr->X_add_number; } } else - as_bad (_("invalid operand %d on '%s'"), - i, xtensa_opcode_name (isa, opcode)); + as_bad (_("symbolic operand not allowed")); break; case O_constant: case O_register: break; - case O_subtract: - if (get_relaxable_immed (opcode) == i) - { - if (tinsn->record_fix) - as_bad (_("invalid subtract operand")); - else - { - tinsn->symbol = expr->X_add_symbol; - tinsn->sub_symbol = expr->X_op_symbol; - tinsn->offset = expr->X_add_number; - } - } - else - as_bad (_("invalid operand %d on '%s'"), - i, xtensa_opcode_name (isa, opcode)); - break; - default: - as_bad (_("invalid expression for operand %d on '%s'"), - i, xtensa_opcode_name (isa, opcode)); + as_bad (_("expression too complex")); break; } } @@ -11855,7 +11466,7 @@ vinsn_from_chars (vliw_insn *vinsn, char *f) slotbuf = xtensa_insnbuf_alloc (isa); } - xtensa_insnbuf_from_chars (isa, insnbuf, f, 0); + xtensa_insnbuf_from_chars (isa, insnbuf, (unsigned char *) f, 0); fmt = xtensa_format_decode (isa, insnbuf); if (fmt == XTENSA_UNDEFINED) as_fatal (_("cannot decode instruction format")); @@ -11935,21 +11546,6 @@ set_expr_symbol_offset (expressionS *s, symbolS *sym, offsetT offset) } -/* Set the expression to symbol - minus_sym + offset. */ - -static void -set_expr_symbol_offset_diff (expressionS *s, - symbolS *sym, - symbolS *minus_sym, - offsetT offset) -{ - s->X_op = O_subtract; - s->X_add_symbol = sym; - s->X_op_symbol = minus_sym; /* unused */ - s->X_add_number = offset; -} - - /* Return TRUE if the two expressions are equal. */ bfd_boolean