Add -fpic/-fPIC support
authorMichael Meissner <meissner@gcc.gnu.org>
Mon, 8 Apr 1996 19:48:29 +0000 (19:48 +0000)
committerMichael Meissner <meissner@gcc.gnu.org>
Mon, 8 Apr 1996 19:48:29 +0000 (19:48 +0000)
From-SVN: r11676

gcc/config/rs6000/rs6000.c
gcc/config/rs6000/rs6000.h
gcc/config/rs6000/rs6000.md

index 9a35b2f212dcf67eaf292950d97bd4ead91474ed..cd3f675d73b296662a19725de95fb96114a4eb0f 100644 (file)
@@ -93,6 +93,9 @@ enum rs6000_abi rs6000_current_abi;
 /* Temporary memory used to convert integer -> float */
 static rtx stack_temps[NUM_MACHINE_MODES];
 
+/* Current PIC register used by the V4 code */
+struct rtx_def *rs6000_pic_register = (struct rtx_def *)0;
+
 \f
 /* Print the options used in the assembly file.  */
 
@@ -524,6 +527,18 @@ reg_or_cint_operand (op, mode)
      return GET_CODE (op) == CONST_INT || gpc_reg_operand (op, mode);
 }
 
+/* Return 1 if the operand is an operand that can be loaded via the GOT */
+
+int
+got_operand (op, mode)
+     register rtx op;
+     enum machine_mode mode;
+{
+  return (GET_CODE (op) == SYMBOL_REF
+         || GET_CODE (op) == CONST
+         || GET_CODE (op) == LABEL_REF);
+}
+
 /* Return the number of instructions it takes to form a constant in an
    integer register.  */
 
@@ -3663,6 +3678,7 @@ output_epilog (file, size)
   /* Reset varargs and save TOC indicator */
   rs6000_sysv_varargs_p = 0;
   rs6000_save_toc_p = 0;
+  rs6000_pic_register = (rtx)0;
 
   if (DEFAULT_ABI == ABI_NT)
     {
index 669dacbf885f454d5862803dacc14779872409c7..1620ad484e10c631a31673b7ce73558f6150d012 100644 (file)
@@ -1841,6 +1841,54 @@ typedef struct rs6000_args
   if (GET_CODE (ADDR) == LO_SUM)                               \
     goto LABEL;                                                        \
 }
+\f
+/* The register number of the register used to address a table of
+   static data addresses in memory.  In some cases this register is
+   defined by a processor's "application binary interface" (ABI).
+   When this macro is defined, RTL is generated for this register
+   once, as with the stack pointer and frame pointer registers.  If
+   this macro is not defined, it is up to the machine-dependent files
+   to allocate such a register (if necessary).  */
+
+/* #define PIC_OFFSET_TABLE_REGNUM */
+
+/* Define this macro if the register defined by
+   `PIC_OFFSET_TABLE_REGNUM' is clobbered by calls.  Do not define
+   this macro if `PPIC_OFFSET_TABLE_REGNUM' is not defined. */
+
+/* #define PIC_OFFSET_TABLE_REG_CALL_CLOBBERED */
+
+/* By generating position-independent code, when two different
+   programs (A and B) share a common library (libC.a), the text of
+   the library can be shared whether or not the library is linked at
+   the same address for both programs.  In some of these
+   environments, position-independent code requires not only the use
+   of different addressing modes, but also special code to enable the
+   use of these addressing modes.
+
+   The `FINALIZE_PIC' macro serves as a hook to emit these special
+   codes once the function is being compiled into assembly code, but
+   not before.  (It is not done before, because in the case of
+   compiling an inline function, it would lead to multiple PIC
+   prologues being included in functions which used inline functions
+   and were compiled to assembly language.)  */
+
+/* #define FINALIZE_PIC */
+
+/* Current PIC register used by the V4 code */
+extern struct rtx_def *rs6000_pic_register;
+
+
+/* A C expression that is nonzero if X is a legitimate immediate
+   operand on the target machine when generating position independent
+   code.  You can assume that X satisfies `CONSTANT_P', so you need
+   not check this.  You can also assume FLAG_PIC is true, so you need
+   not check it either.  You need not define this macro if all
+   constants (including `SYMBOL_REF') can be immediate operands when
+   generating position independent code.  */
+
+/* #define LEGITIMATE_PIC_OPERAND_P (X) */
+
 \f
 /* Define this if some processing needs to be done immediately before
    emitting code for an insn.  */
@@ -2769,6 +2817,7 @@ do {                                                                      \
   {"reg_or_neg_short_operand", {SUBREG, REG, CONST_INT}},      \
   {"reg_or_u_short_operand", {SUBREG, REG, CONST_INT}},                \
   {"reg_or_cint_operand", {SUBREG, REG, CONST_INT}},           \
+  {"got_operand", {SYMBOL_REF, CONST, LABEL_REF}},             \
   {"easy_fp_constant", {CONST_DOUBLE}},                                \
   {"reg_or_mem_operand", {SUBREG, MEM, REG}},                  \
   {"lwa_operand", {SUBREG, MEM, REG}},                         \
@@ -2804,7 +2853,8 @@ do {                                                                      \
    (no need to use the default) */
 #define MACHINE_issue_rate
 
-/* General optimization flags.  */
+/* General flags.  */
+extern int flag_pic;
 extern int optimize;
 extern int flag_expensive_optimizations;
 
@@ -2824,6 +2874,7 @@ extern int reg_or_short_operand ();
 extern int reg_or_neg_short_operand ();
 extern int reg_or_u_short_operand ();
 extern int reg_or_cint_operand ();
+extern int got_operand ();
 extern int num_insns_constant ();
 extern int easy_fp_constant ();
 extern int volatile_mem_operand ();
index 58258b3ad9293d9d645e42eeeec6957803b344a7..5aa18139142c76688ee3b96dc539146c55344b51 100644 (file)
    "TARGET_ELF && !TARGET_64BIT"
    "{cal %0,%a2@l(%1)|addi %0,%1,%2@l}")
 
+;; Set up a register with a value from the GOT table
+
+(define_expand "movsi_got"
+  [(set (match_operand:SI 0 "register_operand" "")
+       (unspec [(match_operand:SI 1 "got_operand" "")
+                (match_dup 2)] 8))]
+  "DEFAULT_ABI == ABI_V4 && flag_pic"
+  "
+{
+  if (!rs6000_pic_register)
+    {
+      rs6000_pic_register = gen_reg_rtx (SImode);
+      emit_insn (gen_init_v4_pic (rs6000_pic_register));
+    }
+
+  operands[2] = rs6000_pic_register;
+  if (flag_pic > 1)
+    {
+      emit_insn (gen_movsi_got_large (operands[0], operands[1], operands[2]));
+      DONE;
+    }
+}")
+
+(define_insn "*movsi_got_internal1"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (unspec [(match_operand:SI 1 "got_operand" "")
+                (match_operand:SI 2 "register_operand" "b")] 8))]
+  "DEFAULT_ABI == ABI_V4 && flag_pic == 1"
+  "{l|lwz} %0,%a1@got(%2)"
+  [(set_attr "type" "load")])
+
+(define_expand "movsi_got_large"
+  [(set (match_dup 3)
+       (unspec [(match_operand:SI 1 "got_operand" "")] 9))
+   (set (match_dup 3)
+       (unspec [(match_dup 1)
+                (match_dup 3)] 10))
+   (set (match_operand:SI 0 "register_operand" "")
+       (mem:SI (plus:SI (match_dup 3)
+                        (match_operand:SI 2 "register_operand" ""))))]
+  "DEFAULT_ABI == ABI_V4 && flag_pic > 1"
+  "
+{
+  if (reload_completed || reload_in_progress)
+    abort ();
+
+  operands[3] = gen_reg_rtx (SImode);
+}")
+
+(define_insn "*movsi_got_internal2_high"
+  [(set (match_operand:SI 0 "register_operand" "=b")
+       (unspec [(match_operand:SI 1 "got_operand" "")] 9))]
+  "DEFAULT_ABI == ABI_V4 && flag_pic > 1"
+  "{cau|addis} %0,0,%1@got@ha")
+
+(define_insn "*movsi_got_internal2_losum"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (unspec [(match_operand:SI 1 "got_operand" "")
+                (match_operand:SI 2 "register_operand" "b")] 10))]
+  "DEFAULT_ABI == ABI_V4 && flag_pic > 1"
+  "{cal %0,%a1@got@l(%2)|addi %0,%2,%a1@got@l}")
+
 ;; For SI, we special-case integers that can't be loaded in one insn.  We
 ;; do the load 16-bits at a time.  We could do this by loading from memory,
 ;; and this is even supposed to be faster, but it is simpler not to get
       DONE;
     }
 
+  if (DEFAULT_ABI == ABI_V4 && flag_pic && got_operand (operands[1], SImode))
+    {
+      emit_insn (gen_movsi_got (operands[0], operands[1]));
+      DONE;
+    }
+
   if (TARGET_ELF && TARGET_NO_TOC && !TARGET_64BIT
       && CONSTANT_P (operands[1])
       && GET_CODE (operands[1]) != HIGH
   else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS)
     output_asm_insn (\"creqv 6,6,6\", operands);
 
-  return \"bl %z0\";
+  return (flag_pic) ? \"bl %z0@plt\" : \"bl %z0\";
 }"
   [(set_attr "type" "branch")
    (set_attr "length" "4,8")])
   else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS)
     output_asm_insn (\"creqv 6,6,6\", operands);
 
-  return \"bl %z1\";
+  return (flag_pic) ? \"bl %z1@plt\" : \"bl %z1\";
 }"
   [(set_attr "type" "branch")
    (set_attr "length" "4,8")])
   ""
   "{ics|isync}")
 
+
+;; V.4 specific code to initialize the PIC register
+
+(define_insn "init_v4_pic"
+  [(set (match_operand:SI 0 "register_operand" "=l")
+       (unspec [(const_int 0)] 7))]
+  "DEFAULT_ABI == ABI_V4"
+  "bl _GLOBAL_OFFSET_TABLE_-4"
+  [(set_attr "type" "branch")])
+
 \f
 ;; Compare insns are next.  Note that the RS/6000 has two types of compares,
 ;; signed & unsigned, and one type of branch.