This is the mail archive of the binutils@sources.redhat.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

revise Xtensa longcall relaxtion in GAS


This patch makes some changes to the behavior of longcall expansions in the Xtensa port of GAS:

- Always relax calls to weak symbols even if longcalls are not enabled. This fixes GCC test g++.dg/warn/weak1.C.

- Relax a call out of range within a section even if longcalls are not enabled. This doesn't come up much but it seems like a good thing to handle.

I updated some comments and fixed a few minor formatting issues, too. Tested successfully with the GAS testsuite for an xtensa-elf target. Committed on the mainline and 2.16 branch.


2005-03-25 Bob Wilson <bob.wilson@acm.org>


	* config/tc-xtensa.c (use_longcalls): Delete.
	(xg_symbolic_immeds_fit): Check for direct calls and return TRUE if
	the use_longcalls flag is set.  Do this before checking the segment.
	(xg_expand_assembly_insn): Rearrange to use new do_expand flag.  Never
	expand direct calls at this point.
	(xtensa_set_frag_assembly_state): Set use_longcalls flag.
	(xtensa_find_unmarked_state_frags): Likewise.
	(md_assemble): Do not disable longcalls by setting is_specific_opcode.
	(xg_assemble_vliw_tokens): Switch frags when use_longcalls changes.
	(convert_frag_immed): Remove unnecessary check of is_specific_opcode.
	* config/tc-xtensa.h (xtensa_frag_type): Add use_longcalls flag.


Index: tc-xtensa.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-xtensa.c,v
retrieving revision 1.25
diff -u -p -r1.25 tc-xtensa.c
--- tc-xtensa.c	21 Mar 2005 19:46:01 -0000	1.25
+++ tc-xtensa.c	25 Mar 2005 23:59:27 -0000
@@ -1031,16 +1031,6 @@ 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
@@ -3312,22 +3302,28 @@ xg_symbolic_immeds_fit (const TInsn *ins
 	  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;
@@ -3645,7 +3641,7 @@ xg_assembly_relax (IStack *istack,
     }
   current_insn = *insn;
 
-  /* Walk through all of the single instruction expansions. */
+  /* Walk through all of the single instruction expansions.  */
   while (xg_is_single_relaxable_insn (&current_insn))
     {
       int error_val = xg_expand_narrow (&single_target, &current_insn);
@@ -3943,15 +3939,16 @@ xg_simplify_insn (TInsn *old_insn, TInsn
 
 /* 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 +3974,37 @@ xg_expand_assembly_insn (IStack *istack,
 
   /* 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;
 }
@@ -4789,6 +4773,8 @@ xtensa_set_frag_assembly_state (fragS *f
      "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;
@@ -4847,6 +4833,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;
 		    }
@@ -5300,11 +5288,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))
     {
@@ -6760,6 +6743,8 @@ xg_assemble_vliw_tokens (vliw_insn *vins
       && (! 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)))
     {
@@ -6877,9 +6862,9 @@ xg_assemble_vliw_tokens (vliw_insn *vins
     {
       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_sub_symbols[slot] = tinsn->sub_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);
@@ -9371,7 +9356,7 @@ convert_frag_immed (segT segP,
       xtensa_insnbuf_to_chars (isa, orig_vinsn.insnbuf, 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
Index: tc-xtensa.h
===================================================================
RCS file: /cvs/src/src/gas/config/tc-xtensa.h,v
retrieving revision 1.9
diff -u -p -r1.9 tc-xtensa.h
--- tc-xtensa.h	17 Mar 2005 21:49:47 -0000	1.9
+++ tc-xtensa.h	25 Mar 2005 23:59:27 -0000
@@ -195,6 +195,7 @@ struct xtensa_frag_type
   unsigned int is_assembly_state_set : 1;
   unsigned int is_no_density : 1;
   unsigned int is_no_transform : 1;
+  unsigned int use_longcalls : 1;
   unsigned int use_absolute_literals : 1;
 
   /* Inhibits relaxation of machine-dependent alignment frags the

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]