This is the mail archive of the binutils@sourceware.org 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]

[Xtensa] add J.L long jump pseudo-op


This patch adds a new pseudo-op for Xtensa. This addresses a longstanding issue of relaxing jumps when the target is beyond the range of a direct jump instruction. Relaxing to an indirect jump requires a temporary register, but Xtensa has no registers reserved for that kind of use. The J.L pseudo-op is a compromise solution: it is like a direct jump but it takes an extra argument to specify a register to be used if the jump needs to be relaxed. The idea is that the compiler (or assembly programmer) can use J.L when the jump range is big, but you won't actually pay for the indirect jump if a direct jump can be used. You do of course pay the opportunity cost of reserving the register.

Sterling Augustine wrote the code and I wrote the testcase. I've verified that the test passes, and we've also been using this feature internally for a while, so I think it's working properly. I've committed it on the trunk.

gas/ChangeLog:
2008-11-04  Sterling Augustine  <sterling@tensilica.com>
	
	* config/tc-xtensa.c (xtensa_j_opcode): New.
	(xg_instruction_matches_option_term): Handle "FREEREG" option.
	(xg_build_to_insn): Likewise.  Update renamed tls_reloc reference.
	(md_begin): Initialize xtensa_j_opcode.
	(md_assemble): Update renamed tls_reloc reference.  Handle "j.l".
	(xg_assemble_vliw_tokens): Save free_reg info in the frag.
	(tinsn_immed_from_frag): Get free_reg info back out of the frag.
	(vinsn_to_insnbuf): Update renamed tls_reloc references.
	Distinguish extra argument for "FREEREG" from extra TLS argument.
	* config/tc-xtensa.h (struct xtensa_frag_type): Add free_reg field.
	* config/xtensa-istack.h (struct tinsn_struct): Rename tls_reloc
	field to extra_arg.
	* config/xtensa-relax.c (widen_spec_list): Add rules to relax "j.l".
	(build_transition): Handle "FREEREG" operand.
	* config/xtensa-relax.h (enum op_type): Add OP_FREEREG.

gas/testsuite/ChangeLog:
2008-11-04  Bob Wilson  <bob.wilson@acm.org>

	* gas/xtensa/all.exp: Run jlong test.
	* gas/xtensa/jlong.d: New.
	* gas/xtensa/jlong.s: New.
Index: config/tc-xtensa.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-xtensa.c,v
retrieving revision 1.104
diff -u -p -r1.104 tc-xtensa.c
--- config/tc-xtensa.c	12 Sep 2008 18:53:55 -0000	1.104
+++ config/tc-xtensa.c	4 Nov 2008 23:03:04 -0000
@@ -571,6 +571,7 @@ static xtensa_opcode xtensa_extui_opcode
 static xtensa_opcode xtensa_movi_opcode;
 static xtensa_opcode xtensa_movi_n_opcode;
 static xtensa_opcode xtensa_isync_opcode;
+static xtensa_opcode xtensa_j_opcode;
 static xtensa_opcode xtensa_jx_opcode;
 static xtensa_opcode xtensa_l32r_opcode;
 static xtensa_opcode xtensa_loop_opcode;
@@ -2730,13 +2731,10 @@ xtensa_insnbuf_get_operand (xtensa_insnb
 
 /* The routine xg_instruction_matches_option_term must return TRUE
    when a given option term is true.  The meaning of all of the option
-   terms is given interpretation by this function.  This is needed when
-   an option depends on the state of a directive, but there are no such
-   options in use right now.  */
+   terms is given interpretation by this function.  */
 
 static bfd_boolean
-xg_instruction_matches_option_term (TInsn *insn ATTRIBUTE_UNUSED,
-				    const ReqOrOption *option)
+xg_instruction_matches_option_term (TInsn *insn, const ReqOrOption *option)
 {
   if (strcmp (option->option_name, "realnop") == 0
       || strncmp (option->option_name, "IsaUse", 6) == 0)
@@ -2745,6 +2743,8 @@ xg_instruction_matches_option_term (TIns
 	 relaxation table.  There's no need to reevaluate them now.  */
       return TRUE;
     }
+  else if (strcmp (option->option_name, "FREEREG") == 0)
+    return insn->extra_arg.X_op == O_register;
   else
     {
       as_fatal (_("internal error: unknown option name '%s'"),
@@ -3370,12 +3370,17 @@ xg_build_to_insn (TInsn *targ, TInsn *in
 	      assert (op_data < insn->ntok);
 	      copy_expr (&targ->tok[op_num], &insn->tok[op_data]);
 	      break;
+	    case OP_FREEREG:
+	      if (insn->extra_arg.X_op != O_register)
+		return FALSE;
+	      copy_expr (&targ->tok[op_num], &insn->extra_arg);
+	      break;
 	    case OP_LITERAL:
 	      sym = get_special_literal_symbol ();
 	      set_expr_symbol_offset (&targ->tok[op_num], sym, 0);
 	      if (insn->tok[op_data].X_op == O_tlsfunc
 		  || insn->tok[op_data].X_op == O_tlsarg)
-		copy_expr (&targ->tls_reloc, &insn->tok[op_data]);
+		copy_expr (&targ->extra_arg, &insn->tok[op_data]);
 	      break;
 	    case OP_LABEL:
 	      sym = get_special_label_symbol ();
@@ -5103,6 +5108,7 @@ md_begin (void)
   xtensa_movi_opcode = xtensa_opcode_lookup (isa, "movi");
   xtensa_movi_n_opcode = xtensa_opcode_lookup (isa, "movi.n");
   xtensa_isync_opcode = xtensa_opcode_lookup (isa, "isync");
+  xtensa_j_opcode = xtensa_opcode_lookup (isa, "j");
   xtensa_jx_opcode = xtensa_opcode_lookup (isa, "jx");
   xtensa_l32r_opcode = xtensa_opcode_lookup (isa, "l32r");
   xtensa_loop_opcode = xtensa_opcode_lookup (isa, "loop");
@@ -5375,7 +5381,7 @@ md_assemble (char *str)
 	    {
 	      bfd_reloc_code_real_type reloc;
 	      char *old_input_line_pointer;
-	      expressionS *tok = &orig_insn.tls_reloc;
+	      expressionS *tok = &orig_insn.extra_arg;
 	      segT t;
 
 	      old_input_line_pointer = input_line_pointer;
@@ -5395,6 +5401,28 @@ md_assemble (char *str)
 	}
     }
 
+  /* Special case: Check for "j.l" psuedo op.  */
+  if (orig_insn.opcode == XTENSA_UNDEFINED
+      && strncasecmp (opname, "j.l", 3) == 0)
+    {
+      if (num_args != 2)
+	as_bad (_("wrong number of operands for '%s'"), opname);
+      else
+	{
+	  char *old_input_line_pointer;
+	  expressionS *tok = &orig_insn.extra_arg;
+
+	  old_input_line_pointer = input_line_pointer;
+	  input_line_pointer = arg_strings[num_args - 1];
+
+	  expression_maybe_register (xtensa_jx_opcode, 0, tok);
+	  input_line_pointer = old_input_line_pointer;
+
+	  num_args -= 1;
+	  orig_insn.opcode = xtensa_j_opcode;
+	}
+    }
+
   if (orig_insn.opcode == XTENSA_UNDEFINED)
     {
       xtensa_format fmt = xtensa_format_lookup (isa, opname);
@@ -6996,6 +7024,7 @@ xg_assemble_vliw_tokens (vliw_insn *vins
       frag_now->tc_frag_data.literal_frags[slot] = tinsn->literal_frag;
       if (tinsn->literal_space != 0)
 	xg_assemble_literal_space (tinsn->literal_space, slot);
+      frag_now->tc_frag_data.free_reg[slot] = tinsn->extra_arg;
 
       if (tinsn->subtype == RELAX_NARROW)
 	assert (vinsn->num_slots == 1);
@@ -11505,6 +11534,7 @@ tinsn_immed_from_frag (TInsn *tinsn, fra
 			      fragP->tc_frag_data.slot_symbols[slot],
 			      fragP->tc_frag_data.slot_offsets[slot]);
     }
+  tinsn->extra_arg = fragP->tc_frag_data.free_reg[slot];
 }
 
 
@@ -11626,14 +11656,14 @@ vinsn_to_insnbuf (vliw_insn *vinsn,
   for (slot = 0; slot < vinsn->num_slots; slot++)
     {
       TInsn *tinsn = &vinsn->slots[slot];
-      expressionS *tls_reloc = &tinsn->tls_reloc;
+      expressionS *extra_arg = &tinsn->extra_arg;
       bfd_boolean tinsn_has_fixup =
 	tinsn_to_slotbuf (vinsn->format, slot, tinsn,
 			  vinsn->slotbuf[slot]);
 
       xtensa_format_set_slot (isa, fmt, slot,
 			      insnbuf, vinsn->slotbuf[slot]);
-      if (tls_reloc->X_op != O_illegal)
+      if (extra_arg->X_op != O_illegal && extra_arg->X_op != O_register)
 	{
 	  if (vinsn->num_slots != 1)
 	    as_bad (_("TLS relocation not allowed in FLIX bundle"));
@@ -11646,8 +11676,8 @@ vinsn_to_insnbuf (vliw_insn *vinsn,
 	  else
 	    fix_new (fragP, frag_offset - fragP->fr_literal,
 		     xtensa_format_length (isa, fmt),
-		     tls_reloc->X_add_symbol, tls_reloc->X_add_number,
-		     FALSE, map_operator_to_reloc (tls_reloc->X_op, FALSE));
+		     extra_arg->X_add_symbol, extra_arg->X_add_number,
+		     FALSE, map_operator_to_reloc (extra_arg->X_op, FALSE));
 	}
       if (tinsn_has_fixup)
 	{
Index: config/tc-xtensa.h
===================================================================
RCS file: /cvs/src/src/gas/config/tc-xtensa.h,v
retrieving revision 1.31
diff -u -p -r1.31 tc-xtensa.h
--- config/tc-xtensa.h	19 Sep 2008 10:00:40 -0000	1.31
+++ config/tc-xtensa.h	4 Nov 2008 23:03:04 -0000
@@ -253,6 +253,10 @@ struct xtensa_frag_type
   int literal_expansion[MAX_SLOTS];
   int unreported_expansion;
 
+  /* For slots that have a free register for relaxation, record that
+     register.  */
+  expressionS free_reg[MAX_SLOTS];
+
   /* For text fragments that can generate literals at relax time:  */
   fragS *literal_frags[MAX_SLOTS];
   enum xtensa_relax_statesE slot_subtypes[MAX_SLOTS];
Index: config/xtensa-istack.h
===================================================================
RCS file: /cvs/src/src/gas/config/xtensa-istack.h,v
retrieving revision 1.13
diff -u -p -r1.13 xtensa-istack.h
--- config/xtensa-istack.h	21 Aug 2008 17:10:24 -0000	1.13
+++ config/xtensa-istack.h	4 Nov 2008 23:03:04 -0000
@@ -49,11 +49,19 @@ typedef struct tinsn_struct
   bfd_boolean loc_directive_seen;
   struct dwarf2_line_info debug_line;
 
-  expressionS tls_reloc;
+  /* This field is used for two types of special pseudo ops:
+     1. TLS-related operations.  Eg:  callx8.tls
+     2. j.l  label, a2
+
+     For the tls-related operations, it will hold a tls-related opcode
+     and info to be used in a fixup.  For j.l it will hold a
+     register to be used during relaxation.  */
+  expressionS extra_arg;
 
   /* Filled out by relaxation_requirements:  */
   enum xtensa_relax_statesE subtype;
   int literal_space;
+
   /* Filled out by vinsn_to_insnbuf:  */
   symbolS *symbol;
   offsetT offset;
Index: config/xtensa-relax.c
===================================================================
RCS file: /cvs/src/src/gas/config/xtensa-relax.c,v
retrieving revision 1.17
diff -u -p -r1.17 xtensa-relax.c
--- config/xtensa-relax.c	20 Aug 2008 23:28:58 -0000	1.17
+++ config/xtensa-relax.c	4 Nov 2008 23:03:04 -0000
@@ -463,7 +463,14 @@ static string_pattern_pair widen_spec_li
   {"call8 %label,%ar8 ? IsaUseConst16",
    "const16 a8,HI16U(%label); const16 a8,LOW16U(%label); callx8 a8,%ar8"},
   {"call12 %label,%ar12 ? IsaUseConst16",
-   "const16 a12,HI16U(%label); const16 a12,LOW16U(%label); callx12 a12,%ar12"}
+   "const16 a12,HI16U(%label); const16 a12,LOW16U(%label); callx12 a12,%ar12"},
+
+  /* Expanding j.l with literals.  */
+  {"j %label ? FREEREG ? IsaUseL32R",
+   "LITERAL %label; l32r FREEREG,%LITERAL; jx FREEREG"},
+  /* Expanding j.l with const16.  */
+  {"j %label ? FREEREG ? IsaUseConst16",
+   "const16 FREEREG,HI16U(%label); const16 FREEREG,LOW16U(%label); jx FREEREG"},
 };
 
 #define WIDEN_COUNT (sizeof (widen_spec_list) / sizeof (string_pattern_pair))
@@ -1793,6 +1800,10 @@ build_transition (insn_pattern *initial_
 			  opcode_name, op->operand_name, to_string);
 	      append_field_op (bi, op->operand_num, orig_op->operand_num);
 	    }
+	  else if (strcmp (op->operand_name, "FREEREG") == 0)
+	    {
+	      append_user_fn_field_op (bi, op->operand_num, OP_FREEREG, 0);
+	    }
 	  else if (parse_special_fn (op->operand_name,
 				     &fn_name, &operand_arg_name))
 	    {
Index: config/xtensa-relax.h
===================================================================
RCS file: /cvs/src/src/gas/config/xtensa-relax.h,v
retrieving revision 1.8
diff -u -p -r1.8 xtensa-relax.h
--- config/xtensa-relax.h	20 Aug 2008 23:28:58 -0000	1.8
+++ config/xtensa-relax.h	4 Nov 2008 23:03:05 -0000
@@ -105,6 +105,7 @@ enum op_type
   OP_OPERAND_LOW16U,		/* Low 16 bits of immed.  */
   OP_OPERAND_HI16U,		/* High 16 bits of immed.  */
   OP_LITERAL,
+  OP_FREEREG,
   OP_LABEL
 };
 
Index: testsuite/gas/xtensa/all.exp
===================================================================
RCS file: /cvs/src/src/gas/testsuite/gas/xtensa/all.exp,v
retrieving revision 1.5
diff -u -p -r1.5 all.exp
--- testsuite/gas/xtensa/all.exp	13 Dec 2007 19:03:45 -0000	1.5
+++ testsuite/gas/xtensa/all.exp	4 Nov 2008 23:03:06 -0000
@@ -81,6 +81,7 @@ if [istarget xtensa*-*-*] then {
     run_dump_test "short_branch_offset"
     run_dump_test "pcrel"
     run_dump_test "weak-call"
+    run_dump_test "jlong"
 }
 
 if [info exists errorInfo] then {
--- /dev/null	2008-04-22 11:39:21.000000000 -0700
+++ gas/xtensa/jlong.d	2008-11-04 12:13:10.000000000 -0800
@@ -0,0 +1,18 @@
+#as: 
+#objdump: -d -j .text.1 -j .text.2
+#name: long jump relaxation
+
+.*: +file format .*xtensa.*
+
+Disassembly of section \.text\.1:
+
+00000000 <\.text\.1>:
+# Skip instructions to load a8 since they will vary depending on whether
+# the Xtensa configuration uses L32R or Const16.
+#...
+  .*:	.*	jx	a8
+Disassembly of section \.text\.2:
+
+00000000 <\.text\.2>:
+   0:	.*	j	.*
+#...
--- /dev/null	2008-04-22 11:39:21.000000000 -0700
+++ gas/xtensa/jlong.s	2008-11-04 12:13:10.000000000 -0800
@@ -0,0 +1,7 @@
+	.section .text.1
+	j.l	.Lfar, a8
+	.section .text.2
+.Lfar:
+	j.l	.Lnear, a9
+	.word	0
+.Lnear:

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