Commit 766a866c by Michael Meissner

Add -fpic/-fPIC support

From-SVN: r11676
parent 2038dc12
...@@ -93,6 +93,9 @@ enum rs6000_abi rs6000_current_abi; ...@@ -93,6 +93,9 @@ enum rs6000_abi rs6000_current_abi;
/* Temporary memory used to convert integer -> float */ /* Temporary memory used to convert integer -> float */
static rtx stack_temps[NUM_MACHINE_MODES]; 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;
/* Print the options used in the assembly file. */ /* Print the options used in the assembly file. */
...@@ -524,6 +527,18 @@ reg_or_cint_operand (op, mode) ...@@ -524,6 +527,18 @@ reg_or_cint_operand (op, mode)
return GET_CODE (op) == CONST_INT || gpc_reg_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 /* Return the number of instructions it takes to form a constant in an
integer register. */ integer register. */
...@@ -3663,6 +3678,7 @@ output_epilog (file, size) ...@@ -3663,6 +3678,7 @@ output_epilog (file, size)
/* Reset varargs and save TOC indicator */ /* Reset varargs and save TOC indicator */
rs6000_sysv_varargs_p = 0; rs6000_sysv_varargs_p = 0;
rs6000_save_toc_p = 0; rs6000_save_toc_p = 0;
rs6000_pic_register = (rtx)0;
if (DEFAULT_ABI == ABI_NT) if (DEFAULT_ABI == ABI_NT)
{ {
......
...@@ -1842,6 +1842,54 @@ typedef struct rs6000_args ...@@ -1842,6 +1842,54 @@ typedef struct rs6000_args
goto LABEL; \ goto LABEL; \
} }
/* 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) */
/* Define this if some processing needs to be done immediately before /* Define this if some processing needs to be done immediately before
emitting code for an insn. */ emitting code for an insn. */
...@@ -2769,6 +2817,7 @@ do { \ ...@@ -2769,6 +2817,7 @@ do { \
{"reg_or_neg_short_operand", {SUBREG, REG, CONST_INT}}, \ {"reg_or_neg_short_operand", {SUBREG, REG, CONST_INT}}, \
{"reg_or_u_short_operand", {SUBREG, REG, CONST_INT}}, \ {"reg_or_u_short_operand", {SUBREG, REG, CONST_INT}}, \
{"reg_or_cint_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}}, \ {"easy_fp_constant", {CONST_DOUBLE}}, \
{"reg_or_mem_operand", {SUBREG, MEM, REG}}, \ {"reg_or_mem_operand", {SUBREG, MEM, REG}}, \
{"lwa_operand", {SUBREG, MEM, REG}}, \ {"lwa_operand", {SUBREG, MEM, REG}}, \
...@@ -2804,7 +2853,8 @@ do { \ ...@@ -2804,7 +2853,8 @@ do { \
(no need to use the default) */ (no need to use the default) */
#define MACHINE_issue_rate #define MACHINE_issue_rate
/* General optimization flags. */ /* General flags. */
extern int flag_pic;
extern int optimize; extern int optimize;
extern int flag_expensive_optimizations; extern int flag_expensive_optimizations;
...@@ -2824,6 +2874,7 @@ extern int reg_or_short_operand (); ...@@ -2824,6 +2874,7 @@ extern int reg_or_short_operand ();
extern int reg_or_neg_short_operand (); extern int reg_or_neg_short_operand ();
extern int reg_or_u_short_operand (); extern int reg_or_u_short_operand ();
extern int reg_or_cint_operand (); extern int reg_or_cint_operand ();
extern int got_operand ();
extern int num_insns_constant (); extern int num_insns_constant ();
extern int easy_fp_constant (); extern int easy_fp_constant ();
extern int volatile_mem_operand (); extern int volatile_mem_operand ();
......
...@@ -4815,6 +4815,68 @@ ...@@ -4815,6 +4815,68 @@
"TARGET_ELF && !TARGET_64BIT" "TARGET_ELF && !TARGET_64BIT"
"{cal %0,%a2@l(%1)|addi %0,%1,%2@l}") "{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 ;; 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, ;; 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 ;; and this is even supposed to be faster, but it is simpler not to get
...@@ -4842,6 +4904,12 @@ ...@@ -4842,6 +4904,12 @@
DONE; 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 if (TARGET_ELF && TARGET_NO_TOC && !TARGET_64BIT
&& CONSTANT_P (operands[1]) && CONSTANT_P (operands[1])
&& GET_CODE (operands[1]) != HIGH && GET_CODE (operands[1]) != HIGH
...@@ -6985,7 +7053,7 @@ ...@@ -6985,7 +7053,7 @@
else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS) else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS)
output_asm_insn (\"creqv 6,6,6\", operands); 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 "type" "branch")
(set_attr "length" "4,8")]) (set_attr "length" "4,8")])
...@@ -7055,7 +7123,7 @@ ...@@ -7055,7 +7123,7 @@
else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS) else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS)
output_asm_insn (\"creqv 6,6,6\", operands); 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 "type" "branch")
(set_attr "length" "4,8")]) (set_attr "length" "4,8")])
...@@ -7123,6 +7191,16 @@ ...@@ -7123,6 +7191,16 @@
"" ""
"{ics|isync}") "{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")])
;; Compare insns are next. Note that the RS/6000 has two types of compares, ;; Compare insns are next. Note that the RS/6000 has two types of compares,
;; signed & unsigned, and one type of branch. ;; signed & unsigned, and one type of branch.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment