gcc/ChangeLog:

        * config/rx/predicates.md (rx_plt_call_operand): New predicate.
        * config/rx/rx.md (PIC_REG): New constant.
        (UNSPEC_PIC): Likewise.
        (UNSPEC_GOT): Likewise.
        (UNSPEC_GOTOFF): Likewise.
        (UNSPEC_PLT): Likewise.
        (UNSPEC_GOTFUNCDESC): Likewise.
        (UNSPEC_GOTOFFFUNCDESC): Likewise.
        (UNSPEC_PCOFFSET): Likewise.
        (UNSPEC_PIC_RESTORE): Likewise.
        (UNSPEC_PC_LOCATION): Likewise.
        (tablejump): Use relative in pic case.
        (call): Add FDPIC call.
        (call_value): Likewise.
        (call_internal): Add use PICREG.
        (call_value_internal): Likewise.
        (mov<register_modes:mode>): Generate got reference code in pic.
        (addsi3): Generate got reference code in pic.
        (sym2GOT): New.
        (sym2GOTreg): New.
        (sym2GOTOFF): New.
        (sym2GOTOFFreg): New.
        (sym2GOTFUNCDESC): New.
        (sym2GOTFUNCDESCreg): New.
        (sym2GOTOFFFUNCDESC): New.
        (sym2GOTOFFFUNCDESCreg): New.
        (sym2PLT): New.
        (call_fdpic): New.
        (call_internal_fd): New.
        (call_internal_plt): New.
        (call_value_fdpic): New.
        (call_value_internal_fd): New.
        (call_value_internal_plt): New.
        (pcoffset_label): New.
        (set_got): New.
        (load_pc_location): New.

Signed-off-by: Yoshinori Sato <[email protected]>
---
 gcc/config/rx/predicates.md |   4 +
 gcc/config/rx/rx.md         | 314 +++++++++++++++++++++++++++++++++---
 2 files changed, 298 insertions(+), 20 deletions(-)

diff --git a/gcc/config/rx/predicates.md b/gcc/config/rx/predicates.md
index c51a21449e2..736a8d7a376 100644
--- a/gcc/config/rx/predicates.md
+++ b/gcc/config/rx/predicates.md
@@ -307,3 +307,7 @@
 (define_predicate "rshift_operator"
   (match_code "ashiftrt,lshiftrt")
 )
+
+(define_predicate "rx_plt_call_operand"
+  (match_code "const")
+)
diff --git a/gcc/config/rx/rx.md b/gcc/config/rx/rx.md
index a3d966efdcc..7d76661d51d 100644
--- a/gcc/config/rx/rx.md
+++ b/gcc/config/rx/rx.md
@@ -35,6 +35,7 @@
 (define_constants
   [
    (SP_REG 0)
+   (PIC_REG               13)
    (CC_REG                16)
 
    (UNSPEC_LOW_REG         0)
@@ -76,6 +77,16 @@
 
    (UNSPEC_PID_ADDR       52)
 
+   (UNSPEC_PIC            60)
+   (UNSPEC_GOT            61)
+   (UNSPEC_GOTOFF         62)
+   (UNSPEC_PLT            63)
+   (UNSPEC_GOTFUNCDESC     64)
+   (UNSPEC_GOTOFFFUNCDESC  65)
+   (UNSPEC_PCOFFSET        66)
+   (UNSPEC_PIC_RESTORE     67)
+   (UNSPEC_PC_LOCATION     68)
+
    (CTRLREG_PSW                    0)
    (CTRLREG_PC             1)
    (CTRLREG_USP                    2)
@@ -342,9 +353,9 @@
        (match_operand:SI          0 "register_operand" "r"))
    (use (label_ref (match_operand  1 "" "")))]
   ""
-  { return TARGET_PID ? (TARGET_AS100_SYNTAX ? "\n?:\tbra\t%0"
-                                            : "\n1:\tbra\t%0")
-                                            : "\n1:jmp\t%0";
+  { return TARGET_PID || flag_pic ? (TARGET_AS100_SYNTAX ? "\n?:\tbra\t%0"
+                                                        : "\n1:\tbra\t%0")
+                                                         : "\n1:jmp\t%0";
   }
   [(set_attr "timings" "33")
    (set_attr "length" "2")]
@@ -425,14 +436,23 @@
 
 (define_expand "call"
   [(call (match_operand:QI 0 "general_operand")
-        (match_operand:SI 1 "general_operand"))]
+        (match_operand:SI 1 "general_operand"))
+        (use (match_operand 2 "" ""))
+        (use (reg:SI PIC_REG))]
   ""
   {
     rtx dest = XEXP (operands[0], 0);
 
-    if (! rx_call_operand (dest, Pmode))
-      dest = force_reg (Pmode, dest);
-    emit_call_insn (gen_call_internal (dest));
+    if (!TARGET_FDPIC)
+      {
+        if (! rx_call_operand (dest, Pmode))
+          dest = force_reg (Pmode, dest);
+        emit_call_insn (gen_call_internal (dest));
+      }
+    else
+      {
+       emit_call_insn (gen_call_fdpic(operands[0], operands[1], operands[2]));
+      }
     DONE;
   }
 )
@@ -440,7 +460,8 @@
 (define_insn "call_internal"
   [(call (mem:QI (match_operand:SI 0 "rx_call_operand" "r,CALL_OP_SYMBOL_REF"))
         (const_int 0))
-   (clobber (reg:CC CC_REG))]
+   (clobber (reg:CC CC_REG))
+   (use (reg:SI PIC_REG))]
   ""
   "@
   jsr\t%0
@@ -452,14 +473,24 @@
 (define_expand "call_value"
   [(set (match_operand          0 "register_operand")
        (call (match_operand:QI 1 "general_operand")
-             (match_operand:SI 2 "general_operand")))]
+             (match_operand:SI 2 "general_operand")))
+        (use (match_operand 3 "" ""))
+         (use (reg:SI PIC_REG))]
   ""
   {
     rtx dest = XEXP (operands[1], 0);
 
-    if (! rx_call_operand (dest, Pmode))
-      dest = force_reg (Pmode, dest);
-    emit_call_insn (gen_call_value_internal (operands[0], dest));
+    if (!TARGET_FDPIC ||
+       (SYMBOL_REF_P(dest) && SYMBOL_REF_LOCAL_P(dest)))
+      {
+        if (! rx_call_operand (dest, Pmode))
+          dest = force_reg (Pmode, dest);
+        emit_call_insn (gen_call_value_internal (operands[0], dest));
+      }
+    else
+      {
+        emit_call_insn (gen_call_value_fdpic(operands[0], operands[1], 
operands[2]));
+      }
     DONE;
   }
 )
@@ -468,7 +499,8 @@
   [(set (match_operand                  0 "register_operand" "=r,r")
        (call (mem:QI (match_operand:SI 1 "rx_call_operand"   
"r,CALL_OP_SYMBOL_REF"))
              (const_int 0)))
-   (clobber (reg:CC CC_REG))]
+   (clobber (reg:CC CC_REG))
+   (use (reg:SI PIC_REG))]
   ""
   "@
   jsr\t%1
@@ -576,8 +608,16 @@
   {
     if (MEM_P (operands[0]) && MEM_P (operands[1]))
       operands[1] = copy_to_mode_reg (<register_modes:MODE>mode, operands[1]);
-    operands[0] = rx_maybe_pidify_operand (operands[0], 0);
-    operands[1] = rx_maybe_pidify_operand (operands[1], 0);
+    if (flag_pic)
+      {
+       operands[0] = rx_mov_pic_operands(operands[0], false);
+       operands[1] = rx_mov_pic_operands(operands[1], false);
+      }
+    else
+      {
+       operands[0] = rx_maybe_pidify_operand (operands[0], 0);
+       operands[1] = rx_maybe_pidify_operand (operands[1], 0);
+      }
     if (GET_CODE (operands[0]) != REG
        && GET_CODE (operands[1]) == PLUS)
       operands[1] = copy_to_mode_reg (<register_modes:MODE>mode, operands[1]);
@@ -869,11 +909,20 @@
                 (match_operand:SI 2 "rx_source_operand" "")))
     (clobber (reg:CC CC_REG))])]
   ""
-  "
-      operands[0] = rx_maybe_pidify_operand (operands[0], 1);
-      operands[1] = rx_maybe_pidify_operand (operands[1], 1);
-      operands[2] = rx_maybe_pidify_operand (operands[2], 1);
-  "
+  {
+    if (flag_pic)
+      {
+        operands[0] = rx_mov_pic_operands(operands[0], true);
+        operands[1] = rx_mov_pic_operands(operands[1], true);
+        operands[2] = rx_mov_pic_operands(operands[2], true);
+      }
+    else
+      {
+        operands[0] = rx_maybe_pidify_operand (operands[0], 1);
+        operands[1] = rx_maybe_pidify_operand (operands[1], 1);
+        operands[2] = rx_maybe_pidify_operand (operands[2], 1);
+      }
+  }
 )
 
 (define_insn "addsi3_internal"
@@ -2887,3 +2936,228 @@
   [(set_attr "length" "16")
    (set_attr "timings" "22")]
 )
+
+(define_expand "sym2GOT"
+  [(const (unspec [(match_operand 0 "" "")] UNSPEC_GOT))]
+  ""
+  "")
+
+(define_expand "symGOT2reg"
+  [(match_operand 0 "" "") (match_operand 1 "" "")]
+  ""
+  {
+    rtx mem = !can_create_pseudo_p ()
+      ? operands[0] : gen_reg_rtx (GET_MODE (operands[0]));
+    rtx gotsym = gen_sym2GOTOFF (operands[1]);
+    rtx picreg = gen_rtx_REG (Pmode, PIC_REG);
+    PUT_MODE (gotsym, Pmode);
+
+    emit_insn (gen_addsi3(mem, picreg, gotsym));
+    emit_move_insn (operands[0], gen_rtx_MEM(Pmode, mem));
+    DONE;
+  }
+)
+
+(define_expand "sym2GOTOFF"
+  [(const (unspec [(match_operand 0 "" "")] UNSPEC_GOTOFF))]
+  ""
+  "")
+
+(define_expand "symGOTOFF2reg"
+  [(match_operand 0 "" "") (match_operand 1 "" "")]
+  ""
+  {
+    rtx picreg = gen_rtx_REG (Pmode, PIC_REG);
+
+    rtx gotoffsym = gen_sym2GOTOFF (operands[1]);
+    emit_move_insn (operands[0],
+                   gen_rtx_MEM(Pmode,
+                               gen_rtx_PLUS(Pmode, picreg, gotoffsym)));
+    DONE;
+  }
+)
+
+(define_expand "sym2GOTFUNCDESC"
+  [(const (unspec [(match_operand 0)] UNSPEC_GOTFUNCDESC))]
+  "TARGET_FDPIC")
+
+(define_expand "sym2GOTOFFFUNCDESC"
+  [(const (unspec [(match_operand 0)] UNSPEC_GOTOFFFUNCDESC))]
+  "TARGET_FDPIC")
+
+(define_expand "symGOTFUNCDESC2reg"
+  [(match_operand 0) (match_operand 1)]
+  "TARGET_FDPIC"
+  {
+    rtx picreg = rx_get_fdpic_reg_initial_val();
+    rtx gotsym = gen_sym2GOTFUNCDESC (operands[1]);
+    PUT_MODE (gotsym, Pmode);
+    emit_move_insn (operands[0], gen_rtx_PLUS(Pmode, picreg, gotsym));
+    DONE;
+  }
+)
+
+(define_expand "symGOTOFFFUNCDESC2reg"
+  [(match_operand 0) (match_operand 1)]
+  "TARGET_FDPIC"
+  {
+    rtx picreg = rx_get_fdpic_reg_initial_val();
+    rtx gotsym = gen_sym2GOTOFFFUNCDESC (operands[1]);
+    PUT_MODE (gotsym, Pmode);
+    emit_move_insn (operands[0], gen_rtx_PLUS(Pmode, picreg, gotsym));
+    DONE;
+  }
+)
+
+(define_expand "sym2PLT"
+  [(const (unspec [(match_operand 0 "" "")] UNSPEC_PLT))]
+  ""
+  "")
+
+(define_expand "call_fdpic"
+  [(call (match_operand:QI 0 "general_operand")
+        (match_operand:SI 1 "general_operand"))
+        (use (match_operand 2 "" ""))
+         (use (reg:SI PIC_REG))]
+  ""
+  {
+    rtx picreg = force_reg (Pmode, gen_rtx_REG(Pmode, PIC_REG));
+    rtx dest = XEXP (operands[0], 0);
+
+    if (SYMBOL_REF_P(dest) && SYMBOL_REF_LOCAL_P(dest))
+      {
+       if (! rx_call_operand (dest, Pmode))
+         dest = force_reg (Pmode, dest);
+       emit_call_insn (gen_call_internal (dest));
+      }
+    else
+      {
+       rtx savereg = gen_reg_rtx(Pmode);
+
+       emit_move_insn (savereg, picreg);
+       if (MEM_P(operands[0]) && SYMBOL_REF_P(dest))
+         {
+           dest = gen_sym2PLT(dest);
+           emit_call_insn (gen_call_internal_plt (dest));
+         }
+       else
+         {
+           rtx func = gen_reg_rtx(Pmode);
+           emit_move_insn(picreg, gen_rtx_MEM(Pmode,
+                                              plus_constant(Pmode, dest, 4)));
+           emit_move_insn(func, gen_rtx_MEM(Pmode, dest));
+           emit_call_insn (gen_call_internal_fd (func));
+         }
+       emit_move_insn (picreg, savereg);
+      }
+    DONE;
+  }
+)
+
+(define_insn "call_internal_fd"
+  [(call (mem:QI (match_operand:SI 0 "register_operand" "r"))
+        (const_int 0))
+   (clobber (reg:CC CC_REG))
+   (use (reg:SI PIC_REG))]
+  ""
+  "jsr\t%A0"
+  [(set_attr "length" "2")
+   (set_attr "timings" "33")]
+)
+
+(define_insn "call_internal_plt"
+  [(call (mem:QI (match_operand 0 "rx_plt_call_operand" ""))
+        (const_int 0))
+   (clobber (reg:CC CC_REG))
+   (use (reg:SI PIC_REG))]
+  ""
+  "bsr\t%A0"
+  [(set_attr "length" "4")
+   (set_attr "timings" "33")]
+)
+
+(define_expand "call_value_fdpic"
+  [(call (match_operand:QI 0 "general_operand")
+        (match_operand:SI 1 "general_operand"))
+        (use (match_operand 2 "" ""))
+         (use (reg:SI PIC_REG))]
+  ""
+  {
+    rtx picreg = force_reg (Pmode, gen_rtx_REG(Pmode, PIC_REG));
+    rtx dest = XEXP (operands[1], 0);
+
+    if (SYMBOL_REF_P(dest) && SYMBOL_REF_LOCAL_P(dest))
+      {
+       if (! rx_call_operand (dest, Pmode))
+         dest = force_reg (Pmode, dest);
+       emit_call_insn (gen_call_internal (dest));
+      }
+    else
+      {
+       rtx savereg = gen_reg_rtx(Pmode);
+       emit_move_insn (savereg, picreg);
+       if (MEM_P(operands[1]) && SYMBOL_REF_P(dest))
+         {
+           dest = gen_sym2PLT(dest);
+           emit_call_insn (gen_call_value_internal_plt (operands[0], dest));
+         }
+       else
+         {
+           rtx fnc = gen_reg_rtx(Pmode);
+           emit_move_insn(picreg, gen_rtx_MEM(Pmode,
+                                              plus_constant(Pmode, dest, 4)));
+           emit_move_insn(fnc, gen_rtx_MEM(Pmode, dest));
+           emit_call_insn (gen_call_value_internal_fd (operands[0], fnc));
+         }
+       emit_move_insn (picreg, savereg);
+      }
+    DONE;
+  }
+)
+
+(define_insn "call_value_internal_plt"
+  [(set (match_operand               0 "register_operand" "=r")
+       (call (mem:QI (match_operand 1 "rx_plt_call_operand" ""))
+             (const_int 0)))
+   (clobber (reg:CC CC_REG))
+   (use (reg:SI PIC_REG))]
+  ""
+  "bsr\t%A1"
+  [(set_attr "length" "4")
+   (set_attr "timings" "33")]
+)
+
+(define_insn "call_value_internal_fd"
+  [(set (match_operand                  0 "register_operand" "=r")
+       (call (mem:QI (match_operand:SI 1 "register_operand"   "r"))
+             (const_int 0)))
+   (clobber (reg:CC CC_REG))
+   (use (reg:SI PIC_REG))]
+  ""
+  "jsr\t%1"
+  [(set_attr "length" "2")
+   (set_attr "timings" "33")]
+)
+
+(define_expand "pcoffset_label"
+  [(const:SI (unspec:SI [(match_operand:SI 0)] UNSPEC_PCOFFSET))]
+  ""
+  ""
+)
+
+(define_insn "set_got"
+  [(set (match_operand:SI 0 "register_operand" "+r,r")
+        (unspec:SI [(match_dup 0)
+                    (match_operand:SI 1 "nonimmediate_operand" "r,m")]
+                   UNSPEC_PIC_RESTORE))]
+  ""
+  "mov.L\t%1, %0"
+)
+
+(define_insn "load_pc_location"
+  [(set (match_operand:SI             0 "register_operand" "=r")
+       (unspec_volatile:SI [(match_operand:SI 1 "immediate_operand" "i")]
+                  UNSPEC_PC_LOCATION))]
+  ""
+  "\n1:\tmvfc\t%C1, %0"
+)
-- 
2.47.3

Reply via email to