#include "expr.h"
#include "obstack.h"
#include "tree.h"
+#include "function.h"
#ifndef TARGET_NO_PROTOTYPE
#define TARGET_NO_PROTOTYPE 0
}
}
+\f
+/* Define the structure for the machine field in struct function. */
+struct machine_function
+{
+ int sysv_varargs_p;
+ int save_toc_p;
+ int fpmem_size;
+ int fpmem_offset;
+};
+
+/* Functions to save and restore rs6000_fpmem_size.
+ These will be called, via pointer variables,
+ from push_function_context and pop_function_context. */
+
+void
+rs6000_save_machine_status (p)
+ struct function *p;
+{
+ struct machine_function *machine =
+ (struct machine_function *) xmalloc (sizeof (struct machine_function));
+
+ p->machine = machine;
+ machine->sysv_varargs_p = rs6000_sysv_varargs_p;
+ machine->save_toc_p = rs6000_save_toc_p;
+ machine->fpmem_size = rs6000_fpmem_size;
+ machine->fpmem_offset = rs6000_fpmem_offset;
+}
+
+void
+rs6000_restore_machine_status (p)
+ struct function *p;
+{
+ struct machine_function *machine = p->machine;
+
+ rs6000_sysv_varargs_p = machine->sysv_varargs_p;
+ rs6000_save_toc_p = machine->save_toc_p;
+ rs6000_fpmem_size = machine->fpmem_size;
+ rs6000_fpmem_offset = machine->fpmem_offset;
+
+ free (machine);
+ p->machine = (struct machine_function *)0;
+}
+
+/* Do anything needed before RTL is emitted for each function. */
+
+void
+rs6000_init_expanders ()
+{
+ /* Reset varargs and save TOC indicator */
+ rs6000_sysv_varargs_p = 0;
+ rs6000_save_toc_p = 0;
+ rs6000_fpmem_size = 0;
+ rs6000_fpmem_offset = 0;
+ pic_offset_table_rtx = (rtx)0;
+
+ /* Arrange to save and restore machine status around nested functions. */
+ save_machine_status = rs6000_save_machine_status;
+ restore_machine_status = rs6000_restore_machine_status;
+}
+
\f
/* Print an operand. Recognize special options, documented below. */
+---------------------------------------+
| Parameter save area (P) | 24
+---------------------------------------+
- | Float/int conversion temporary (X) | 24+P
+ | Alloca space (A) | 24+P
+---------------------------------------+
- | Alloca space (A) | 24+P+X
+ | Local variable space (L) | 24+P+A
+---------------------------------------+
- | Local variable space (L) | 24+P+X+A
+ | Float/int conversion temporary (X) | 24+P+A+L
+---------------------------------------+
- | Save area for GP registers (G) | 24+P+X+A+L
+ | Save area for GP registers (G) | 24+P+A+X+L
+---------------------------------------+
- | Save area for FP registers (F) | 24+P+X+A+L+G
+ | Save area for FP registers (F) | 24+P+A+X+L+G
+---------------------------------------+
old SP->| back chain to caller's caller |
+---------------------------------------+
+---------------------------------------+
| Parameter save area (P) | 8
+---------------------------------------+
- | Float/int conversion temporary (X) | 8+P
- +---------------------------------------+
- | Alloca space (A) | 8+P+X
- +---------------------------------------+
- | Varargs save area (V) | 8+P+X+A
- +---------------------------------------+
- | Local variable space (L) | 8+P+X+A+V
+ | Alloca space (A) | 8+P
+ +---------------------------------------+
+ | Varargs save area (V) | 8+P+A
+ +---------------------------------------+
+ | Local variable space (L) | 8+P+A+V
+ +---------------------------------------+
+ | Float/int conversion temporary (X) | 8+P+A+V+L
+---------------------------------------+
- | saved CR (C) | 8+P+X+A+V+L
- +---------------------------------------+
- | Save area for GP registers (G) | 8+P+X+A+V+L+C
- +---------------------------------------+
- | Save area for FP registers (F) | 8+P+X+A+V+L+C+G
+ | saved CR (C) | 8+P+A+V+L+X
+ +---------------------------------------+
+ | Save area for GP registers (G) | 8+P+A+V+L+X+C
+ +---------------------------------------+
+ | Save area for FP registers (F) | 8+P+A+V+L+X+C+G
+---------------------------------------+
old SP->| back chain to caller's caller |
+---------------------------------------+
+---------------------------------------+
| Parameter save area (P) | 24
+---------------------------------------+
- | Float/int conversion temporary (X) | 24+P
- +---------------------------------------+
- | Alloca space (A) | 24+P+X
- +---------------------------------------+
- | Local variable space (L) | 24+P+X+A
- +---------------------------------------+
- | Save area for FP registers (F) | 24+P+X+A+L
- +---------------------------------------+
- | Possible alignment area (X) | 24+P+X+A+L+F
+ | Alloca space (A) | 24+P
+ +---------------------------------------+
+ | Local variable space (L) | 24+P+A
+ +---------------------------------------+
+ | Float/int conversion temporary (X) | 24+P+A+L
+---------------------------------------+
- | Save area for GP registers (G) | 24+P+X+A+L+F+X
- +---------------------------------------+
- | Save area for CR (C) | 24+P+X+A+L+F+X+G
- +---------------------------------------+
- | Save area for TOC (T) | 24+P+X+A+L+F+X+G+C
- +---------------------------------------+
- | Save area for LR (R) | 24+P+X+A+L+F+X+G+C+T
+ | Save area for FP registers (F) | 24+P+A+L+X
+ +---------------------------------------+
+ | Possible alignment area (Y) | 24+P+A+L+X+F
+ +---------------------------------------+
+ | Save area for GP registers (G) | 24+P+A+L+X+F+Y
+ +---------------------------------------+
+ | Save area for CR (C) | 24+P+A+L+X+F+Y+G
+ +---------------------------------------+
+ | Save area for TOC (T) | 24+P+A+L+X+F+Y+G+C
+ +---------------------------------------+
+ | Save area for LR (R) | 24+P+A+L+X+F+Y+G+C+T
+---------------------------------------+
old SP->| back chain to caller's caller |
+---------------------------------------+
|| info_ptr->total_size > 220);
/* Calculate the offsets */
- info_ptr->fpmem_offset = info_ptr->total_size - info_ptr->parm_size;
switch (abi)
{
case ABI_NONE:
case ABI_SOLARIS:
info_ptr->fp_save_offset = - info_ptr->fp_size;
info_ptr->gp_save_offset = info_ptr->fp_save_offset - info_ptr->gp_size;
- info_ptr->cr_save_offset = info_ptr->gp_save_offset - reg_size;
- info_ptr->toc_save_offset = info_ptr->cr_save_offset - info_ptr->cr_size;
- info_ptr->main_save_offset = info_ptr->toc_save_offset - info_ptr->toc_size;
+ info_ptr->cr_save_offset = info_ptr->gp_save_offset - info_ptr->cr_size;
+ info_ptr->toc_save_offset = info_ptr->cr_save_offset - info_ptr->toc_size;
+ info_ptr->main_save_offset = info_ptr->toc_save_offset - info_ptr->main_size;
info_ptr->lr_save_offset = reg_size;
break;
break;
}
+ if (info_ptr->fpmem_p)
+ info_ptr->fpmem_offset = STARTING_FRAME_OFFSET - info_ptr->total_size + info_ptr->vars_size;
+
/* Zero offsets if we're not saving those registers */
if (!info_ptr->fp_size)
info_ptr->fp_save_offset = 0;
else
{
rs6000_fpmem_size = info_ptr->fpmem_size;
- rs6000_fpmem_offset = STACK_DYNAMIC_OFFSET (current_function_decl) - info_ptr->fpmem_size;
- if (rs6000_fpmem_offset > 32767)
- abort ();
+ rs6000_fpmem_offset = info_ptr->total_size + info_ptr->fpmem_offset;
}
return info_ptr;
fputs ("\t.byte 31\n", file);
}
- /* Reset varargs and save TOC indicator */
- rs6000_sysv_varargs_p = 0;
- rs6000_save_toc_p = 0;
- rs6000_fpmem_size = 0;
- rs6000_fpmem_offset = 0;
- pic_offset_table_rtx = (rtx)0;
-
if (DEFAULT_ABI == ABI_NT)
{
RS6000_OUTPUT_BASENAME (file, XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0));
/* Align an address */
#define ALIGN(n,a) (((n) + (a) - 1) & ~((a) - 1))
+/* Initialize data used by insn expanders. This is called from
+ init_emit, once for each function, before code is generated. */
+#define INIT_EXPANDERS rs6000_init_expanders ()
+
/* Size of V.4 varargs area in bytes */
#define RS6000_VARARGS_SIZE \
((GP_ARG_NUM_REG * (TARGET_32BIT ? 4 : 8)) + (FP_ARG_NUM_REG * 8) + 8)
/* Offset of V.4 varargs area */
#define RS6000_VARARGS_OFFSET \
(ALIGN (current_function_outgoing_args_size, 8) \
- + ALIGN (rs6000_fpmem_size, 8) \
+ RS6000_SAVE_AREA)
/* Offset within stack frame to start allocating local variables at.
#define STARTING_FRAME_OFFSET \
(ALIGN (current_function_outgoing_args_size, 8) \
- + ALIGN (rs6000_fpmem_size, 8) \
+ RS6000_VARARGS_AREA \
+ RS6000_SAVE_AREA)
machines. See `function.c' for details. */
#define STACK_DYNAMIC_OFFSET(FUNDECL) \
(ALIGN (current_function_outgoing_args_size, 8) \
- + ALIGN (rs6000_fpmem_size, 8) \
+ (STACK_POINTER_OFFSET))
/* If we generate an insn to push BYTES bytes,
extern int flag_pic;
extern int optimize;
extern int flag_expensive_optimizations;
+extern int frame_pointer_needed;
/* Declare functions in rs6000.c */
extern void output_options ();
extern enum reg_class secondary_reload_class ();
extern int ccr_bit ();
extern void rs6000_finalize_pic ();
+extern void rs6000_save_machine_status ();
+extern void rs6000_restore_machine_status ();
+extern void rs6000_init_expanders ();
extern void print_operand ();
extern void print_operand_address ();
extern int first_reg_to_save ();
(use (match_dup 2))
(use (match_dup 3))
(clobber (match_dup 4))
+ (clobber (match_dup 5))
(clobber (reg:DF 76))])]
"! TARGET_POWERPC64 && TARGET_HARD_FLOAT"
"
operands[2] = force_reg (SImode, GEN_INT (0x43300000));
operands[3] = force_reg (DFmode, rs6000_float_const (\"4503601774854144\", DFmode));
operands[4] = gen_reg_rtx (SImode);
+ operands[5] = gen_reg_rtx (Pmode);
}")
(define_insn "*floatsidf2_internal"
(use (match_operand:SI 2 "gpc_reg_operand" "r"))
(use (match_operand:DF 3 "gpc_reg_operand" "f"))
(clobber (match_operand:SI 4 "gpc_reg_operand" "=r"))
+ (clobber (match_operand:SI 5 "gpc_reg_operand" "=b"))
(clobber (reg:DF 76))]
"! TARGET_POWERPC64 && TARGET_HARD_FLOAT"
"#"
- [(set_attr "length" "20")])
+ [(set_attr "length" "24")])
(define_split
[(set (match_operand:DF 0 "gpc_reg_operand" "")
(use (match_operand:SI 2 "gpc_reg_operand" ""))
(use (match_operand:DF 3 "gpc_reg_operand" ""))
(clobber (match_operand:SI 4 "gpc_reg_operand" ""))
+ (clobber (match_operand:SI 5 "gpc_reg_operand" ""))
(clobber (reg:DF 76))]
"! TARGET_POWERPC64 && TARGET_HARD_FLOAT"
[(set (match_dup 4)
(xor:SI (match_dup 1)
- (match_dup 5)))
- (set (match_dup 6)
- (unspec [(match_dup 4) ;; low word
- (reg:SI 1)] 11))
- (set (match_dup 6)
- (unspec [(match_dup 2) ;; high word
- (reg:SI 1)
- (match_dup 6)] 12))
+ (match_dup 6)))
+ (set (match_dup 5)
+ (unspec [(const_int 0)] 11))
+ (set (match_dup 7)
+ (unspec [(match_dup 4)
+ (match_dup 5)] 12)) ;; low word
+ (set (match_dup 7)
+ (unspec [(match_dup 2)
+ (match_dup 5)
+ (match_dup 7)] 13)) ;; high word
(set (match_dup 0)
- (unspec [(match_dup 6)
- (reg:SI 1)] 13))
+ (unspec [(match_dup 7)
+ (match_dup 5)] 14))
(set (match_dup 0)
(minus:DF (match_dup 0)
(match_dup 3)))]
"
{
- operands[5] = GEN_INT (0x80000000);
- operands[6] = gen_rtx (REG, DFmode, FPMEM_REGNUM);
+ operands[6] = GEN_INT (0x80000000);
+ operands[7] = gen_rtx (REG, DFmode, FPMEM_REGNUM);
}")
(define_expand "floatunssidf2"
(unsigned_float:DF (match_operand:SI 1 "gpc_reg_operand" "")))
(use (match_dup 2))
(use (match_dup 3))
+ (clobber (match_dup 4))
(clobber (reg:DF 76))])]
"! TARGET_POWERPC64 && TARGET_HARD_FLOAT"
"
{
operands[2] = force_reg (SImode, GEN_INT (0x43300000));
operands[3] = force_reg (DFmode, rs6000_float_const (\"4503599627370496\", DFmode));
+ operands[4] = gen_reg_rtx (Pmode);
}")
(define_insn "*floatunssidf2_internal"
(unsigned_float:DF (match_operand:SI 1 "gpc_reg_operand" "r")))
(use (match_operand:SI 2 "gpc_reg_operand" "r"))
(use (match_operand:DF 3 "gpc_reg_operand" "f"))
+ (clobber (match_operand:SI 4 "gpc_reg_operand" "=b"))
(clobber (reg:DF 76))]
"! TARGET_POWERPC64 && TARGET_HARD_FLOAT"
"#"
- [(set_attr "length" "16")])
+ [(set_attr "length" "20")])
(define_split
[(set (match_operand:DF 0 "gpc_reg_operand" "")
(unsigned_float:DF (match_operand:SI 1 "gpc_reg_operand" "")))
(use (match_operand:SI 2 "gpc_reg_operand" ""))
(use (match_operand:DF 3 "gpc_reg_operand" ""))
+ (clobber (match_operand:SI 4 "gpc_reg_operand" "=b"))
(clobber (reg:DF 76))]
"! TARGET_POWERPC64 && TARGET_HARD_FLOAT"
[(set (match_dup 4)
- (unspec [(match_dup 1) ;; low word
- (reg:SI 1)] 11))
- (set (match_dup 4)
- (unspec [(match_dup 2) ;; high word
- (reg:SI 1)
- (reg:DF 76)] 12))
+ (unspec [(const_int 0)] 11))
+ (set (match_dup 5)
+ (unspec [(match_dup 1)
+ (match_dup 4)] 12)) ;; low word
+ (set (match_dup 5)
+ (unspec [(match_dup 2)
+ (match_dup 4)
+ (match_dup 5)] 13)) ;; high word
(set (match_dup 0)
- (unspec [(match_dup 4)
- (reg:SI 1)] 13))
+ (unspec [(match_dup 5)
+ (reg:SI 1)] 14))
(set (match_dup 0)
(minus:DF (match_dup 0)
(match_dup 3)))]
- "operands[4] = gen_rtx (REG, DFmode, FPMEM_REGNUM);")
+ "operands[5] = gen_rtx (REG, DFmode, FPMEM_REGNUM);")
+
+;; Load up scratch register with base address + offset if needed
+(define_insn "*floatsidf2_loadaddr"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=b")
+ (unspec [(const_int 0)] 11))]
+ "TARGET_HARD_FLOAT"
+ "*
+{
+ if (rs6000_fpmem_offset > 32760)
+ {
+ rtx xop[3];
-;; Note, we list r1 in the unspec, so that the optimizer is not tempted to optimize
-;; around an alloca call (the memory address is constructed directly from r1).
+ xop[0] = operands[0];
+ xop[1] = (frame_pointer_needed) ? frame_pointer_rtx : stack_pointer_rtx;
+ xop[2] = GEN_INT ((rs6000_fpmem_offset >> 16) & 0xffff);
+ output_asm_insn (\"{cau %0,%2(%1)|addis %0,%1,%2}\", xop);
+ }
+ else if (rs6000_fpmem_offset < 0)
+ abort ();
+
+ return \"\";
+}"
+ [(set_attr "length" "4")])
(define_insn "*floatsidf2_store1"
[(set (reg:DF 76)
(unspec [(match_operand:SI 0 "gpc_reg_operand" "r")
- (reg:SI 1)] 11))]
+ (match_operand:SI 1 "gpc_reg_operand" "r")] 12))]
"! TARGET_POWERPC64 && TARGET_HARD_FLOAT"
"*
{
- operands[1] = gen_rtx (MEM, SImode,
+ rtx indx;
+
+ if (rs6000_fpmem_offset > 32760)
+ indx = operands[1];
+ else if (frame_pointer_needed)
+ indx = frame_pointer_rtx;
+ else
+ indx = stack_pointer_rtx;
+
+ operands[2] = gen_rtx (MEM, SImode,
gen_rtx (PLUS, Pmode,
- stack_pointer_rtx,
- GEN_INT (rs6000_fpmem_offset
+ indx,
+ GEN_INT ((rs6000_fpmem_offset & 0xffff)
+ ((WORDS_BIG_ENDIAN != 0) * 4))));
- return \"{st|stw} %0,%1\";
+ return \"{st|stw} %0,%2\";
}"
[(set_attr "type" "store")])
(define_insn "*floatsidf2_store2"
[(set (reg:DF 76)
(unspec [(match_operand:SI 0 "gpc_reg_operand" "r")
- (reg:SI 1)
- (reg:DF 76)] 12))]
+ (match_operand:SI 1 "gpc_reg_operand" "r")
+ (reg:DF 76)] 13))]
"! TARGET_POWERPC64 && TARGET_HARD_FLOAT"
"*
{
- operands[1] = gen_rtx (MEM, SImode,
+ rtx indx;
+
+ if (rs6000_fpmem_offset > 32760)
+ indx = operands[1];
+ else if (frame_pointer_needed)
+ indx = frame_pointer_rtx;
+ else
+ indx = stack_pointer_rtx;
+
+ operands[2] = gen_rtx (MEM, SImode,
gen_rtx (PLUS, Pmode,
- stack_pointer_rtx,
- GEN_INT (rs6000_fpmem_offset
+ indx,
+ GEN_INT ((rs6000_fpmem_offset & 0xffff)
+ ((WORDS_BIG_ENDIAN == 0) * 4))));
- return \"{st|stw} %0,%1\";
+ return \"{st|stw} %0,%2\";
}"
[(set_attr "type" "store")])
(define_insn "*floatsidf2_load"
[(set (match_operand:DF 0 "gpc_reg_operand" "=f")
(unspec [(reg:DF 76)
- (reg:SI 1)] 13))]
+ (match_operand:SI 1 "gpc_reg_operand" "b")] 14))]
"! TARGET_POWERPC64 && TARGET_HARD_FLOAT"
"*
{
- operands[1] = gen_rtx (MEM, SImode,
+ rtx indx;
+
+ if (rs6000_fpmem_offset > 32760)
+ indx = operands[1];
+ else if (frame_pointer_needed)
+ indx = frame_pointer_rtx;
+ else
+ indx = stack_pointer_rtx;
+
+ operands[2] = gen_rtx (MEM, SImode,
gen_rtx (PLUS, Pmode,
- stack_pointer_rtx,
+ indx,
GEN_INT (rs6000_fpmem_offset)));
- return \"lfd %0,%1\";
+ return \"lfd %0,%2\";
}"
[(set_attr "type" "fpload")])
[(parallel [(set (match_operand:SI 0 "gpc_reg_operand" "")
(fix:SI (match_operand:DF 1 "gpc_reg_operand" "")))
(clobber (match_dup 2))
- (clobber (match_dup 3))])]
+ (clobber (match_dup 3))
+ (clobber (match_dup 4))])]
"TARGET_HARD_FLOAT"
"
{
}
operands[2] = gen_reg_rtx (DImode);
- operands[3] = gen_rtx (REG, DImode, FPMEM_REGNUM);
+ operands[3] = gen_reg_rtx (Pmode);
+ operands[4] = gen_rtx (REG, DImode, FPMEM_REGNUM);
}")
(define_insn "*fix_truncdfsi2_internal"
[(set (match_operand:SI 0 "gpc_reg_operand" "=r")
(fix:SI (match_operand:DF 1 "gpc_reg_operand" "f")))
(clobber (match_operand:DI 2 "gpc_reg_operand" "=f"))
+ (clobber (match_operand:SI 3 "gpc_reg_operand" "=b"))
(clobber (reg:DI 76))]
"TARGET_HARD_FLOAT"
"#"
[(set (match_operand:SI 0 "gpc_reg_operand" "")
(fix:SI (match_operand:DF 1 "gpc_reg_operand" "f")))
(clobber (match_operand:DI 2 "gpc_reg_operand" ""))
+ (clobber (match_operand:SI 3 "gpc_reg_operand" ""))
(clobber (reg:DI 76))]
"TARGET_HARD_FLOAT"
[(set (match_dup 2)
(sign_extend:DI (fix:SI (match_operand:DF 1 "gpc_reg_operand" ""))))
(set (match_dup 3)
+ (unspec [(const_int 0)] 11))
+ (set (match_dup 4)
(unspec [(match_dup 2)
- (reg:SI 1)] 14))
+ (match_dup 3)] 15))
(set (match_operand:SI 0 "gpc_reg_operand" "")
- (unspec [(match_dup 3)
- (reg:SI 1)] 15))]
- "operands[3] = gen_rtx (REG, DImode, FPMEM_REGNUM);")
+ (unspec [(match_dup 4)
+ (match_dup 3)] 16))]
+ "operands[4] = gen_rtx (REG, DImode, FPMEM_REGNUM);")
(define_insn "*fctiwz"
[(set (match_operand:DI 0 "gpc_reg_operand" "=f")
(define_insn "*fix_truncdfsi2_store"
[(set (reg:DI 76)
(unspec [(match_operand:DI 0 "gpc_reg_operand" "f")
- (reg:SI 1)] 14))]
+ (match_operand:SI 1 "gpc_reg_operand" "b")] 15))]
"(TARGET_POWER2 || TARGET_POWERPC) && TARGET_HARD_FLOAT"
"*
{
- operands[1] = gen_rtx (MEM, DFmode,
+ rtx indx;
+
+ if (rs6000_fpmem_offset > 32760)
+ indx = operands[1];
+ else if (frame_pointer_needed)
+ indx = frame_pointer_rtx;
+ else
+ indx = stack_pointer_rtx;
+
+ operands[2] = gen_rtx (MEM, DFmode,
gen_rtx (PLUS, Pmode,
- stack_pointer_rtx,
- GEN_INT (rs6000_fpmem_offset)));
+ indx,
+ GEN_INT ((rs6000_fpmem_offset & 0xffff))));
- return \"stfd %0,%1\";
+ return \"stfd %0,%2\";
}"
[(set_attr "type" "fpstore")])
(define_insn "*fix_truncdfsi2_load"
[(set (match_operand:SI 0 "gpc_reg_operand" "=r")
(unspec [(reg:DI 76)
- (reg:SI 1)] 15))]
+ (match_operand:SI 1 "gpc_reg_operand" "b")] 16))]
"(TARGET_POWER2 || TARGET_POWERPC) && TARGET_HARD_FLOAT"
"*
{
- operands[1] = gen_rtx (MEM, DFmode,
+ rtx indx;
+
+ if (rs6000_fpmem_offset > 32760)
+ indx = operands[1];
+ else if (frame_pointer_needed)
+ indx = frame_pointer_rtx;
+ else
+ indx = stack_pointer_rtx;
+
+ operands[2] = gen_rtx (MEM, DFmode,
gen_rtx (PLUS, Pmode,
- stack_pointer_rtx,
- GEN_INT (rs6000_fpmem_offset + ((WORDS_BIG_ENDIAN) ? 4 : 0))));
+ indx,
+ GEN_INT ((rs6000_fpmem_offset & 0xffff)
+ + ((WORDS_BIG_ENDIAN) ? 4 : 0))));
- return \"{l|lwz} %0,%1\";
+ return \"{l|lwz} %0,%2\";
}"
[(set_attr "type" "load")])