gcc/ChangeLog:

        * config/rx/rx.cc (rx_legitimize_address): Add PIC support.
        (legitimize_pic_address): New.
        (rx_is_legitimate_address): Add PIC case.
        (+nonpic_symbol_mentioned_p): New.
        (rx_print_operand_address): Add PIC symbol attribute.
        (rx_assemble_integer): Add PIC case output.
        (rx_print_operand): Add PC based address output.
        (rx_get_stack_layout): Save PIC registers.
        (rx_expand_prologue): Genarate PIC prologue.
        (rx_elf_asm_cdtor): Add FDPIC special output.
        (rx_option_override): fdpic support.
        (rx_function_ok_for_sibcall): Use relative call in fdpic mode.
        (rx_is_legitimate_constant): Add PIC support.
        (rx_legitimate_pic_operand_p): New.
        (rx_load_function_descriptor): New.
        (rx_get_fdpic_reg_initial_val) New.
        (rx_mov_pic_operands): New.
        (rx_asm_output_addr_const_extra) New.
        (rx_const_not_ok_for_debug_p): New.
        (rx_pic_vector_address): New.
        (rx_cannot_force_const_mem_p): New.
        (TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA): New.
        (TARGET_CONST_NOT_OK_FOR_DEBUG_P): New.
        (TARGET_CANNOT_FORCE_CONST_MEM): New.

Signed-off-by: Yoshinori Sato <[email protected]>
---
 gcc/config/rx/rx.cc | 390 +++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 384 insertions(+), 6 deletions(-)

diff --git a/gcc/config/rx/rx.cc b/gcc/config/rx/rx.cc
index c5638817d08..865637e434c 100644
--- a/gcc/config/rx/rx.cc
+++ b/gcc/config/rx/rx.cc
@@ -148,6 +148,9 @@ rx_legitimize_address (rtx x,
                       rtx oldx ATTRIBUTE_UNUSED,
                       machine_mode mode ATTRIBUTE_UNUSED)
 {
+  if (flag_pic)
+    return legitimize_pic_address (oldx, mode, NULL_RTX);
+
   if (rx_pid_data_operand (x) == PID_UNENCODED)
     {
       rtx rv = gen_pid_addr (gen_rtx_REG (SImode, rx_pid_base_regnum ()), x);
@@ -163,6 +166,59 @@ rx_legitimize_address (rtx x,
   return x;
 }
 
+/* Convert a non-PIC address in `orig' to a PIC address using @GOT or
+   @GOTOFF in `reg'.  */
+rtx
+legitimize_pic_address (rtx orig, machine_mode mode ATTRIBUTE_UNUSED, rtx reg)
+{
+  if (flag_plt && (GET_CODE (orig) == LABEL_REF ||
+                  (GET_CODE (orig) == SYMBOL_REF &&
+                   !SYMBOL_REF_LOCAL_P (orig))))
+    {
+      if (reg == NULL_RTX)
+       reg = gen_reg_rtx (Pmode);
+
+      if (TARGET_FDPIC)
+       {
+         if (GET_CODE (orig) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (orig))
+           emit_insn (gen_symGOTOFFFUNCDESC2reg (reg, orig));
+         else
+           emit_insn (gen_symGOT2reg (reg, orig));
+       }
+      crtl->uses_pic_offset_table = 1;
+      return reg;
+    }
+  else if (GET_CODE (orig) == SYMBOL_REF)
+    {
+      if (reg == NULL_RTX)
+       reg = gen_reg_rtx (Pmode);
+
+      if (TARGET_FDPIC &&
+         SYMBOL_REF_FUNCTION_P (orig) && SYMBOL_REF_EXTERNAL_P(orig))
+       emit_insn (gen_symGOTFUNCDESC2reg (reg, orig));
+      else
+       emit_insn (gen_symGOT2reg (reg, orig));
+      crtl->uses_pic_offset_table = 1;
+      return reg;
+    }
+  else if ((MEM_P(orig) && GET_CODE (XEXP (orig, 1)) == LABEL_REF) &&
+          (GET_CODE (orig) == SYMBOL_REF && SYMBOL_REF_DECL (orig)
+           && (TREE_READONLY (SYMBOL_REF_DECL (orig)))))
+    {
+      rtx label = XEXP (orig, 1);
+      if (reg == NULL_RTX)
+       reg = gen_reg_rtx(Pmode);
+      emit_insn(gen_load_pc_location(reg, GEN_INT (CTRLREG_PC)));
+      if (GET_CODE (orig) == PLUS)
+       {
+         label = gen_pcoffset_label(label);
+         XEXP (orig, 1) = XEXP (orig, 0);
+         XEXP (orig, 0) = gen_rtx_PLUS(Pmode, reg, label);
+       }
+    }
+  return orig;
+}
+
 /* Return true if OP is a reference to an object in a small data area.  */
 
 static bool
@@ -262,6 +318,8 @@ rx_is_legitimate_address (machine_mode mode, rtx x,
              && CONST_INT_P (factor)
              && GET_MODE_SIZE (mode) == INTVAL (factor);
          }
+       case CONST:
+         return GET_CODE (XEXP (index, 0)) == UNSPEC;
 
        default:
          return false;
@@ -272,6 +330,45 @@ rx_is_legitimate_address (machine_mode mode, rtx x,
   return rx_small_data_operand (x);
 }
 
+/* Return TRUE if X references a SYMBOL_REF or LABEL_REF whose symbol
+   isn't protected by a PIC unspec.  */
+bool
+nonpic_symbol_mentioned_p (rtx x)
+{
+  if (GET_CODE (x) == PC)
+    return true;
+
+  /* We don't want to look into the possible MEM location of a
+     CONST_DOUBLE, since we're not going to use it, in general.  */
+  if (GET_CODE (x) == CONST_DOUBLE)
+    return false;
+
+  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
+         || XINT (x, 1) == UNSPEC_GOTFUNCDESC
+         || XINT (x, 1) == UNSPEC_GOTOFFFUNCDESC
+         || XINT (x, 1) == UNSPEC_PCOFFSET))
+    return false;
+
+  const char* fmt = GET_RTX_FORMAT (GET_CODE (x));
+  for (int i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
+    {
+      if (fmt[i] == 'E')
+       {
+         for (int j = XVECLEN (x, i) - 1; j >= 0; j--)
+           if (nonpic_symbol_mentioned_p (XVECEXP (x, i, j)))
+             return true;
+       }
+      else if (fmt[i] == 'e' && nonpic_symbol_mentioned_p (XEXP (x, i)))
+       return true;
+    }
+
+  return false;
+}
+
 /* Returns TRUE for simple memory addresses, ie ones
    that do not involve register indirect addressing
    or pre/post increment/decrement.  */
@@ -461,7 +558,47 @@ rx_print_operand_address (FILE * file, machine_mode 
/*mode*/, rtx addr)
       break;
 
     case UNSPEC:
-      addr = XVECEXP (addr, 0, 0);
+      {
+       int post = XINT (addr, 1);
+       const char *attr = NULL;
+       bool immideate = false;
+#define ATTR_STR(_name) \
+  case UNSPEC_##_name: \
+    addr = XVECEXP (addr, 0, 0); \
+    attr = #_name; \
+    break
+#define ATTR_STR_IMM(_name) \
+  case UNSPEC_##_name: \
+    addr = XVECEXP (addr, 0, 0); \
+    attr = #_name; \
+    immideate = true; \
+    break
+
+       switch (post)
+         {
+           ATTR_STR(GOT);
+           ATTR_STR(GOTFUNCDESC);
+           ATTR_STR(PLT);
+           ATTR_STR_IMM(GOTOFF);
+           ATTR_STR_IMM(GOTOFFFUNCDESC);
+         case UNSPEC_PCOFFSET:
+           output_addr_const (file, addr);
+           return;
+         }
+       if (attr)
+         {
+           if (SYMBOL_REF_P(addr))
+             {
+               if (immideate)
+                 fprintf (file, "#");
+               output_addr_const (file, addr);
+               fprintf (file, "@%s", attr);
+             }
+           else
+             rx_print_operand (file, addr, 0);
+           return;
+         }
+      }
       /* Fall through.  */
     case LABEL_REF:
     case SYMBOL_REF:
@@ -490,6 +627,15 @@ rx_assemble_integer (rtx x, unsigned int size, int 
is_aligned)
 {
   const char *  op = integer_asm_op (size, is_aligned);
 
+    if (TARGET_FDPIC && size == UNITS_PER_WORD
+      && GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (x))
+    {
+      fputs (op, asm_out_file);
+      output_addr_const (asm_out_file, x);
+      fputs ("@FUNCDESC\n", asm_out_file);
+      return true;
+    }
+
   if (! CONST_INT_P (x))
     return default_assemble_integer (x, size, is_aligned);
 
@@ -917,6 +1063,11 @@ rx_print_operand (FILE * file, rtx op, int letter)
                fprintf (file, ")");
                return;
              }
+           case UNSPEC_PCOFFSET:
+             if (print_hash)
+               fprintf (file, "#");
+             output_addr_const(file, op);
+             return;
            }
          /* Fall through */
 
@@ -1496,7 +1647,8 @@ rx_get_stack_layout (unsigned int * lowest,
                 to call-used by rx_conditional_register_usage.  If so then
                 they can be used in the fast interrupt handler without
                 saving them on the stack.  */
-             || (is_fast_interrupt_func (NULL_TREE)
+             || is_fast_interrupt_func (NULL_TREE)
+             || ((flag_pic && reg == PIC_REG)
                  && ! IN_RANGE (reg, 10, 13))))
        {
          if (low == 0)
@@ -1832,6 +1984,13 @@ rx_expand_prologue (void)
                    GEN_INT ((HOST_WIDE_INT) stack_size),
                    true);
     }
+  if (crtl->uses_pic_offset_table && !TARGET_FDPIC)
+    {
+      rtx picreg = gen_rtx_REG (Pmode, PIC_REG);
+      rtx gotsym = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
+      emit_insn (gen_mvfc (picreg, GEN_INT (CTRLREG_PC)));
+      emit_move_insn (picreg, gen_rtx_PLUS (Pmode, picreg, gotsym));
+    }
 }
 
 static void
@@ -2681,7 +2840,14 @@ rx_elf_asm_cdtor (rtx symbol, int priority, bool is_ctor)
 
   switch_to_section (s);
   assemble_align (POINTER_SIZE);
-  assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
+  if (!TARGET_FDPIC)
+    assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
+  else
+    {
+      fputs ("\t.long\t", asm_out_file);
+      output_addr_const (asm_out_file, symbol);
+      fputs ("\n", asm_out_file);
+    }
 }
 
 static void
@@ -2832,6 +2998,13 @@ rx_option_override (void)
   if (flag_strict_volatile_bitfields < 0 && abi_version_at_least(2))
     flag_strict_volatile_bitfields = 1;
 
+  /* FDPIC code is a special form of PIC, and the vast majority of code
+     generation constraints that apply to PIC also apply to FDPIC, so we
+     set flag_pic to avoid the need to check TARGET_FDPIC everywhere
+     flag_pic is checked. */
+  if (TARGET_FDPIC && !flag_pic)
+    flag_pic = 2;
+
   rx_override_options_after_change ();
 
   /* These values are bytes, not log.  */
@@ -2879,7 +3052,7 @@ rx_warn_func_return (tree decl)
 static bool
 rx_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
 {
-  if (TARGET_JSR)
+  if (TARGET_JSR || TARGET_FDPIC)
     return false;
 
   /* Do not allow indirect tailcalls.  The
@@ -2936,10 +3109,17 @@ rx_is_legitimate_constant (machine_mode mode 
ATTRIBUTE_UNUSED, rtx x)
        {
        case LABEL_REF:
        case SYMBOL_REF:
-         return true;
+         return !flag_pic;
 
        case UNSPEC:
-         return XINT (x, 1) == UNSPEC_CONST || XINT (x, 1) == UNSPEC_PID_ADDR;
+         return XINT (x, 1) == UNSPEC_CONST ||
+                XINT (x, 1) == UNSPEC_PID_ADDR ||
+                XINT (x, 1) == UNSPEC_GOT ||
+                XINT (x, 1) == UNSPEC_GOTOFF ||
+                XINT (x, 1) == UNSPEC_GOTFUNCDESC ||
+                XINT (x, 1) == UNSPEC_GOTOFFFUNCDESC ||
+                XINT (x, 1) == UNSPEC_PLT ||
+                XINT (x, 1) == UNSPEC_PCOFFSET;
 
        default:
          /* FIXME: Can this ever happen ?  */
@@ -3644,7 +3824,196 @@ rx_c_mode_for_floating_type (enum tree_index ti)
     return TARGET_64BIT_DOUBLES ? DFmode : SFmode;
   return default_mode_for_floating_type (ti);
 }
+
+int rx_legitimate_pic_operand_p(rtx x)
+{
+  return (! nonpic_symbol_mentioned_p (x)
+         && GET_CODE (x) != SYMBOL_REF);
+}
+
+
+
+/* Emit insns to load the function address from FUNCDESC (an FDPIC
+   function descriptor) and the GOT address */
+
+rtx
+rx_load_function_descriptor (rtx sym)
+{
+  rtx gotsym = gen_sym2GOTOFFFUNCDESC (sym);
+  rtx picreg = gen_rtx_REG (Pmode, PIC_REG);
+  rtx func = gen_reg_rtx (GET_MODE (sym));
+  rtx got;
+  rtx tmp = gen_reg_rtx(Pmode);
+
+  emit_move_insn (picreg, rx_get_fdpic_reg_initial_val ());
+  PUT_MODE (gotsym, Pmode);
+  got = gen_rtx_MEM(Pmode, plus_constant(Pmode, picreg, 4));
+  emit_move_insn(tmp, gen_rtx_MEM(Pmode, gotsym));
+  emit_move_insn(picreg, gen_rtx_PLUS(Pmode, picreg, tmp));
+  emit_move_insn(func, gen_rtx_MEM(Pmode, picreg));
+  emit_insn(gen_set_got(picreg, got));
+
+  return func;
+}
+
+/* Return an rtx holding the initial value of the FDPIC register (the
+   FDPIC pointer passed in from the caller).  */
+
+rtx
+rx_get_fdpic_reg_initial_val (void)
+{
+  return get_hard_reg_initial_val (Pmode, PIC_REG);
+}
+
+rtx
+rx_mov_pic_operands (rtx x, bool offset)
+{
+  rtx gotsym = NULL;
+  rtx funcsym = NULL;
+  rtx picreg = gen_rtx_REG (Pmode, PIC_REG);
+  rtx t;
+
+  if (!can_create_pseudo_p ())
+    {
+      if (!offset &&
+         MEM_P(x) && GET_CODE(XEXP(x, 0)) == PLUS &&
+         GET_CODE(XEXP(XEXP(x, 0), 1)) == CONST &&
+         GET_CODE(XEXP(XEXP(XEXP(x, 0), 1), 0)) == UNSPEC)
+       switch(XINT(XEXP(XEXP(XEXP(x, 0), 1), 0), 1))
+         {
+         case UNSPEC_GOTOFFFUNCDESC:
+           XINT(XEXP(XEXP(XEXP(x, 0), 1), 0), 1) = UNSPEC_GOTFUNCDESC;
+           break;
+         case UNSPEC_GOTOFF:
+           XINT(XEXP(XEXP(XEXP(x, 0), 1), 0), 1) = UNSPEC_GOT;
+           break;
+         }
+      return x;
+    }
+  if (GET_CODE(x) == CONST &&
+      (GET_CODE(XEXP(x, 0)) == PLUS || GET_CODE(XEXP(x, 0)) == MINUS) &&
+      GET_CODE(XEXP(XEXP(x, 0), 0)) == SYMBOL_REF)
+    {
+      if (TREE_READONLY (SYMBOL_REF_DECL (XEXP(XEXP(x, 0), 0))))
+       {
+         // PC relative with offset
+         rtx label = gen_pcoffset_label(XEXP(XEXP(x, 0), 0));
+         t = gen_reg_rtx (GET_MODE(x));
+         emit_insn(gen_load_pc_location(t, GEN_INT(CTRLREG_PC)));
+         emit_insn(gen_addsi3(t, t, label));
+         if (GET_CODE(XEXP(x, 0)) == PLUS)
+           emit_insn(gen_addsi3(t, t, XEXP(XEXP(x, 0), 1)));
+         else
+           emit_insn(gen_subsi3(t, t, XEXP(XEXP(x, 0), 1)));
+         return t;
+       }
+      else
+       {
+         // GOT with offset
+         gotsym = gen_sym2GOT (XEXP(XEXP(x, 0), 0));
+         t = gen_reg_rtx (GET_MODE(x));
+         emit_move_insn(t, gen_rtx_MEM(GET_MODE(x),
+                                       gen_rtx_PLUS(Pmode, picreg, gotsym)));
+         crtl->uses_pic_offset_table = true;
+         if (GET_CODE(XEXP(x, 0)) == PLUS)
+           emit_insn(gen_addsi3(t, t, XEXP(XEXP(x, 0), 1)));
+         else
+           emit_insn(gen_subsi3(t, t, XEXP(XEXP(x, 0), 1)));
+         return t;
+       }
+    }
+  if (GET_CODE(x) == SYMBOL_REF)
+    {
+      if (!RTX_FLAG (x, frame_related))
+       {
+         if (TARGET_FDPIC && SYMBOL_REF_FUNCTION_P(x))
+           funcsym = !offset ?
+             gen_sym2GOTOFFFUNCDESC (x) : gen_sym2GOTFUNCDESC (x);
+         else
+           gotsym = offset ? gen_sym2GOTOFF (x) : gen_sym2GOT(x);
+       }
+      else if (TREE_READONLY (SYMBOL_REF_DECL (x)))
+       {
+         // PC relative address
+         rtx label = gen_pcoffset_label(x);
+         t = gen_reg_rtx (GET_MODE(x));
+         emit_insn(gen_load_pc_location(t, GEN_INT(CTRLREG_PC)));
+         emit_insn(gen_addsi3(t, t, label));
+         return t;
+       }
+      else
+       gotsym = gen_sym2GOT (x);
+    }
+  if (gotsym)
+    {
+      if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_DECL (x)
+         && (TREE_READONLY (SYMBOL_REF_DECL (x))))
+       {
+         rtx reg = gen_reg_rtx(Pmode);
+         rtx label = gen_pcoffset_label(x);
+         emit_insn(gen_load_pc_location(reg, GEN_INT (CTRLREG_PC)));
+         return gen_rtx_PLUS(Pmode, reg, label);
+       }
+      t = gen_rtx_MEM(GET_MODE(x), gen_rtx_PLUS(Pmode, picreg, gotsym));
+      crtl->uses_pic_offset_table = true;
+      return t;
+    }
+  else if (funcsym)
+    {
+      t = gen_reg_rtx (GET_MODE(x));
+      emit_insn(gen_addsi3(t, picreg, funcsym));
+      return t;
+    }
+  else
+    return x;
+}
+
+/* Implement TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA.  */
+static bool
+rx_asm_output_addr_const_extra (FILE *file, rtx x)
+{
+  if (GET_CODE (x) == UNSPEC)
+    {
+      switch (XINT (x, 1))
+       {
+       case UNSPEC_PCOFFSET:
+         output_addr_const (file, XVECEXP (x, 0, 0));
+         fprintf (file, " - 1b");
+         break;
+       default:
+         return false;
+       }
+      return true;
+    }
+  else
+    return false;
+}
+
+static bool
+rx_const_not_ok_for_debug_p (rtx p)
+{
+  return (GET_CODE (p) == SYMBOL_REF);
+}
+
+rtx rx_pic_vector_address(rtx index)
+{
+  rtx base = gen_reg_rtx(SImode);
+  rtx label = gen_pcoffset_label(XEXP(index, 1));
+
+  emit_insn(gen_load_pc_location(base, GEN_INT(1)));
+  XEXP(index, 1) = gen_rtx_PLUS(SImode, base, label);
+  return index;
+}
+
+bool
+rx_cannot_force_const_mem_p (machine_mode mode ATTRIBUTE_UNUSED,
+                            rtx x ATTRIBUTE_UNUSED)
+{
+  return flag_pic;
+}
+
 
+
 #undef  TARGET_NARROW_VOLATILE_BITFIELD
 #define TARGET_NARROW_VOLATILE_BITFIELD                
rx_narrow_volatile_bitfield
 
@@ -3809,6 +4178,15 @@ rx_c_mode_for_floating_type (enum tree_index ti)
 #undef TARGET_DOCUMENTATION_NAME
 #define TARGET_DOCUMENTATION_NAME "RX"
 
+#undef TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA
+#define TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA rx_asm_output_addr_const_extra
+
+#undef TARGET_CONST_NOT_OK_FOR_DEBUG_P
+#define TARGET_CONST_NOT_OK_FOR_DEBUG_P rx_const_not_ok_for_debug_p
+
+#undef TARGET_CANNOT_FORCE_CONST_MEM
+#define TARGET_CANNOT_FORCE_CONST_MEM rx_cannot_force_const_mem_p
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-rx.h"
-- 
2.47.3

Reply via email to