* config/tc-mips.c (mips_cpreturn_offset): New variable.
authorThiemo Seufer <ths@networkno.de>
Wed, 10 Oct 2001 01:08:35 +0000 (01:08 +0000)
committerThiemo Seufer <ths@networkno.de>
Wed, 10 Oct 2001 01:08:35 +0000 (01:08 +0000)
(mips_cpreturn_register): Likewise.
(mips_gp_register): Likewise.
(s_cpsetup): New function prototype.
(s_cplocal): Likewise.
(s_cpreturn): Likewise.
(s_gpvalue): Likewise.
(mips_pseudo_table): Add .cpsetup, .cplocal, .cpreturn, .gpvalue
pseudo-ops.
(macro): Don't warn about .cprestore for NewABI.
(md_pcrel_from): Code cleanup.
(mips_force_relocation): Force output of some NewABI relocations even
without a defined symbol.
(s_cpload): Ignore .cpload for NewABI.
(s_cpsetup): Handle .cpsetup.
(s_cplocal): Handle .cplocal.
(s_cprestore): Ignore .cprestore for NewABI.
(s_cpreturn): Handle .cpreturn.
(s_gpvalue): Handle .gpvalue.
(s_cpadd): Ignore .cpadd for NewABI.
(nopic_need_relax): Take g_switch_value into account as gp
optimization.
(tc_gen_reloc): Don't handle BFD_RELOC_MIPS_{CALL,GOT}* for NewABI.

gas/ChangeLog
gas/config/tc-mips.c

index f788b9a..edb6e8c 100644 (file)
@@ -1,5 +1,31 @@
 2001-10-10  Thiemo Seufer <seufer@csv.ica.uni-stuttgart.de>
 
+       * config/tc-mips.c (mips_cpreturn_offset): New variable.
+       (mips_cpreturn_register): Likewise.
+       (mips_gp_register): Likewise.
+       (s_cpsetup): New function prototype.
+       (s_cplocal): Likewise.
+       (s_cpreturn): Likewise.
+       (s_gpvalue): Likewise.
+       (mips_pseudo_table): Add .cpsetup, .cplocal, .cpreturn, .gpvalue
+       pseudo-ops.
+       (macro): Don't warn about .cprestore for NewABI.
+       (md_pcrel_from): Code cleanup.
+       (mips_force_relocation): Force output of some NewABI relocations even
+       without a defined symbol.
+       (s_cpload): Ignore .cpload for NewABI.
+       (s_cpsetup): Handle .cpsetup.
+       (s_cplocal): Handle .cplocal.
+       (s_cprestore): Ignore .cprestore for NewABI.
+       (s_cpreturn): Handle .cpreturn.
+       (s_gpvalue): Handle .gpvalue.
+       (s_cpadd): Ignore .cpadd for NewABI.
+       (nopic_need_relax): Take g_switch_value into account as gp
+       optimization.
+       (tc_gen_reloc): Don't handle BFD_RELOC_MIPS_{CALL,GOT}* for NewABI.
+
+2001-10-10  Thiemo Seufer <seufer@csv.ica.uni-stuttgart.de>
+
        * config/tc-mips.c (my_getSmallParser): New function prototype.
        (small_ex_type): Named this enum, more return values for
        my_getSmallExpression.
index df2e662..978a4de 100644 (file)
@@ -393,6 +393,13 @@ static int auto_align = 1;
    variable.  */
 static offsetT mips_cprestore_offset = -1;
 
+/* Similiar for NewABI PIC code, where $gp is callee-saved.  NewABI has some
+   more optimizations, it can use a register value instead of a memory-saved
+   offset and even an other than GP as global pointer.  */
+static offsetT mips_cpreturn_offset = -1;
+static int mips_cpreturn_register = -1;
+static int mips_gp_register = GP;
+
 /* This is the register which holds the stack frame, as set by the
    .frame pseudo-op.  This is needed to implement .cprestore.  */
 static int mips_frame_reg = SP;
@@ -690,7 +697,11 @@ static void s_option PARAMS ((int));
 static void s_mipsset PARAMS ((int));
 static void s_abicalls PARAMS ((int));
 static void s_cpload PARAMS ((int));
+static void s_cpsetup PARAMS ((int));
+static void s_cplocal PARAMS ((int));
 static void s_cprestore PARAMS ((int));
+static void s_cpreturn PARAMS ((int));
+static void s_gpvalue PARAMS ((int));
 static void s_gpword PARAMS ((int));
 static void s_cpadd PARAMS ((int));
 static void s_insn PARAMS ((int));
@@ -779,7 +790,11 @@ static const pseudo_typeS mips_pseudo_table[] =
   {"livereg", s_ignore, 0},
   {"abicalls", s_abicalls, 0},
   {"cpload", s_cpload, 0},
+  {"cpsetup", s_cpsetup, 0},
+  {"cplocal", s_cplocal, 0},
   {"cprestore", s_cprestore, 0},
+  {"cpreturn", s_cpreturn, 0},
+  {"gpvalue", s_gpvalue, 0},
   {"gpword", s_gpword, 0},
   {"cpadd", s_cpadd, 0},
   {"insn", s_insn, 0},
@@ -4967,14 +4982,17 @@ macro (ip)
 
          macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "jalr",
                       "d,s", dreg, sreg);
-         if (mips_cprestore_offset < 0)
-           as_warn (_("No .cprestore pseudo-op used in PIC code"));
-         else
+         if (! HAVE_NEWABI)
            {
-             expr1.X_add_number = mips_cprestore_offset;
-             macro_build ((char *) NULL, &icnt, &expr1,
-                          HAVE_32BIT_ADDRESSES ? "lw" : "ld",
-                          "t,o(b)", GP, (int) BFD_RELOC_LO16, mips_frame_reg);
+             if (mips_cprestore_offset < 0)
+               as_warn (_("No .cprestore pseudo-op used in PIC code"));
+             else
+               {
+                 expr1.X_add_number = mips_cprestore_offset;
+                 macro_build ((char *) NULL, &icnt, &expr1,
+                              HAVE_32BIT_ADDRESSES ? "lw" : "ld", "t,o(b)",
+                              GP, (int) BFD_RELOC_LO16, mips_frame_reg);
+               }
            }
        }
       else
@@ -5067,18 +5085,20 @@ macro (ip)
                       (int) BFD_RELOC_LO16);
          macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
                       "jalr", "s", PIC_CALL_REG);
-         if (mips_cprestore_offset < 0)
-           as_warn (_("No .cprestore pseudo-op used in PIC code"));
-         else
+         if (! HAVE_NEWABI)
            {
-             if (mips_opts.noreorder)
-               macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
+             if (mips_cprestore_offset < 0)
+               as_warn (_("No .cprestore pseudo-op used in PIC code"));
+             else
+               {
+                 if (mips_opts.noreorder)
+                   macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
                             "nop", "");
-             expr1.X_add_number = mips_cprestore_offset;
-             macro_build ((char *) NULL, &icnt, &expr1,
-                          HAVE_32BIT_ADDRESSES ? "lw" : "ld",
-                          "t,o(b)", GP, (int) BFD_RELOC_LO16,
-                          mips_frame_reg);
+                 expr1.X_add_number = mips_cprestore_offset;
+                 macro_build ((char *) NULL, &icnt, &expr1,
+                              HAVE_32BIT_ADDRESSES ? "lw" : "ld", "t,o(b)",
+                              GP, (int) BFD_RELOC_LO16, mips_frame_reg);
+               }
            }
        }
       else if (mips_pic == EMBEDDED_PIC)
@@ -9930,16 +9950,12 @@ md_pcrel_from (fixP)
       && fixP->fx_addsy != (symbolS *) NULL
       && ! S_IS_DEFINED (fixP->fx_addsy))
     {
+      /* This makes a branch to an undefined symbol be a branch to the
+        current location.  */
       if (mips_pic == EMBEDDED_PIC)
-       {
-         /* This makes a branch to an undefined symbol be a branch to the
-            current location.  */
-         return 4;
-       }
+       return 4;
       else
-       {
-         return 1;
-       }
+       return 1;
     }
 
   /* return the address of the delay slot */
@@ -10082,6 +10098,13 @@ mips_force_relocation (fixp)
          || fixp->fx_r_type == BFD_RELOC_LO16))
     return 1;
 
+  if (HAVE_NEWABI
+      && S_GET_SEGMENT (fixp->fx_addsy) == bfd_abs_section_ptr
+      && (fixp->fx_r_type == BFD_RELOC_MIPS_SUB
+         || fixp->fx_r_type == BFD_RELOC_HI16_S
+         || fixp->fx_r_type == BFD_RELOC_LO16))
+    return 1;
+
   return (mips_pic == EMBEDDED_PIC
          && (fixp->fx_pcrel
              || SWITCH_TABLE (fixp)
@@ -11069,8 +11092,9 @@ s_cpload (ignore)
   expressionS ex;
   int icnt = 0;
 
-  /* If we are not generating SVR4 PIC code, .cpload is ignored.  */
-  if (mips_pic != SVR4_PIC)
+  /* If we are not generating SVR4 PIC code, or if this is NewABI code,
+     .cpload is ignored.  */
+  if (mips_pic != SVR4_PIC || HAVE_NEWABI)
     {
       s_ignore (0);
       return;
@@ -11098,6 +11122,119 @@ s_cpload (ignore)
   demand_empty_rest_of_line ();
 }
 
+/* Handle the .cpsetup pseudo-op defined for NewABI PIC code.  The syntax is:
+     .cpsetup $reg1, offset|$reg2, label
+
+   If offset is given, this results in:
+     sd                $gp, offset($sp)
+     lui       $gp, %gp_rel(%neg(%hi(label)))
+     daddiu    $gp, $gp, %gp_rel(%neg(%lo(label)))
+     addu      $gp, $gp, $reg1
+
+   If $reg2 is given, this results in:
+     daddu     $reg2, $gp, $0
+     lui       $gp, %gp_rel(%neg(%hi(label)))
+     daddiu    $gp, $gp, %gp_rel(%neg(%lo(label)))
+     addu      $gp, $gp, $reg1
+ */
+static void
+s_cpsetup (ignore)
+     int ignore ATTRIBUTE_UNUSED;
+{
+  expressionS ex_off;
+  expressionS ex_sym;
+  int reg1;
+  int icnt = 0;
+  char *sym;
+
+  /* If we are not generating SVR4 PIC code, .cpload is ignored.
+     We also need NewABI support.  */
+  if (mips_pic != SVR4_PIC || ! HAVE_NEWABI)
+    {
+      s_ignore (0);
+      return;
+    }
+
+  reg1 = tc_get_register (0);
+  SKIP_WHITESPACE ();
+  if (*input_line_pointer != ',')
+    {
+      as_bad (_("missing argument separator ',' for .cpsetup"));
+      return;
+    }
+  else
+    input_line_pointer++;
+  SKIP_WHITESPACE ();
+  if (*input_line_pointer == '$')
+    mips_cpreturn_register = tc_get_register (0);
+  else
+    mips_cpreturn_offset = get_absolute_expression ();
+  SKIP_WHITESPACE ();
+  if (*input_line_pointer != ',')
+    {
+      as_bad (_("missing argument separator ',' for .cpsetup"));
+      return;
+    }
+  else
+    input_line_pointer++;
+  SKIP_WHITESPACE ();
+  sym = input_line_pointer;
+  while (ISALNUM (*input_line_pointer))
+    input_line_pointer++;
+  *input_line_pointer = 0;
+
+  ex_sym.X_op = O_symbol;
+  ex_sym.X_add_symbol = symbol_find_or_make (sym);
+  ex_sym.X_op_symbol = NULL;
+  ex_sym.X_add_number = 0;
+
+  if (mips_cpreturn_register == -1)
+    {
+      ex_off.X_op = O_constant;
+      ex_off.X_add_symbol = NULL;
+      ex_off.X_op_symbol = NULL;
+      ex_off.X_add_number = mips_cpreturn_offset;
+
+      macro_build ((char *) NULL, &icnt, &ex_off, "sd", "t,o(b)",
+                  mips_gp_register, (int) BFD_RELOC_LO16, SP);
+    }
+  else
+    macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "daddu",
+                "d,v,t", mips_cpreturn_register, mips_gp_register, 0);
+
+  macro_build ((char *) NULL, &icnt, &ex_sym, "lui", "t,u", mips_gp_register,
+              (int) BFD_RELOC_GPREL16);
+  fix_new (frag_now, (char *) prev_insn_fixp - 4 - frag_now->fr_literal, 0,
+          NULL, 0, 0, BFD_RELOC_MIPS_SUB);
+  fix_new (frag_now, (char *) prev_insn_fixp - 4 - frag_now->fr_literal, 0,
+          NULL, 0, 0, BFD_RELOC_HI16_S);
+  macro_build ((char *) NULL, &icnt, &ex_sym, "addiu", "t,r,j",
+              mips_gp_register, mips_gp_register, (int) BFD_RELOC_GPREL16);
+  fix_new (frag_now, (char *) prev_insn_fixp - 4 - frag_now->fr_literal, 0,
+          NULL, 0, 0, BFD_RELOC_MIPS_SUB);
+  fix_new (frag_now, (char *) prev_insn_fixp - 4 - frag_now->fr_literal, 0,
+          NULL, 0, 0, BFD_RELOC_LO16);
+  macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "daddu",
+              "d,v,t", mips_gp_register, mips_gp_register, reg1);
+
+  demand_empty_rest_of_line ();
+}
+
+static void
+s_cplocal (ignore)
+     int ignore ATTRIBUTE_UNUSED;
+{
+  /* If we are not generating SVR4 PIC code, or if this is not NewABI code,
+   .cplocal is ignored.  */
+  if (mips_pic != SVR4_PIC || ! HAVE_NEWABI)
+    {
+      s_ignore (0);
+      return;
+    }
+
+  mips_gp_register = tc_get_register (0);
+}
+
 /* Handle the .cprestore pseudo-op.  This stores $gp into a given
    offset from $sp.  The offset is remembered, and after making a PIC
    call $gp is restored from that location.  */
@@ -11109,8 +11246,9 @@ s_cprestore (ignore)
   expressionS ex;
   int icnt = 0;
 
-  /* If we are not generating SVR4 PIC code, .cprestore is ignored.  */
-  if (mips_pic != SVR4_PIC)
+  /* If we are not generating SVR4 PIC code, or if this is NewABI code,
+   .cprestore is ignored.  */
+  if (mips_pic != SVR4_PIC || HAVE_NEWABI)
     {
       s_ignore (0);
       return;
@@ -11130,6 +11268,65 @@ s_cprestore (ignore)
   demand_empty_rest_of_line ();
 }
 
+/* Handle the .cpreturn pseudo-op defined for NewABI PIC code. If an offset
+   was given in the preceeding .gpsetup, it results in:
+     ld                $gp, offset($sp)
+   
+   If a register $reg2 was given there, it results in:
+     daddiu    $gp, $gp, $reg2
+ */
+static void
+s_cpreturn (ignore)
+     int ignore ATTRIBUTE_UNUSED;
+{
+  expressionS ex;
+  int icnt = 0;
+
+  /* If we are not generating SVR4 PIC code, .cpreturn is ignored.
+     We also need NewABI support.  */
+  if (mips_pic != SVR4_PIC || ! HAVE_NEWABI)
+    {
+      s_ignore (0);
+      return;
+    }
+
+  if (mips_cpreturn_register == -1)
+    {
+      ex.X_op = O_constant;
+      ex.X_add_symbol = NULL;
+      ex.X_op_symbol = NULL;
+      ex.X_add_number = mips_cpreturn_offset;
+
+      macro_build ((char *) NULL, &icnt, &ex, "ld", "t,o(b)",
+                  mips_gp_register, (int) BFD_RELOC_LO16, SP);
+    }
+  else
+    macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "daddu",
+                "d,v,t", mips_gp_register, mips_cpreturn_register, 0);
+
+  demand_empty_rest_of_line ();
+}
+
+/* Handle the .gpvalue pseudo-op.  This is used when generating NewABI PIC
+   code.  It sets the offset to use in gp_rel relocations.  */
+
+static void
+s_gpvalue (ignore)
+     int ignore ATTRIBUTE_UNUSED;
+{
+  /* If we are not generating SVR4 PIC code, .gpvalue is ignored.
+     We also need NewABI support.  */
+  if (mips_pic != SVR4_PIC || ! HAVE_NEWABI)
+    {
+      s_ignore (0);
+      return;
+    }
+
+  mips_cpreturn_offset = get_absolute_expression ();
+
+  demand_empty_rest_of_line ();
+}
+
 /* Handle the .gpword pseudo-op.  This is used when generating PIC
    code.  It generates a 32 bit GP relative reloc.  */
 
@@ -11180,8 +11377,9 @@ s_cpadd (ignore)
   int icnt = 0;
   int reg;
 
-  /* This is ignored when not generating SVR4 PIC code.  */
-  if (mips_pic != SVR4_PIC)
+  /* This is ignored when not generating SVR4 PIC code or if this is NewABI
+     code.  */
+  if (mips_pic != SVR4_PIC || HAVE_NEWABI)
     {
       s_ignore (0);
       return;
@@ -11361,7 +11559,7 @@ nopic_need_relax (sym, before_relaxing)
   if (sym == 0)
     return 0;
 
-  if (USE_GLOBAL_POINTER_OPT)
+  if (USE_GLOBAL_POINTER_OPT && g_switch_value > 0)
     {
       const char *symname;
       int change;
@@ -11832,7 +12030,8 @@ tc_gen_reloc (section, fixp)
          || fixp->fx_r_type == BFD_RELOC_MIPS_GOT_HI16
          || fixp->fx_r_type == BFD_RELOC_MIPS_GOT_LO16
          || fixp->fx_r_type == BFD_RELOC_MIPS_CALL_HI16
-         || fixp->fx_r_type == BFD_RELOC_MIPS_CALL_LO16))
+         || fixp->fx_r_type == BFD_RELOC_MIPS_CALL_LO16)
+      && ! HAVE_NEWABI)
     {
       arelent *reloc2;