OSDN Git Service

2003-06-16 Alexandre Oliva <aoliva@redhat.com>
authoraoliva <aoliva@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 10 Jul 2003 03:25:32 +0000 (03:25 +0000)
committeraoliva <aoliva@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 10 Jul 2003 03:25:32 +0000 (03:25 +0000)
* config/mn10300/mn10300.c (mn10300_unspec_int_label_counter):
Moved from...
* config/mn10300/mn10300.md (GOTaddr2picreg): ... here.
* config/mn10300/mn10300.h: GTY-declare it.
2003-06-11  Alexandre Oliva  <aoliva@redhat.com>
* config/mn10300/mn10300.c (mn10300_encode_section_info): Fix
prototype.  Use incoming RTL argument.
2002-12-12  Alexandre Oliva  <aoliva@redhat.com>
* config/mn10300/mn10300.md (int_label): Move C statements...
(GOTaddr2picreg): ... here.
2002-08-15  Alexandre Oliva  <aoliva@redhat.com>
* config/mn10300/mn10300.h (ENCODE_SECTION_INFO): Move...
* config/mn10300/mn10300.c (mn10300_encode_section_info):
... here.  New function.
(TARGET_ENCODE_SECTION_INFO): Define to it.
2001-11-04  Alexandre Oliva  <aoliva@redhat.com>
* config/mn10300/mn10300.md (builtin_setjmp_receiver): Fix typo in
pattern name.
(mn10300_loadPC): Define as insn splittable after reload.
2001-05-13  Alexandre Oliva  <aoliva@redhat.com>
* config/sh/mn10300.h (JUMP_TABLES_IN_TEXT_SECTION): Let them
be defined in .rodata even in PIC, now that the assembler
supports that.
2001-05-09  Alexandre Oliva  <aoliva@redhat.com>
* config/mn10300/mn10300.h (GOT_SYMBOL_NAME): Don't let the
symbol take an underscore prefix.
2001-04-14  Alexandre Oliva  <aoliva@redhat.com>
* config/mn10300/mn10300-protos.h (legitimate_pic_operand_p,
legitimize_pic_address): Declare.
* config/mn10300/mn10300.h (CONDITIONAL_REGISTER_USAGE): Mark
the PIC register as fixed.
(EXTRA_CONSTRAINT): Match UNSPEC_PLT and UNSPEC_PIC for 'S'.
(GO_IF_LEGITIMATE_ADDRESS): Require legitimate_pic_operand for
PIC.
(LEGITIMATE_PIC_OPERAND_P): Define.
(PIC_OFFSET_TABLE_REGNUM): Define.
(GOT_SYMBOL_NAME): Define.
(SYMBOLIC_CONST_P): Define.
(ENCODE_SECTION_INFO): Use SYMBOL_REF_FLAG to mark local
symbols.
(MN10300_GLOBAL_P): Test it.
(OUTPUT_ADDR_CONST_EXTRA): Handle PIC-related unspecs.
(JUMP_TABLES_IN_TEXT_SECTION): Enable for PIC.
* config/mn10300/mn10300.c (print_operand): Handle unspec.
(expand_prologue): Set PIC register.
(call_address_operand): Don't match SYMBOL_REFs in PIC.
(legitimize_address): Call legitimize_pic_address.
(legitimize_pic_address): New fn.
(legitimate_pic_operand_p): New fn.
* config/mn10300/mn10300.md (PIC_REG, SP_REG): New constants.
(UNSPEC_INT_LABEL, UNSPEC_PIC, UNSPEC_GOT, UNSPEC_GOTOFF,
UNSPEC_PLT): New constants.
(pop_pic_reg): New insn.
(movsi): Adjust non-PIC addresses.
(builtin_setjmp_receiver): Restore the PIC register.
(casesi): New insn.
(call): Adjust non-PIC addresses.
(int_label, GOTaddr2picreg): New expands.
(am33_loadPC): New insn.
(mn10300_loadPC): New expand.
(call_next_insn): New insn.
(add_GOT_to_pic_reg): New expand.
(symGOT2reg, symGOT2reg_i): New expands.
(symGOTOFF2reg, symGOTOFF2reg_i): New expands.
(sym2PIC, sym2PLT): New expands.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@69169 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/config/mn10300/mn10300-protos.h
gcc/config/mn10300/mn10300.c
gcc/config/mn10300/mn10300.h
gcc/config/mn10300/mn10300.md

index d01693a..3e07a5b 100644 (file)
@@ -1,5 +1,74 @@
 2003-07-09  Alexandre Oliva  <aoliva@redhat.com>
 
+       2003-06-16  Alexandre Oliva  <aoliva@redhat.com>
+       * config/mn10300/mn10300.c (mn10300_unspec_int_label_counter):
+       Moved from...
+       * config/mn10300/mn10300.md (GOTaddr2picreg): ... here.
+       * config/mn10300/mn10300.h: GTY-declare it.
+       2003-06-11  Alexandre Oliva  <aoliva@redhat.com>
+       * config/mn10300/mn10300.c (mn10300_encode_section_info): Fix
+       prototype.  Use incoming RTL argument.
+       2002-12-12  Alexandre Oliva  <aoliva@redhat.com>
+       * config/mn10300/mn10300.md (int_label): Move C statements...
+       (GOTaddr2picreg): ... here.
+       2002-08-15  Alexandre Oliva  <aoliva@redhat.com>
+       * config/mn10300/mn10300.h (ENCODE_SECTION_INFO): Move...
+       * config/mn10300/mn10300.c (mn10300_encode_section_info):
+       ... here.  New function.
+       (TARGET_ENCODE_SECTION_INFO): Define to it.
+       2001-11-04  Alexandre Oliva  <aoliva@redhat.com>
+       * config/mn10300/mn10300.md (builtin_setjmp_receiver): Fix typo in
+       pattern name.
+       (mn10300_loadPC): Define as insn splittable after reload.
+       2001-05-13  Alexandre Oliva  <aoliva@redhat.com>
+       * config/sh/mn10300.h (JUMP_TABLES_IN_TEXT_SECTION): Let them
+       be defined in .rodata even in PIC, now that the assembler
+       supports that.
+       2001-05-09  Alexandre Oliva  <aoliva@redhat.com>
+       * config/mn10300/mn10300.h (GOT_SYMBOL_NAME): Don't let the
+       symbol take an underscore prefix.
+       2001-04-14  Alexandre Oliva  <aoliva@redhat.com>
+       * config/mn10300/mn10300-protos.h (legitimate_pic_operand_p,
+       legitimize_pic_address): Declare.
+       * config/mn10300/mn10300.h (CONDITIONAL_REGISTER_USAGE): Mark
+       the PIC register as fixed.
+       (EXTRA_CONSTRAINT): Match UNSPEC_PLT and UNSPEC_PIC for 'S'.
+       (GO_IF_LEGITIMATE_ADDRESS): Require legitimate_pic_operand for
+       PIC.
+       (LEGITIMATE_PIC_OPERAND_P): Define.
+       (PIC_OFFSET_TABLE_REGNUM): Define.
+       (GOT_SYMBOL_NAME): Define.
+       (SYMBOLIC_CONST_P): Define.
+       (ENCODE_SECTION_INFO): Use SYMBOL_REF_FLAG to mark local
+       symbols.
+       (MN10300_GLOBAL_P): Test it.
+       (OUTPUT_ADDR_CONST_EXTRA): Handle PIC-related unspecs.
+       (JUMP_TABLES_IN_TEXT_SECTION): Enable for PIC.
+       * config/mn10300/mn10300.c (print_operand): Handle unspec.
+       (expand_prologue): Set PIC register.
+       (call_address_operand): Don't match SYMBOL_REFs in PIC.
+       (legitimize_address): Call legitimize_pic_address.
+       (legitimize_pic_address): New fn.
+       (legitimate_pic_operand_p): New fn.
+       * config/mn10300/mn10300.md (PIC_REG, SP_REG): New constants.
+       (UNSPEC_INT_LABEL, UNSPEC_PIC, UNSPEC_GOT, UNSPEC_GOTOFF,
+       UNSPEC_PLT): New constants.
+       (pop_pic_reg): New insn.
+       (movsi): Adjust non-PIC addresses.
+       (builtin_setjmp_receiver): Restore the PIC register.
+       (casesi): New insn.
+       (call): Adjust non-PIC addresses.
+       (int_label, GOTaddr2picreg): New expands.
+       (am33_loadPC): New insn.
+       (mn10300_loadPC): New expand.
+       (call_next_insn): New insn.
+       (add_GOT_to_pic_reg): New expand.
+       (symGOT2reg, symGOT2reg_i): New expands.
+       (symGOTOFF2reg, symGOTOFF2reg_i): New expands.
+       (sym2PIC, sym2PLT): New expands.
+
+2003-07-09  Alexandre Oliva  <aoliva@redhat.com>
+
        * config/mn10300/mn10300.h (PREDICATE_CODES): Define.
        2001-05-01  Alexandre Oliva  <aoliva@redhat.com>
        * config/mn10300/mn10300.md (sqrtsf2): flag_fast_math was renamed
index 209a7e6..74154d9 100644 (file)
@@ -26,6 +26,8 @@ extern void mn10300_va_start PARAMS ((tree, rtx));
 #endif /* TREE_CODE */
 
 extern struct rtx_def *legitimize_address PARAMS ((rtx, rtx, enum machine_mode));
+extern rtx legitimize_pic_address   (rtx, rtx);
+extern int legitimate_pic_operand_p (rtx);
 extern void print_operand PARAMS ((FILE *, rtx, int));
 extern void print_operand_address PARAMS ((FILE *, rtx));
 extern void mn10300_print_reg_list PARAMS ((FILE *, int));
index bb14b4c..e4ef4bf 100644 (file)
@@ -44,6 +44,10 @@ Boston, MA 02111-1307, USA.  */
 #include "target.h"
 #include "target-def.h"
 
+/* This is used by GOTaddr2picreg to uniquely identify
+   UNSPEC_INT_LABELs.  */
+int mn10300_unspec_int_label_counter;
+
 /* The size of the callee register save area.  Right now we save everything
    on entry since it costs us nothing in code size.  It does cost us from a
    speed standpoint, so we want to optimize this sooner or later.  */
@@ -75,6 +79,10 @@ static void mn10300_file_start PARAMS ((void));
 #undef TARGET_ASM_FILE_START_FILE_DIRECTIVE
 #define TARGET_ASM_FILE_START_FILE_DIRECTIVE true
 
+#undef  TARGET_ENCODE_SECTION_INFO
+#define TARGET_ENCODE_SECTION_INFO mn10300_encode_section_info
+
+static void mn10300_encode_section_info (tree, rtx, int);
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 static void
@@ -410,6 +418,7 @@ print_operand (file, x, code)
          case CONST:
          case LABEL_REF:
          case CODE_LABEL:
+         case UNSPEC:
            print_operand_address (file, x);
            break;
          default:
@@ -881,6 +890,24 @@ expand_prologue ()
     emit_insn (gen_addsi3 (stack_pointer_rtx,
                           stack_pointer_rtx,
                           GEN_INT (-size)));
+  if (flag_pic && regs_ever_live[PIC_OFFSET_TABLE_REGNUM])
+    {
+      rtx insn = get_last_insn ();
+      rtx last = emit_insn (gen_GOTaddr2picreg ());
+
+      /* Mark these insns as possibly dead.  Sometimes, flow2 may
+        delete all uses of the PIC register.  In this case, let it
+        delete the initialization too.  */
+      do
+       {
+         insn = NEXT_INSN (insn);
+
+         REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD,
+                                               const0_rtx,
+                                               REG_NOTES (insn));
+       }
+      while (insn != last);
+    }
 }
 
 void
@@ -1269,6 +1296,9 @@ call_address_operand (op, mode)
      rtx op;
      enum machine_mode mode ATTRIBUTE_UNUSED;
 {
+  if (flag_pic)
+    return (EXTRA_CONSTRAINT (op, 'S') || GET_CODE (op) == REG);
+
   return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == REG);
 }
 
@@ -1756,6 +1786,9 @@ legitimize_address (x, oldx, mode)
      rtx oldx ATTRIBUTE_UNUSED;
      enum machine_mode mode ATTRIBUTE_UNUSED;
 {
+  if (flag_pic && ! legitimate_pic_operand_p (x))
+    x = legitimize_pic_address (oldx, NULL_RTX);
+
   /* Uh-oh.  We might have an address for x[n-100000].  This needs
      special handling to avoid creating an indexed memory address
      with x-100000 as the base.  */
@@ -1786,6 +1819,75 @@ legitimize_address (x, oldx, mode)
   return x;
 }
 
+/* Convert a non-PIC address in `orig' to a PIC address using @GOT or
+   @GOTOFF in `reg'. */
+rtx
+legitimize_pic_address (orig, reg)
+     rtx orig;
+     rtx reg;
+{
+  if (GET_CODE (orig) == LABEL_REF
+      || (GET_CODE (orig) == SYMBOL_REF
+         && (CONSTANT_POOL_ADDRESS_P (orig)
+             || ! MN10300_GLOBAL_P (orig))))
+    {
+      if (reg == 0)
+       reg = gen_reg_rtx (Pmode);
+
+      emit_insn (gen_symGOTOFF2reg (reg, orig));
+      return reg;
+    }
+  else if (GET_CODE (orig) == SYMBOL_REF)
+    {
+      if (reg == 0)
+       reg = gen_reg_rtx (Pmode);
+
+      emit_insn (gen_symGOT2reg (reg, orig));
+      return reg;
+    }
+  return orig;
+}
+
+/* Return zero if X references a SYMBOL_REF or LABEL_REF whose symbol
+   isn't protected by a PIC unspec; non-zero otherwise.  */
+int
+legitimate_pic_operand_p (x)
+     rtx x;
+{
+  register const char *fmt;
+  register int i;
+
+  if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)
+    return 0;
+
+  if (GET_CODE (x) == UNSPEC
+      && (XINT (x, 1) == UNSPEC_PIC
+         || XINT (x, 1) == UNSPEC_GOT
+         || XINT (x, 1) == UNSPEC_GOTOFF
+         || XINT (x, 1) == UNSPEC_PLT))
+      return 1;
+
+  if (GET_CODE (x) == QUEUED)
+    return legitimate_pic_operand_p (QUEUED_VAR (x));
+
+  fmt = GET_RTX_FORMAT (GET_CODE (x));
+  for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
+    {
+      if (fmt[i] == 'E')
+       {
+         register int j;
+
+         for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+           if (! legitimate_pic_operand_p (XVECEXP (x, i, j)))
+             return 0;
+       }
+      else if (fmt[i] == 'e' && ! legitimate_pic_operand_p (XEXP (x, i)))
+       return 0;
+    }
+
+  return 1;
+}
+
 static int
 mn10300_address_cost_1 (x, unsig)
      rtx x;
@@ -1973,3 +2075,23 @@ mn10300_wide_const_load_uses_clr (operands)
 
   return val[0] == 0 || val[1] == 0;
 }
+/* If using PIC, mark a SYMBOL_REF for a non-global symbol so that we
+   may access it using GOTOFF instead of GOT.  */
+
+static void
+mn10300_encode_section_info (decl, rtl, first)
+     tree decl;
+     rtx rtl;
+     int first;
+{
+  rtx symbol;
+
+  if (GET_CODE (rtl) != MEM)
+    return;
+  symbol = XEXP (rtl, 0);
+  if (GET_CODE (symbol) != SYMBOL_REF)
+    return;
+
+  if (flag_pic)
+    SYMBOL_REF_FLAG (symbol) = (*targetm.binds_local_p) (decl);
+}
index 75d4183..2432a38 100644 (file)
@@ -46,6 +46,8 @@ Boston, MA 02111-1307, USA.  */
 
 extern int target_flags;
 
+extern GTY(()) int mn10300_unspec_int_label_counter;
+
 /* Macros used in the machine description to test the flags.  */
 
 /* Macro to define tables used to set the flags.
@@ -212,6 +214,8 @@ extern int target_flags;
            i++)                                \
        fixed_regs[i] = call_used_regs[i] = 1;  \
     }                                          \
+  if (flag_pic)                                        \
+    fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1;   \
 }
 
 /* Return number of consecutive hard regs needed starting at reg REGNO
@@ -735,6 +739,9 @@ struct cum_arg {int nbytes; };
 #define EXTRA_CONSTRAINT(OP, C) \
  ((C) == 'R' ? OK_FOR_R (OP) \
   : (C) == 'Q' ? OK_FOR_Q (OP) \
+  : (C) == 'S' && flag_pic \
+  ? GET_CODE (OP) == UNSPEC && (XINT (OP, 1) == UNSPEC_PLT \
+                               || XINT (OP, 1) == UNSPEC_PIC) \
   : (C) == 'S' ? GET_CODE (OP) == SYMBOL_REF \
   : (C) == 'T' ? OK_FOR_T (OP) \
   : 0)
@@ -775,7 +782,8 @@ struct cum_arg {int nbytes; };
 
 #define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR)        \
 {                                                      \
-  if (CONSTANT_ADDRESS_P (X))                          \
+  if (CONSTANT_ADDRESS_P (X)                           \
+      && (! flag_pic || legitimate_pic_operand_p (X))) \
     goto ADDR;                                         \
   if (RTX_OK_FOR_BASE_P (X))                           \
     goto ADDR;                                         \
@@ -797,6 +805,8 @@ struct cum_arg {int nbytes; };
        {                                               \
          if (GET_CODE (index) == CONST_INT)            \
            goto ADDR;                                  \
+         if (GET_CODE (index) == CONST)                \
+           goto ADDR;                                  \
        }                                               \
     }                                                  \
 }
@@ -833,6 +843,60 @@ struct cum_arg {int nbytes; };
 
 #define LEGITIMATE_CONSTANT_P(X) 1
 
+/* Zero if this needs fixing up to become PIC.  */
+
+#define LEGITIMATE_PIC_OPERAND_P(X) (legitimate_pic_operand_p (X))
+
+/* Register to hold the addressing base for
+   position independent code access to data items.  */
+#define PIC_OFFSET_TABLE_REGNUM        PIC_REG
+
+/* The name of the pseudo-symbol representing the Global Offset Table.  */
+#define GOT_SYMBOL_NAME "*_GLOBAL_OFFSET_TABLE_"
+
+#define SYMBOLIC_CONST_P(X)    \
+((GET_CODE (X) == SYMBOL_REF || GET_CODE (X) == LABEL_REF)     \
+  && ! LEGITIMATE_PIC_OPERAND_P (X))
+
+/* Non-global SYMBOL_REFs have SYMBOL_REF_FLAG enabled.  */
+#define MN10300_GLOBAL_P(X) (! SYMBOL_REF_FLAG (X))
+
+/* Recognize machine-specific patterns that may appear within
+   constants.  Used for PIC-specific UNSPECs.  */
+#define OUTPUT_ADDR_CONST_EXTRA(STREAM, X, FAIL) \
+  do                                                                   \
+    if (GET_CODE (X) == UNSPEC && XVECLEN ((X), 0) == 1)       \
+      {                                                                        \
+       switch (XINT ((X), 1))                                          \
+         {                                                             \
+         case UNSPEC_INT_LABEL:                                        \
+           asm_fprintf ((STREAM), ".%LLIL%d",                          \
+                        INTVAL (XVECEXP ((X), 0, 0)));                 \
+           break;                                                      \
+         case UNSPEC_PIC:                                              \
+           /* GLOBAL_OFFSET_TABLE or local symbols, no suffix.  */     \
+           output_addr_const ((STREAM), XVECEXP ((X), 0, 0));          \
+           break;                                                      \
+         case UNSPEC_GOT:                                              \
+           output_addr_const ((STREAM), XVECEXP ((X), 0, 0));          \
+           fputs ("@GOT", (STREAM));                                   \
+           break;                                                      \
+         case UNSPEC_GOTOFF:                                           \
+           output_addr_const ((STREAM), XVECEXP ((X), 0, 0));          \
+           fputs ("@GOTOFF", (STREAM));                                \
+           break;                                                      \
+         case UNSPEC_PLT:                                              \
+           output_addr_const ((STREAM), XVECEXP ((X), 0, 0));          \
+           fputs ("@PLT", (STREAM));                                   \
+           break;                                                      \
+         default:                                                      \
+           goto FAIL;                                                  \
+         }                                                             \
+       break;                                                          \
+      }                                                                        \
+    else                                                               \
+      goto FAIL;                                                       \
+  while (0)
 \f
 /* Tell final.c how to eliminate redundant test instructions.  */
 
index a615f6b..27a40ef 100644 (file)
 ;; clobber - value of cc is unknown
 (define_attr "cc" "none,none_0hit,set_znv,set_zn,compare,clobber,invert"
   (const_string "clobber"))
+
+(define_constants [
+  (PIC_REG     6)
+  (SP_REG      9)
+
+  (UNSPEC_INT_LABEL    0)
+  (UNSPEC_PIC          1)
+  (UNSPEC_GOT          2)
+  (UNSPEC_GOTOFF       3)
+  (UNSPEC_PLT          4)
+])
 \f
 ;; ----------------------------------------------------------------------
 ;; MOVE INSTRUCTIONS
   DONE;
 }")
 
+(define_insn "pop_pic_reg"
+  [(set (reg:SI PIC_REG)
+       (mem:SI (post_inc:SI (reg:SI SP_REG))))]
+  "reload_completed"
+  "movm (sp),[a2]")
+
 (define_expand "movsi"
   [(set (match_operand:SI 0 "general_operand" "")
        (match_operand:SI 1 "general_operand" ""))]
   if (!register_operand (operand1, SImode)
       && !register_operand (operand0, SImode))
     operands[1] = copy_to_mode_reg (SImode, operand1);
+  if (flag_pic)
+    {
+      rtx temp;
+      if (SYMBOLIC_CONST_P (operands[1]))
+       {
+         if (GET_CODE (operands[0]) == MEM)
+           operands[1] = force_reg (Pmode, operands[1]);
+         else
+           {
+             temp = no_new_pseudos ? operands[0] : gen_reg_rtx (Pmode);
+             operands[1] = legitimize_pic_address (operands[1], temp);
+           }
+       }
+      else if (GET_CODE (operands[1]) == CONST
+              && GET_CODE (XEXP (operands[1], 0)) == PLUS
+              && SYMBOLIC_CONST_P (XEXP (XEXP (operands[1], 0), 0)))
+       {
+         temp = no_new_pseudos ? operands[0] : gen_reg_rtx (Pmode);
+         temp = legitimize_pic_address (XEXP (XEXP (operands[1], 0), 0),
+                                        temp);
+         operands[1] = expand_binop (SImode, add_optab, temp,
+                                     XEXP (XEXP (operands[1], 0), 1),
+                                     no_new_pseudos ? temp
+                                     : gen_reg_rtx (Pmode),
+                                     0, OPTAB_LIB_WIDEN);
+       }
+    }
 }")
 
 (define_insn ""
   "jmp (%0)"
   [(set_attr "cc" "none")])
 
+(define_expand "builtin_setjmp_receiver"
+  [(match_operand 0 "" "")]
+  "flag_pic"
+  "
+{
+  if (flag_pic)
+    emit_insn (gen_GOTaddr2picreg ());
+
+  DONE;
+}")
+
+(define_expand "casesi"
+  [(match_operand:SI 0 "register_operand" "")
+   (match_operand:SI 1 "immediate_operand" "")
+   (match_operand:SI 2 "immediate_operand" "")
+   (match_operand 3 "" "") (match_operand 4 "" "")]
+  ""
+  "
+{
+  rtx table = gen_reg_rtx (SImode);
+  rtx index = gen_reg_rtx (SImode);
+  rtx addr = gen_reg_rtx (Pmode);
+
+  emit_move_insn (table, gen_rtx_LABEL_REF (VOIDmode, operands[3]));
+  emit_move_insn (index, plus_constant (operands[0], - INTVAL (operands[1])));
+  emit_insn (gen_cmpsi (index, operands[2]));
+  emit_jump_insn (gen_bgtu (operands[4]));
+  emit_move_insn (index, gen_rtx_ASHIFT (SImode, index, GEN_INT (2)));
+  emit_move_insn (addr, gen_rtx_MEM (SImode,
+                                    gen_rtx_PLUS (SImode, table, index)));
+  if (flag_pic)
+    emit_move_insn (addr, gen_rtx_PLUS (SImode, addr, table));
+
+  emit_jump_insn (gen_tablejump (addr, operands[3]));
+  DONE;
+}")
+
 (define_insn "tablejump"
   [(set (pc) (match_operand:SI 0 "register_operand" "a"))
    (use (label_ref (match_operand 1 "" "")))]
   ""
   "
 {
+  if (flag_pic && GET_CODE (XEXP (operands[0], 0)) == SYMBOL_REF)
+    {
+      if (MN10300_GLOBAL_P (XEXP (operands[0], 0)))
+       {
+         /* The PLT code won't run on AM30, but then, there's no
+            shared library support for AM30 either, so we just assume
+            the linker is going to adjust all @PLT relocs to the
+            actual symbols.  */
+         emit_insn (gen_rtx_USE (VOIDmode, pic_offset_table_rtx));
+         XEXP (operands[0], 0) = gen_sym2PLT (XEXP (operands[0], 0));
+       }
+      else
+       XEXP (operands[0], 0) = gen_sym2PIC (XEXP (operands[0], 0));
+    }
   if (! call_address_operand (XEXP (operands[0], 0), VOIDmode))
     XEXP (operands[0], 0) = force_reg (SImode, XEXP (operands[0], 0));
   emit_call_insn (gen_call_internal (XEXP (operands[0], 0), operands[1]));
   ""
   "
 {
+  if (flag_pic && GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF)
+    {
+      if (MN10300_GLOBAL_P (XEXP (operands[1], 0)))
+       {
+         /* The PLT code won't run on AM30, but then, there's no
+            shared library support for AM30 either, so we just assume
+            the linker is going to adjust all @PLT relocs to the
+            actual symbols.  */
+         emit_insn (gen_rtx_USE (VOIDmode, pic_offset_table_rtx));
+         XEXP (operands[1], 0) = gen_sym2PLT (XEXP (operands[1], 0));
+       }
+      else
+       XEXP (operands[1], 0) = gen_sym2PIC (XEXP (operands[1], 0));
+    }
   if (! call_address_operand (XEXP (operands[1], 0), VOIDmode))
     XEXP (operands[1], 0) = force_reg (SImode, XEXP (operands[1], 0));
   emit_call_insn (gen_call_value_internal (operands[0],
   "add %0,%0\;bcc %1"
   [(set_attr "cc" "clobber")])
 
+(define_expand "int_label"
+  [(unspec [(match_operand:SI 0 "" "")] UNSPEC_INT_LABEL)]
+  "" "")
+
+(define_expand "GOTaddr2picreg"
+  [(match_dup 0)]
+  "" "
+{
+  /* It would be nice to be able to have int_label keep track of the
+     counter and all, but if we add C code to it, we'll get an insn
+     back, and we just want the pattern.  */
+  operands[0] = gen_int_label (GEN_INT (mn10300_unspec_int_label_counter++));
+  if (TARGET_AM33)
+    emit_insn (gen_am33_loadPC (operands[0]));
+  else
+    emit_insn (gen_mn10300_loadPC (operands[0]));
+  emit_insn (gen_add_GOT_to_pic_reg (operands[0]));
+  DONE;
+}
+")
+
+(define_insn "am33_loadPC"
+  [(parallel
+    [(set (reg:SI PIC_REG) (pc))
+     (use (match_operand 0 "" ""))])]
+  "TARGET_AM33"
+  "%0:\;mov pc,a2")
+
+
+(define_insn_and_split "mn10300_loadPC"
+  [(parallel
+    [(set (reg:SI PIC_REG) (pc))
+     (use (match_operand 0 "" ""))])]
+  ""
+  "#"
+  "reload_completed"
+  [(match_operand 0 "" "")]
+  "
+{
+  rtx sp_reg = gen_rtx_REG (SImode, SP_REG);
+  int need_stack_space = (get_frame_size () == 0
+                         && current_function_outgoing_args_size == 0);
+
+  if (need_stack_space)
+    emit_move_insn (sp_reg, plus_constant (sp_reg, -4));
+
+  emit_insn (gen_call_next_insn (operands[0]));
+
+  if (need_stack_space)
+    emit_insn (gen_pop_pic_reg ());
+  else
+    emit_move_insn (pic_offset_table_rtx, gen_rtx_MEM (SImode, sp_reg));
+
+  DONE;
+}")
+
+(define_insn "call_next_insn"
+  [(parallel
+    [(set (mem:SI (reg:SI SP_REG)) (pc))
+     (use (match_operand 0 "" ""))])]
+  "reload_completed"
+  "calls %0\;%0:")
+
+(define_expand "add_GOT_to_pic_reg"
+  [(set (reg:SI PIC_REG)
+       (plus:SI
+        (reg:SI PIC_REG)
+        (const
+         (unspec [(minus:SI
+                   (match_dup 1)
+                   (const (minus:SI
+                           (const (match_operand:SI 0 "" ""))
+                           (pc))))
+                 ] UNSPEC_PIC))))]
+  ""
+  "
+{
+  operands[1] = gen_rtx_SYMBOL_REF (VOIDmode, GOT_SYMBOL_NAME);
+}")
+
+(define_expand "symGOT2reg"
+  [(match_operand:SI 0 "" "")
+   (match_operand:SI 1 "" "")]
+  ""
+  "
+{
+  rtx insn = emit_insn (gen_symGOT2reg_i (operands[0], operands[1]));
+
+  RTX_UNCHANGING_P (SET_SRC (PATTERN (insn))) = 1;
+
+  REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, operands[1],
+                                       REG_NOTES (insn));
+
+  DONE;
+}")
+
+(define_expand "symGOT2reg_i"
+  [(set (match_operand:SI 0 "" "")
+       (mem:SI (plus:SI (reg:SI PIC_REG)
+                        (const (unspec [(match_operand:SI 1 "" "")]
+                                       UNSPEC_GOT)))))]
+  ""
+  "")
+
+(define_expand "symGOTOFF2reg"
+  [(match_operand:SI 0 "" "") (match_operand:SI 1 "" "")]
+  ""
+  "
+{
+  rtx insn = emit_insn (gen_symGOTOFF2reg_i (operands[0], operands[1]));
+
+  REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, operands[1],
+                                       REG_NOTES (insn));
+
+  DONE;
+}")
+
+(define_expand "symGOTOFF2reg_i"
+  [(set (match_operand:SI 0 "" "")
+       (const (unspec [(match_operand:SI 1 "" "")] UNSPEC_GOTOFF)))
+  (set (match_dup 0) (plus:SI (match_dup 0) (reg:SI PIC_REG)))]
+  ""
+  "")
+
+(define_expand "sym2PIC"
+  [(unspec [(match_operand:SI 0 "" "")] UNSPEC_PIC)]
+  "" "")
+
+(define_expand "sym2PLT"
+  [(unspec [(match_operand:SI 0 "" "")] UNSPEC_PLT)]
+  "" "")