/* 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. */
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. */
/* 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)
{
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. */
{"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}}, \
(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;
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 ();
"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.