From 766a866c11644e16aadc27aa954332d4b0c464ac Mon Sep 17 00:00:00 2001 From: Michael Meissner Date: Mon, 8 Apr 1996 19:48:29 +0000 Subject: [PATCH] Add -fpic/-fPIC support From-SVN: r11676 --- gcc/config/rs6000/rs6000.c | 16 ++++++++ gcc/config/rs6000/rs6000.h | 53 +++++++++++++++++++++++- gcc/config/rs6000/rs6000.md | 82 ++++++++++++++++++++++++++++++++++++- 3 files changed, 148 insertions(+), 3 deletions(-) diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index 9a35b2f212d..cd3f675d73b 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -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; + /* 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) { diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h index 669dacbf885..1620ad484e1 100644 --- a/gcc/config/rs6000/rs6000.h +++ b/gcc/config/rs6000/rs6000.h @@ -1841,6 +1841,54 @@ typedef struct rs6000_args if (GET_CODE (ADDR) == LO_SUM) \ 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 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 (); diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index 58258b3ad92..5aa18139142 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -4815,6 +4815,68 @@ "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 @@ -4842,6 +4904,12 @@ 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 @@ -6985,7 +7053,7 @@ 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")]) @@ -7055,7 +7123,7 @@ 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")]) @@ -7123,6 +7191,16 @@ "" "{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, ;; signed & unsigned, and one type of branch. -- 2.30.2