aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/rs6000/rs6000.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/rs6000/rs6000.c')
-rw-r--r--gcc/config/rs6000/rs6000.c161
1 files changed, 113 insertions, 48 deletions
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 5c0ef2f6f30..3c17f2156f2 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -1,6 +1,6 @@
/* Subroutines used for code generation on IBM RS/6000.
Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- 2000, 2001, 2002 Free Software Foundation, Inc.
+ 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
This file is part of GNU CC.
@@ -284,7 +284,9 @@ char rs6000_reg_names[][8] =
"8", "9", "10", "11", "12", "13", "14", "15",
"16", "17", "18", "19", "20", "21", "22", "23",
"24", "25", "26", "27", "28", "29", "30", "31",
- "vrsave"
+ "vrsave", "vscr",
+ /* SPE registers. */
+ "spe_acc", "spefscr"
};
#ifdef TARGET_REGNAMES
@@ -301,12 +303,14 @@ static const char alt_reg_names[][8] =
"mq", "lr", "ctr", "ap",
"%cr0", "%cr1", "%cr2", "%cr3", "%cr4", "%cr5", "%cr6", "%cr7",
"xer",
- /* AltiVec registers. */
+ /* AltiVec registers. */
"%v0", "%v1", "%v2", "%v3", "%v4", "%v5", "%v6", "%v7",
- "%v8", "%v9", "%v10", "%v11", "%v12", "%v13", "%v14", "%v15",
- "%v16", "%v17", "%v18", "%v19", "%v20", "%v21", "%v22", "%v23",
- "%v24", "%v25", "%v26", "%v27", "%v28", "%v29", "%v30", "%v31",
- "vrsave"
+ "%v8", "%v9", "%v10", "%v11", "%v12", "%v13", "%v14", "%v15",
+ "%v16", "%v17", "%v18", "%v19", "%v20", "%v21", "%v22", "%v23",
+ "%v24", "%v25", "%v26", "%v27", "%v28", "%v29", "%v30", "%v31",
+ "vrsave", "vscr",
+ /* SPE registers. */
+ "spe_acc", "spefscr"
};
#endif
@@ -2636,16 +2640,15 @@ rs6000_emit_move (dest, source, mode)
}
}
- /* Handle the case where reload calls us with an invalid address;
- and the case of CONSTANT_P_RTX. */
- if (!ALTIVEC_VECTOR_MODE (mode)
+ /* Handle the case where reload calls us with an invalid address. */
+ if (reload_in_progress && mode == Pmode
&& (! general_operand (operands[1], mode)
- || ! nonimmediate_operand (operands[0], mode)
- || GET_CODE (operands[1]) == CONSTANT_P_RTX))
- {
- emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
- return;
- }
+ || ! nonimmediate_operand (operands[0], mode)))
+ goto emit_set;
+
+ /* Handle the case of CONSTANT_P_RTX. */
+ if (GET_CODE (operands[1]) == CONSTANT_P_RTX)
+ goto emit_set;
/* FIXME: In the long term, this switch statement should go away
and be replaced by a sequence of tests based on things like
@@ -2841,6 +2844,16 @@ rs6000_emit_move (dest, source, mode)
operands[1]
= replace_equiv_address (operands[1],
copy_addr_to_reg (XEXP (operands[1], 0)));
+ if (TARGET_POWER)
+ {
+ emit_insn (gen_rtx_PARALLEL (VOIDmode,
+ gen_rtvec (2,
+ gen_rtx_SET (VOIDmode,
+ operands[0], operands[1]),
+ gen_rtx_CLOBBER (VOIDmode,
+ gen_rtx_SCRATCH (SImode)))));
+ return;
+ }
break;
default:
@@ -2850,13 +2863,11 @@ rs6000_emit_move (dest, source, mode)
/* Above, we may have called force_const_mem which may have returned
an invalid address. If we can, fix this up; otherwise, reload will
have to deal with it. */
- if (GET_CODE (operands[1]) == MEM
- && ! memory_address_p (mode, XEXP (operands[1], 0))
- && ! reload_in_progress)
- operands[1] = adjust_address (operands[1], mode, 0);
+ if (GET_CODE (operands[1]) == MEM && ! reload_in_progress)
+ operands[1] = validize_mem (operands[1]);
+ emit_set:
emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
- return;
}
/* Initialize a variable CUM of type CUMULATIVE_ARGS
@@ -2867,11 +2878,12 @@ rs6000_emit_move (dest, source, mode)
so we never return a PARALLEL. */
void
-init_cumulative_args (cum, fntype, libname, incoming)
+init_cumulative_args (cum, fntype, libname, incoming, libcall)
CUMULATIVE_ARGS *cum;
tree fntype;
rtx libname ATTRIBUTE_UNUSED;
int incoming;
+ int libcall;
{
static CUMULATIVE_ARGS zero_cumulative;
@@ -2880,7 +2892,8 @@ init_cumulative_args (cum, fntype, libname, incoming)
cum->fregno = FP_ARG_MIN_REG;
cum->vregno = ALTIVEC_ARG_MIN_REG;
cum->prototype = (fntype && TYPE_ARG_TYPES (fntype));
- cum->call_cookie = CALL_NORMAL;
+ cum->call_cookie = ((DEFAULT_ABI == ABI_V4 && libcall)
+ ? CALL_LIBCALL : CALL_NORMAL);
cum->sysv_gregno = GP_ARG_MIN_REG;
if (incoming)
@@ -3088,7 +3101,7 @@ function_arg_advance (cum, mode, type, named)
If this is floating-point and no prototype is specified, we use
both an FP and integer register (or possibly FP reg and stack). Library
- functions (when TYPE is zero) always have the proper types for args,
+ functions (when CALL_LIBCALL is set) always have the proper types for args,
so we can pass the FP value just in one register. emit_library_function
doesn't support PARALLEL anyway. */
@@ -3109,7 +3122,8 @@ function_arg (cum, mode, type, named)
{
if (abi == ABI_V4
&& cum->nargs_prototype < 0
- && type && (cum->prototype || TARGET_NO_PROTOTYPE))
+ && (cum->call_cookie & CALL_LIBCALL) == 0
+ && (cum->prototype || TARGET_NO_PROTOTYPE))
{
/* For the SPE, we need to crxor CR6 always. */
if (TARGET_SPE_ABI)
@@ -3275,7 +3289,10 @@ function_arg_partial_nregs (cum, mode, type, named)
the argument itself. The pointer is passed in whatever way is
appropriate for passing a pointer to that type.
- Under V.4, structures and unions are passed by reference. */
+ Under V.4, structures and unions are passed by reference.
+
+ As an extension to all ABIs, variable sized types are passed by
+ reference. */
int
function_arg_pass_by_reference (cum, mode, type, named)
@@ -3293,8 +3310,7 @@ function_arg_pass_by_reference (cum, mode, type, named)
return 1;
}
-
- return 0;
+ return type && int_size_in_bytes (type) <= 0;
}
/* Perform any needed actions needed for a function that is receiving a
@@ -3533,7 +3549,28 @@ rs6000_va_arg (valist, type)
rtx lab_false, lab_over, addr_rtx, r;
if (DEFAULT_ABI != ABI_V4)
- return std_expand_builtin_va_arg (valist, type);
+ {
+ /* Variable sized types are passed by reference. */
+ if (int_size_in_bytes (type) <= 0)
+ {
+ u = build_pointer_type (type);
+
+ /* Args grow upward. */
+ t = build (POSTINCREMENT_EXPR, TREE_TYPE (valist), valist,
+ build_int_2 (POINTER_SIZE / BITS_PER_UNIT, 0));
+ TREE_SIDE_EFFECTS (t) = 1;
+
+ t = build1 (NOP_EXPR, build_pointer_type (u), t);
+ TREE_SIDE_EFFECTS (t) = 1;
+
+ t = build1 (INDIRECT_REF, u, t);
+ TREE_SIDE_EFFECTS (t) = 1;
+
+ return expand_expr (t, NULL_RTX, VOIDmode, EXPAND_NORMAL);
+ }
+ else
+ return std_expand_builtin_va_arg (valist, type);
+ }
f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
f_fpr = TREE_CHAIN (f_gpr);
@@ -8837,7 +8874,7 @@ first_reg_to_save ()
if (regs_ever_live[first_reg]
&& (! call_used_regs[first_reg]
|| (first_reg == RS6000_PIC_OFFSET_TABLE_REGNUM
- && ((DEFAULT_ABI == ABI_V4 && flag_pic == 1)
+ && ((DEFAULT_ABI == ABI_V4 && flag_pic != 0)
|| (DEFAULT_ABI == ABI_DARWIN && flag_pic)))))
break;
@@ -9265,7 +9302,6 @@ rs6000_stack_info ()
+ ehrd_size
+ info_ptr->cr_size
+ info_ptr->lr_size
- + info_ptr->vrsave_size
+ info_ptr->toc_size,
(TARGET_ALTIVEC_ABI || ABI_DARWIN)
? 16 : 8);
@@ -9609,7 +9645,7 @@ void
rs6000_emit_load_toc_table (fromprolog)
int fromprolog;
{
- rtx dest;
+ rtx dest, insn;
dest = gen_rtx_REG (Pmode, RS6000_PIC_OFFSET_TABLE_REGNUM);
if (TARGET_ELF && DEFAULT_ABI == ABI_V4 && flag_pic == 1)
@@ -9617,8 +9653,12 @@ rs6000_emit_load_toc_table (fromprolog)
rtx temp = (fromprolog
? gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM)
: gen_reg_rtx (Pmode));
- rs6000_maybe_dead (emit_insn (gen_load_toc_v4_pic_si (temp)));
- rs6000_maybe_dead (emit_move_insn (dest, temp));
+ insn = emit_insn (gen_load_toc_v4_pic_si (temp));
+ if (fromprolog)
+ rs6000_maybe_dead (insn);
+ insn = emit_move_insn (dest, temp);
+ if (fromprolog)
+ rs6000_maybe_dead (insn);
}
else if (TARGET_ELF && DEFAULT_ABI != ABI_AIX && flag_pic == 2)
{
@@ -9665,14 +9705,13 @@ rs6000_emit_load_toc_table (fromprolog)
ASM_GENERATE_INTERNAL_LABEL (buf, "LCG", reload_toc_labelno++);
symF = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
- rs6000_maybe_dead (emit_insn (gen_load_toc_v4_PIC_1b (tempLR,
- symF,
- tocsym)));
- rs6000_maybe_dead (emit_move_insn (dest, tempLR));
- rs6000_maybe_dead (emit_move_insn (temp0,
- gen_rtx_MEM (Pmode, dest)));
+ emit_insn (gen_load_toc_v4_PIC_1b (tempLR, symF, tocsym));
+ emit_move_insn (dest, tempLR);
+ emit_move_insn (temp0, gen_rtx_MEM (Pmode, dest));
}
- rs6000_maybe_dead (emit_insn (gen_addsi3 (dest, temp0, dest)));
+ insn = emit_insn (gen_addsi3 (dest, temp0, dest));
+ if (fromprolog)
+ rs6000_maybe_dead (insn);
}
else if (TARGET_ELF && !TARGET_AIX && flag_pic == 0 && TARGET_MINIMAL_TOC)
{
@@ -9682,15 +9721,21 @@ rs6000_emit_load_toc_table (fromprolog)
ASM_GENERATE_INTERNAL_LABEL (buf, "LCTOC", 1);
realsym = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
- rs6000_maybe_dead (emit_insn (gen_elf_high (dest, realsym)));
- rs6000_maybe_dead (emit_insn (gen_elf_low (dest, dest, realsym)));
+ insn = emit_insn (gen_elf_high (dest, realsym));
+ if (fromprolog)
+ rs6000_maybe_dead (insn);
+ insn = emit_insn (gen_elf_low (dest, dest, realsym));
+ if (fromprolog)
+ rs6000_maybe_dead (insn);
}
else if (DEFAULT_ABI == ABI_AIX)
{
if (TARGET_32BIT)
- rs6000_maybe_dead (emit_insn (gen_load_toc_aix_si (dest)));
+ insn = emit_insn (gen_load_toc_aix_si (dest));
else
- rs6000_maybe_dead (emit_insn (gen_load_toc_aix_di (dest)));
+ insn = emit_insn (gen_load_toc_aix_di (dest));
+ if (fromprolog)
+ rs6000_maybe_dead (insn);
}
else
abort ();
@@ -10423,7 +10468,7 @@ rs6000_emit_prologue ()
if ((regs_ever_live[info->first_gp_reg_save+i]
&& ! call_used_regs[info->first_gp_reg_save+i])
|| (i+info->first_gp_reg_save == RS6000_PIC_OFFSET_TABLE_REGNUM
- && ((DEFAULT_ABI == ABI_V4 && flag_pic == 1)
+ && ((DEFAULT_ABI == ABI_V4 && flag_pic != 0)
|| (DEFAULT_ABI == ABI_DARWIN && flag_pic))))
{
rtx addr, reg, mem;
@@ -10839,7 +10884,7 @@ rs6000_emit_epilogue (sibcall)
if ((regs_ever_live[info->first_gp_reg_save+i]
&& ! call_used_regs[info->first_gp_reg_save+i])
|| (i+info->first_gp_reg_save == RS6000_PIC_OFFSET_TABLE_REGNUM
- && ((DEFAULT_ABI == ABI_V4 && flag_pic == 1)
+ && ((DEFAULT_ABI == ABI_V4 && flag_pic != 0)
|| (DEFAULT_ABI == ABI_DARWIN && flag_pic))))
{
rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
@@ -11065,6 +11110,23 @@ rs6000_output_function_epilogue (file, size)
}
}
+#if TARGET_OBJECT_FORMAT == OBJECT_MACHO
+ /* Mach-O doesn't support labels at the end of objects, so if
+ it looks like we might want one, insert a NOP. */
+ {
+ rtx insn = get_last_insn ();
+ while (insn
+ && NOTE_P (insn)
+ && NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED_LABEL)
+ insn = PREV_INSN (insn);
+ if (insn
+ && (LABEL_P (insn)
+ || (NOTE_P (insn)
+ && NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED_LABEL)))
+ fputs ("\tnop\n", file);
+ }
+#endif
+
/* Output a traceback table here. See /usr/include/sys/debug.h for info
on its format.
@@ -12617,11 +12679,15 @@ rs6000_elf_encode_section_info (decl, first)
&& DEFAULT_ABI == ABI_V4
&& TREE_CODE (decl) == VAR_DECL)
{
+ rtx sym_ref = XEXP (DECL_RTL (decl), 0);
int size = int_size_in_bytes (TREE_TYPE (decl));
tree section_name = DECL_SECTION_NAME (decl);
const char *name = (char *)0;
int len = 0;
+ if ((*targetm.binds_local_p) (decl))
+ SYMBOL_REF_FLAG (sym_ref) = 1;
+
if (section_name)
{
if (TREE_CODE (section_name) == STRING_CST)
@@ -12648,7 +12714,6 @@ rs6000_elf_encode_section_info (decl, first)
|| (len == sizeof (".PPC.EMB.sbss0") - 1
&& strcmp (name, ".PPC.EMB.sbss0") == 0))))
{
- rtx sym_ref = XEXP (DECL_RTL (decl), 0);
size_t len = strlen (XSTR (sym_ref, 0));
char *str = alloca (len + 2);