summaryrefslogtreecommitdiffstats
path: root/contrib/gcc/config/rs6000/rs6000.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/gcc/config/rs6000/rs6000.c')
-rw-r--r--contrib/gcc/config/rs6000/rs6000.c781
1 files changed, 519 insertions, 262 deletions
diff --git a/contrib/gcc/config/rs6000/rs6000.c b/contrib/gcc/config/rs6000/rs6000.c
index 33f47ce..1ffd4da 100644
--- a/contrib/gcc/config/rs6000/rs6000.c
+++ b/contrib/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, 2003, 2004 Free Software Foundation, Inc.
+ 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
This file is part of GCC.
@@ -220,6 +220,20 @@ static GTY(()) tree opaque_V2SI_type_node;
static GTY(()) tree opaque_V2SF_type_node;
static GTY(()) tree opaque_p_V2SI_type_node;
+/* AltiVec requires a few more basic types in addition to the vector
+ types already defined in tree.c. */
+static GTY(()) tree bool_char_type_node; /* __bool char */
+static GTY(()) tree bool_short_type_node; /* __bool short */
+static GTY(()) tree bool_int_type_node; /* __bool int */
+static GTY(()) tree pixel_type_node; /* __pixel */
+static GTY(()) tree bool_V16QI_type_node; /* __vector __bool char */
+static GTY(()) tree bool_V8HI_type_node; /* __vector __bool short */
+static GTY(()) tree bool_V4SI_type_node; /* __vector __bool int */
+static GTY(()) tree pixel_V8HI_type_node; /* __vector __pixel */
+
+int rs6000_warn_altivec_long = 1; /* On by default. */
+const char *rs6000_warn_altivec_long_switch;
+
const char *rs6000_traceback_name;
static enum {
traceback_default = 0,
@@ -238,7 +252,8 @@ static GTY(()) int rs6000_sr_alias_set;
/* Call distance, overridden by -mlongcall and #pragma longcall(1).
The only place that looks at this is rs6000_set_default_type_attributes;
everywhere else should rely on the presence or absence of a longcall
- attribute on the function declaration. */
+ attribute on the function declaration. Exception: init_cumulative_args
+ looks at it too, for libcalls. */
int rs6000_default_long_calls;
const char *rs6000_longcall_switch;
@@ -290,6 +305,8 @@ static void rs6000_assemble_visibility (tree, int);
#endif
static int rs6000_ra_ever_killed (void);
static tree rs6000_handle_longcall_attribute (tree *, tree, tree, int, bool *);
+static tree rs6000_handle_altivec_attribute (tree *, tree, tree, int, bool *);
+static const char *rs6000_mangle_fundamental_type (tree);
extern const struct attribute_spec rs6000_attribute_table[];
static void rs6000_set_default_type_attributes (tree);
static void rs6000_output_function_prologue (FILE *, HOST_WIDE_INT);
@@ -303,6 +320,7 @@ static void rs6000_file_start (void);
static unsigned int rs6000_elf_section_type_flags (tree, const char *, int);
static void rs6000_elf_asm_out_constructor (rtx, int);
static void rs6000_elf_asm_out_destructor (rtx, int);
+static void rs6000_elf_end_indicate_exec_stack (void) ATTRIBUTE_UNUSED;
static void rs6000_elf_select_section (tree, int, unsigned HOST_WIDE_INT);
static void rs6000_elf_unique_section (tree, int);
static void rs6000_elf_select_rtx_section (enum machine_mode, rtx,
@@ -398,8 +416,7 @@ static int rs6000_get_some_local_dynamic_name_1 (rtx *, void *);
static rtx rs6000_complex_function_value (enum machine_mode);
static rtx rs6000_spe_function_arg (CUMULATIVE_ARGS *,
enum machine_mode, tree);
-static rtx rs6000_mixed_function_arg (CUMULATIVE_ARGS *,
- enum machine_mode, tree, int);
+static rtx rs6000_mixed_function_arg (enum machine_mode, tree, int);
static void rs6000_move_block_from_reg (int regno, rtx x, int nregs);
static void setup_incoming_varargs (CUMULATIVE_ARGS *,
enum machine_mode, tree,
@@ -565,6 +582,9 @@ static const char alt_reg_names[][8] =
#undef TARGET_EXPAND_BUILTIN
#define TARGET_EXPAND_BUILTIN rs6000_expand_builtin
+#undef TARGET_MANGLE_FUNDAMENTAL_TYPE
+#define TARGET_MANGLE_FUNDAMENTAL_TYPE rs6000_mangle_fundamental_type
+
#undef TARGET_INIT_LIBFUNCS
#define TARGET_INIT_LIBFUNCS rs6000_init_libfuncs
@@ -735,9 +755,8 @@ rs6000_override_options (const char *default_cpu)
set_masks &= ~MASK_ALTIVEC;
#endif
- /* Don't override these by the processor default if given explicitly. */
- set_masks &= ~(target_flags_explicit
- & (MASK_MULTIPLE | MASK_STRING | MASK_SOFT_FLOAT));
+ /* Don't override by the processor default if given explicitly. */
+ set_masks &= ~target_flags_explicit;
/* Identify the processor type. */
rs6000_select[0].string = default_cpu;
@@ -923,6 +942,17 @@ rs6000_override_options (const char *default_cpu)
rs6000_default_long_calls = (base[0] != 'n');
}
+ /* Handle -m(no-)warn-altivec-long similarly. */
+ if (rs6000_warn_altivec_long_switch)
+ {
+ const char *base = rs6000_warn_altivec_long_switch;
+ while (base[-1] != 'm') base--;
+
+ if (*rs6000_warn_altivec_long_switch != '\0')
+ error ("invalid option `%s'", base);
+ rs6000_warn_altivec_long = (base[0] != 'n');
+ }
+
/* Handle -mprioritize-restricted-insns option. */
rs6000_sched_restricted_insns_priority
= (rs6000_sched_groups ? 1 : 0);
@@ -2972,13 +3002,9 @@ rs6000_legitimize_tls_address (rtx addr, enum tls_model model)
rs6000_emit_move (got, gsym, Pmode);
else
{
- char buf[30];
- static int tls_got_labelno = 0;
- rtx tempLR, lab, tmp3, mem;
+ rtx tempLR, tmp3, mem;
rtx first, last;
- ASM_GENERATE_INTERNAL_LABEL (buf, "LTLS", tls_got_labelno++);
- lab = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
tempLR = gen_reg_rtx (Pmode);
tmp1 = gen_reg_rtx (Pmode);
tmp2 = gen_reg_rtx (Pmode);
@@ -2986,8 +3012,7 @@ rs6000_legitimize_tls_address (rtx addr, enum tls_model model)
mem = gen_rtx_MEM (Pmode, tmp1);
RTX_UNCHANGING_P (mem) = 1;
- first = emit_insn (gen_load_toc_v4_PIC_1b (tempLR, lab,
- gsym));
+ first = emit_insn (gen_load_toc_v4_PIC_1b (tempLR, gsym));
emit_move_insn (tmp1, tempLR);
emit_move_insn (tmp2, mem);
emit_insn (gen_addsi3 (tmp3, tmp1, tmp2));
@@ -3942,10 +3967,11 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
cum->nargs_prototype = n_named_args;
/* Check for a longcall attribute. */
- if (fntype
- && lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype))
- && !lookup_attribute ("shortcall", TYPE_ATTRIBUTES (fntype)))
- cum->call_cookie = CALL_LONG;
+ if ((!fntype && rs6000_default_long_calls)
+ || (fntype
+ && lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype))
+ && !lookup_attribute ("shortcall", TYPE_ATTRIBUTES (fntype))))
+ cum->call_cookie |= CALL_LONG;
if (TARGET_DEBUG_ARG)
{
@@ -4258,105 +4284,49 @@ rs6000_spe_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
/* Determine where to place an argument in 64-bit mode with 32-bit ABI. */
static rtx
-rs6000_mixed_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
- tree type, int align_words)
-{
- if (mode == DFmode)
- {
- /* -mpowerpc64 with 32bit ABI splits up a DFmode argument
- in vararg list into zero, one or two GPRs */
- if (align_words >= GP_ARG_NUM_REG)
- return gen_rtx_PARALLEL (DFmode,
- gen_rtvec (2,
- gen_rtx_EXPR_LIST (VOIDmode,
- NULL_RTX, const0_rtx),
- gen_rtx_EXPR_LIST (VOIDmode,
- gen_rtx_REG (mode,
- cum->fregno),
- const0_rtx)));
- else if (align_words + rs6000_arg_size (mode, type)
- > GP_ARG_NUM_REG)
- /* If this is partially on the stack, then we only
- include the portion actually in registers here. */
- return gen_rtx_PARALLEL (DFmode,
- gen_rtvec (2,
- gen_rtx_EXPR_LIST (VOIDmode,
- gen_rtx_REG (SImode,
- GP_ARG_MIN_REG
- + align_words),
- const0_rtx),
- gen_rtx_EXPR_LIST (VOIDmode,
- gen_rtx_REG (mode,
- cum->fregno),
- const0_rtx)));
-
- /* split a DFmode arg into two GPRs */
- return gen_rtx_PARALLEL (DFmode,
- gen_rtvec (3,
- gen_rtx_EXPR_LIST (VOIDmode,
- gen_rtx_REG (SImode,
- GP_ARG_MIN_REG
- + align_words),
- const0_rtx),
- gen_rtx_EXPR_LIST (VOIDmode,
- gen_rtx_REG (SImode,
- GP_ARG_MIN_REG
- + align_words + 1),
- GEN_INT (4)),
- gen_rtx_EXPR_LIST (VOIDmode,
- gen_rtx_REG (mode, cum->fregno),
- const0_rtx)));
- }
- /* -mpowerpc64 with 32bit ABI splits up a DImode argument into one
- or two GPRs */
- else if (mode == DImode)
+rs6000_mixed_function_arg (enum machine_mode mode, tree type, int align_words)
+{
+ int n_units;
+ int i, k;
+ rtx rvec[GP_ARG_NUM_REG + 1];
+
+ if (align_words >= GP_ARG_NUM_REG)
+ return NULL_RTX;
+
+ n_units = rs6000_arg_size (mode, type);
+
+ /* Optimize the simple case where the arg fits in one gpr, except in
+ the case of BLKmode due to assign_parms assuming that registers are
+ BITS_PER_WORD wide. */
+ if (n_units == 0
+ || (n_units == 1 && mode != BLKmode))
+ return gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
+
+ k = 0;
+ if (align_words + n_units > GP_ARG_NUM_REG)
+ /* Not all of the arg fits in gprs. Say that it goes in memory too,
+ using a magic NULL_RTX component.
+ FIXME: This is not strictly correct. Only some of the arg
+ belongs in memory, not all of it. However, there isn't any way
+ to do this currently, apart from building rtx descriptions for
+ the pieces of memory we want stored. Due to bugs in the generic
+ code we can't use the normal function_arg_partial_nregs scheme
+ with the PARALLEL arg description we emit here.
+ In any case, the code to store the whole arg to memory is often
+ more efficient than code to store pieces, and we know that space
+ is available in the right place for the whole arg. */
+ rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX, const0_rtx);
+
+ i = 0;
+ do
{
- if (align_words < GP_ARG_NUM_REG - 1)
- return gen_rtx_PARALLEL (DImode,
- gen_rtvec (2,
- gen_rtx_EXPR_LIST (VOIDmode,
- gen_rtx_REG (SImode,
- GP_ARG_MIN_REG
- + align_words),
- const0_rtx),
- gen_rtx_EXPR_LIST (VOIDmode,
- gen_rtx_REG (SImode,
- GP_ARG_MIN_REG
- + align_words + 1),
- GEN_INT (4))));
- else if (align_words == GP_ARG_NUM_REG - 1)
- return gen_rtx_PARALLEL (DImode,
- gen_rtvec (2,
- gen_rtx_EXPR_LIST (VOIDmode,
- NULL_RTX, const0_rtx),
- gen_rtx_EXPR_LIST (VOIDmode,
- gen_rtx_REG (SImode,
- GP_ARG_MIN_REG
- + align_words),
- const0_rtx)));
- }
- else if (mode == BLKmode && align_words <= (GP_ARG_NUM_REG - 1))
- {
- int k;
- int size = int_size_in_bytes (type);
- int no_units = ((size - 1) / 4) + 1;
- int max_no_words = GP_ARG_NUM_REG - align_words;
- int rtlvec_len = no_units < max_no_words ? no_units : max_no_words;
- rtx *rtlvec = (rtx *) alloca (rtlvec_len * sizeof (rtx));
-
- memset ((char *) rtlvec, 0, rtlvec_len * sizeof (rtx));
-
- for (k=0; k < rtlvec_len; k++)
- rtlvec[k] = gen_rtx_EXPR_LIST (VOIDmode,
- gen_rtx_REG (SImode,
- GP_ARG_MIN_REG
- + align_words + k),
- k == 0 ? const0_rtx : GEN_INT (k*4));
-
- return gen_rtx_PARALLEL (BLKmode, gen_rtvec_v (k, rtlvec));
- }
+ rtx r = gen_rtx_REG (SImode, GP_ARG_MIN_REG + align_words);
+ rtx off = GEN_INT (i++ * 4);
+ rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, off);
+ }
+ while (++align_words < GP_ARG_NUM_REG && --n_units != 0);
- return NULL_RTX;
+ return gen_rtx_PARALLEL (mode, gen_rtvec_v (k, rvec));
}
/* Determine where to put an argument to a function.
@@ -4451,8 +4421,8 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
{
/* Vector parameters to varargs functions under AIX or Darwin
get passed in memory and possibly also in GPRs. */
- int align, align_words;
- enum machine_mode part_mode = mode;
+ int align, align_words, n_words;
+ enum machine_mode part_mode;
/* Vector parameters must be 16-byte aligned. This places them at
2 mod 4 in terms of words in 32-bit mode, since the parameter
@@ -4468,15 +4438,19 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
/* Out of registers? Memory, then. */
if (align_words >= GP_ARG_NUM_REG)
return NULL_RTX;
-
+
+ if (TARGET_32BIT && TARGET_POWERPC64)
+ return rs6000_mixed_function_arg (mode, type, align_words);
+
/* The vector value goes in GPRs. Only the part of the
value in GPRs is reported here. */
- if (align_words + CLASS_MAX_NREGS (mode, GENERAL_REGS)
- > GP_ARG_NUM_REG)
+ part_mode = mode;
+ n_words = rs6000_arg_size (mode, type);
+ if (align_words + n_words > GP_ARG_NUM_REG)
/* Fortunately, there are only two possibilities, the value
is either wholly in GPRs or half in GPRs and half not. */
part_mode = DImode;
-
+
return gen_rtx_REG (part_mode, GP_ARG_MIN_REG + align_words);
}
}
@@ -4504,10 +4478,13 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
gregno += (1 - gregno) & 1;
/* Multi-reg args are not split between registers and stack. */
- if (gregno + n_words - 1 <= GP_ARG_MAX_REG)
- return gen_rtx_REG (mode, gregno);
- else
+ if (gregno + n_words - 1 > GP_ARG_MAX_REG)
return NULL_RTX;
+
+ if (TARGET_32BIT && TARGET_POWERPC64)
+ return rs6000_mixed_function_arg (mode, type,
+ gregno - GP_ARG_MIN_REG);
+ return gen_rtx_REG (mode, gregno);
}
}
else
@@ -4517,75 +4494,82 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
if (USE_FP_FOR_ARG_P (cum, mode, type))
{
- rtx fpr[2];
- rtx *r;
+ rtx rvec[GP_ARG_NUM_REG + 1];
+ rtx r;
+ int k;
bool needs_psave;
enum machine_mode fmode = mode;
- int n;
unsigned long n_fpreg = (GET_MODE_SIZE (mode) + 7) >> 3;
if (cum->fregno + n_fpreg > FP_ARG_MAX_REG + 1)
{
- /* Long double split over regs and memory. */
- if (fmode == TFmode)
- fmode = DFmode;
-
/* Currently, we only ever need one reg here because complex
doubles are split. */
- if (cum->fregno != FP_ARG_MAX_REG - 1)
+ if (cum->fregno != FP_ARG_MAX_REG || fmode != TFmode)
abort ();
+
+ /* Long double split over regs and memory. */
+ fmode = DFmode;
}
- fpr[1] = gen_rtx_REG (fmode, cum->fregno);
/* Do we also need to pass this arg in the parameter save
area? */
needs_psave = (type
&& (cum->nargs_prototype <= 0
|| (DEFAULT_ABI == ABI_AIX
- && TARGET_XL_CALL
+ && TARGET_XL_COMPAT
&& align_words >= GP_ARG_NUM_REG)));
if (!needs_psave && mode == fmode)
- return fpr[1];
-
- if (TARGET_32BIT && TARGET_POWERPC64
- && mode == DFmode && cum->stdarg)
- return rs6000_mixed_function_arg (cum, mode, type, align_words);
-
- /* Describe where this piece goes. */
- r = fpr + 1;
- *r = gen_rtx_EXPR_LIST (VOIDmode, *r, const0_rtx);
- n = 1;
+ return gen_rtx_REG (fmode, cum->fregno);
+ k = 0;
if (needs_psave)
{
- /* Now describe the part that goes in gprs or the stack.
+ /* Describe the part that goes in gprs or the stack.
This piece must come first, before the fprs. */
- rtx reg = NULL_RTX;
if (align_words < GP_ARG_NUM_REG)
{
unsigned long n_words = rs6000_arg_size (mode, type);
- enum machine_mode rmode = mode;
-
- if (align_words + n_words > GP_ARG_NUM_REG)
- /* If this is partially on the stack, then we only
- include the portion actually in registers here.
- We know this can only be one register because
- complex doubles are splt. */
- rmode = Pmode;
- reg = gen_rtx_REG (rmode, GP_ARG_MIN_REG + align_words);
+
+ if (align_words + n_words > GP_ARG_NUM_REG
+ || (TARGET_32BIT && TARGET_POWERPC64))
+ {
+ /* If this is partially on the stack, then we only
+ include the portion actually in registers here. */
+ enum machine_mode rmode = TARGET_32BIT ? SImode : DImode;
+ rtx off;
+ do
+ {
+ r = gen_rtx_REG (rmode,
+ GP_ARG_MIN_REG + align_words);
+ off = GEN_INT (k * GET_MODE_SIZE (rmode));
+ rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, off);
+ }
+ while (++align_words < GP_ARG_NUM_REG && --n_words != 0);
+ }
+ else
+ {
+ /* The whole arg fits in gprs. */
+ r = gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
+ rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, const0_rtx);
+ }
}
- *--r = gen_rtx_EXPR_LIST (VOIDmode, reg, const0_rtx);
- ++n;
+ else
+ /* It's entirely in memory. */
+ rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX, const0_rtx);
}
- return gen_rtx_PARALLEL (mode, gen_rtvec_v (n, r));
+ /* Describe where this piece goes in the fprs. */
+ r = gen_rtx_REG (fmode, cum->fregno);
+ rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, const0_rtx);
+
+ return gen_rtx_PARALLEL (mode, gen_rtvec_v (k, rvec));
}
else if (align_words < GP_ARG_NUM_REG)
{
- if (TARGET_32BIT && TARGET_POWERPC64
- && (mode == DImode || mode == BLKmode))
- return rs6000_mixed_function_arg (cum, mode, type, align_words);
+ if (TARGET_32BIT && TARGET_POWERPC64)
+ return rs6000_mixed_function_arg (mode, type, align_words);
return gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
}
@@ -4594,15 +4578,20 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
}
}
-/* For an arg passed partly in registers and partly in memory,
- this is the number of registers used.
- For args passed entirely in registers or entirely in memory, zero. */
+/* For an arg passed partly in registers and partly in memory, this is
+ the number of registers used. For args passed entirely in registers
+ or entirely in memory, zero. When an arg is described by a PARALLEL,
+ perhaps using more than one register type, this function returns the
+ number of registers used by the first element of the PARALLEL. */
int
function_arg_partial_nregs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
tree type, int named)
{
int ret = 0;
+ int align;
+ int parm_offset;
+ int align_words;
if (DEFAULT_ABI == ABI_V4)
return 0;
@@ -4611,17 +4600,29 @@ function_arg_partial_nregs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
&& cum->nargs_prototype >= 0)
return 0;
- if (USE_FP_FOR_ARG_P (cum, mode, type))
+ align = function_arg_boundary (mode, type) / PARM_BOUNDARY - 1;
+ parm_offset = TARGET_32BIT ? 2 : 0;
+ align_words = cum->words + ((parm_offset - cum->words) & align);
+
+ if (USE_FP_FOR_ARG_P (cum, mode, type)
+ /* If we are passing this arg in gprs as well, then this function
+ should return the number of gprs (or memory) partially passed,
+ *not* the number of fprs. */
+ && !(type
+ && (cum->nargs_prototype <= 0
+ || (DEFAULT_ABI == ABI_AIX
+ && TARGET_XL_COMPAT
+ && align_words >= GP_ARG_NUM_REG))))
{
if (cum->fregno + ((GET_MODE_SIZE (mode) + 7) >> 3) > FP_ARG_MAX_REG + 1)
- ret = FP_ARG_MAX_REG - cum->fregno;
+ ret = FP_ARG_MAX_REG + 1 - cum->fregno;
else if (cum->nargs_prototype >= 0)
return 0;
}
- if (cum->words < GP_ARG_NUM_REG
- && GP_ARG_NUM_REG < cum->words + rs6000_arg_size (mode, type))
- ret = GP_ARG_NUM_REG - cum->words;
+ if (align_words < GP_ARG_NUM_REG
+ && GP_ARG_NUM_REG < align_words + rs6000_arg_size (mode, type))
+ ret = GP_ARG_NUM_REG - align_words;
if (ret != 0 && TARGET_DEBUG_ARG)
fprintf (stderr, "function_arg_partial_nregs: %d\n", ret);
@@ -4776,6 +4777,7 @@ setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
{
mem = gen_rtx_MEM (DFmode, plus_constant (save_area, off));
set_mem_alias_set (mem, set);
+ set_mem_align (mem, GET_MODE_ALIGNMENT (DFmode));
emit_move_insn (mem, gen_rtx_REG (DFmode, fregno));
fregno++;
off += 8;
@@ -5695,6 +5697,7 @@ rs6000_expand_binop_builtin (enum insn_code icode, tree arglist, rtx target)
|| icode == CODE_FOR_spe_evsrwiu)
{
/* Only allow 5-bit unsigned literals. */
+ STRIP_NOPS (arg1);
if (TREE_CODE (arg1) != INTEGER_CST
|| TREE_INT_CST_LOW (arg1) & ~0x1f)
{
@@ -6120,6 +6123,8 @@ altivec_expand_dst_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
|| arg2 == error_mark_node)
return const0_rtx;
+ *expandedp = true;
+ STRIP_NOPS (arg2);
if (TREE_CODE (arg2) != INTEGER_CST
|| TREE_INT_CST_LOW (arg2) & ~0x3)
{
@@ -6136,7 +6141,6 @@ altivec_expand_dst_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
if (pat != 0)
emit_insn (pat);
- *expandedp = true;
return NULL_RTX;
}
@@ -6226,6 +6230,7 @@ altivec_expand_builtin (tree exp, rtx target, bool *expandedp)
case ALTIVEC_BUILTIN_DSS:
icode = CODE_FOR_altivec_dss;
arg0 = TREE_VALUE (arglist);
+ STRIP_NOPS (arg0);
op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
mode0 = insn_data[icode].operand[0].mode;
@@ -6245,6 +6250,15 @@ altivec_expand_builtin (tree exp, rtx target, bool *expandedp)
emit_insn (gen_altivec_dss (op0));
return NULL_RTX;
+
+ case ALTIVEC_BUILTIN_COMPILETIME_ERROR:
+ arg0 = TREE_VALUE (arglist);
+ while (TREE_CODE (arg0) == NOP_EXPR || TREE_CODE (arg0) == ADDR_EXPR)
+ arg0 = TREE_OPERAND (arg0, 0);
+ error ("invalid parameter combination for `%s' AltiVec intrinsic",
+ TREE_STRING_POINTER (arg0));
+
+ return const0_rtx;
}
/* Expand abs* operations. */
@@ -6684,6 +6698,73 @@ rs6000_init_builtins (void)
opaque_V2SF_type_node = copy_node (V2SF_type_node);
opaque_p_V2SI_type_node = build_pointer_type (opaque_V2SI_type_node);
+ /* The 'vector bool ...' types must be kept distinct from 'vector unsigned ...'
+ types, especially in C++ land. Similarly, 'vector pixel' is distinct from+ 'vector unsigned short'. */
+
+ bool_char_type_node = copy_node (unsigned_intQI_type_node);
+ TYPE_MAIN_VARIANT (bool_char_type_node) = bool_char_type_node;
+ bool_short_type_node = copy_node (unsigned_intHI_type_node);
+ TYPE_MAIN_VARIANT (bool_short_type_node) = bool_short_type_node;
+ bool_int_type_node = copy_node (unsigned_intSI_type_node);
+ TYPE_MAIN_VARIANT (bool_int_type_node) = bool_int_type_node;
+ pixel_type_node = copy_node (unsigned_intHI_type_node);
+ TYPE_MAIN_VARIANT (pixel_type_node) = pixel_type_node;
+
+ (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
+ get_identifier ("__bool char"),
+ bool_char_type_node));
+ (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
+ get_identifier ("__bool short"),
+ bool_short_type_node));
+ (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
+ get_identifier ("__bool int"),
+ bool_int_type_node));
+ (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
+ get_identifier ("__pixel"),
+ pixel_type_node));
+
+ bool_V16QI_type_node = make_vector (V16QImode, bool_char_type_node, 1);
+ bool_V8HI_type_node = make_vector (V8HImode, bool_short_type_node, 1);
+ bool_V4SI_type_node = make_vector (V4SImode, bool_int_type_node, 1);
+ pixel_V8HI_type_node = make_vector (V8HImode, pixel_type_node, 1);
+
+ (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
+ get_identifier ("__vector unsigned char"),
+ unsigned_V16QI_type_node));
+ (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
+ get_identifier ("__vector signed char"),
+ V16QI_type_node));
+ (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
+ get_identifier ("__vector __bool char"),
+ bool_V16QI_type_node));
+
+ (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
+ get_identifier ("__vector unsigned short"),
+ unsigned_V8HI_type_node));
+ (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
+ get_identifier ("__vector signed short"),
+ V8HI_type_node));
+ (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
+ get_identifier ("__vector __bool short"),
+ bool_V8HI_type_node));
+
+ (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
+ get_identifier ("__vector unsigned int"),
+ unsigned_V4SI_type_node));
+ (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
+ get_identifier ("__vector signed int"),
+ V4SI_type_node));
+ (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
+ get_identifier ("__vector __bool int"),
+ bool_V4SI_type_node));
+
+ (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
+ get_identifier ("__vector float"),
+ V4SF_type_node));
+ (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
+ get_identifier ("__vector __pixel"),
+ pixel_V8HI_type_node));
+
if (TARGET_SPE)
spe_init_builtins ();
if (TARGET_ALTIVEC)
@@ -6989,8 +7070,8 @@ altivec_init_builtins (void)
= build_function_type (V8HI_type_node, void_list_node);
tree void_ftype_void
= build_function_type (void_type_node, void_list_node);
- tree void_ftype_qi
- = build_function_type_list (void_type_node, char_type_node, NULL_TREE);
+ tree void_ftype_int
+ = build_function_type_list (void_type_node, integer_type_node, NULL_TREE);
tree v16qi_ftype_long_pcvoid
= build_function_type_list (V16QI_type_node,
@@ -7034,10 +7115,13 @@ altivec_init_builtins (void)
= build_function_type_list (V16QI_type_node, V16QI_type_node, NULL_TREE);
tree v4sf_ftype_v4sf
= build_function_type_list (V4SF_type_node, V4SF_type_node, NULL_TREE);
- tree void_ftype_pcvoid_int_char
+ tree void_ftype_pcvoid_int_int
= build_function_type_list (void_type_node,
pcvoid_type_node, integer_type_node,
- char_type_node, NULL_TREE);
+ integer_type_node, NULL_TREE);
+ tree int_ftype_pcchar
+ = build_function_type_list (integer_type_node,
+ pcchar_type_node, NULL_TREE);
def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_4sf", v4sf_ftype_pcfloat,
ALTIVEC_BUILTIN_LD_INTERNAL_4sf);
@@ -7058,7 +7142,7 @@ altivec_init_builtins (void)
def_builtin (MASK_ALTIVEC, "__builtin_altivec_mtvscr", void_ftype_v4si, ALTIVEC_BUILTIN_MTVSCR);
def_builtin (MASK_ALTIVEC, "__builtin_altivec_mfvscr", v8hi_ftype_void, ALTIVEC_BUILTIN_MFVSCR);
def_builtin (MASK_ALTIVEC, "__builtin_altivec_dssall", void_ftype_void, ALTIVEC_BUILTIN_DSSALL);
- def_builtin (MASK_ALTIVEC, "__builtin_altivec_dss", void_ftype_qi, ALTIVEC_BUILTIN_DSS);
+ def_builtin (MASK_ALTIVEC, "__builtin_altivec_dss", void_ftype_int, ALTIVEC_BUILTIN_DSS);
def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvsl", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVSL);
def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvsr", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVSR);
def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvebx", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVEBX);
@@ -7072,10 +7156,14 @@ altivec_init_builtins (void)
def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvebx", void_ftype_v16qi_long_pvoid, ALTIVEC_BUILTIN_STVEBX);
def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvehx", void_ftype_v8hi_long_pvoid, ALTIVEC_BUILTIN_STVEHX);
+ /* See altivec.h for usage of "__builtin_altivec_compiletime_error". */
+ def_builtin (MASK_ALTIVEC, "__builtin_altivec_compiletime_error", int_ftype_pcchar,
+ ALTIVEC_BUILTIN_COMPILETIME_ERROR);
+
/* Add the DST variants. */
d = (struct builtin_description *) bdesc_dst;
for (i = 0; i < ARRAY_SIZE (bdesc_dst); i++, d++)
- def_builtin (d->mask, d->name, void_ftype_pcvoid_int_char, d->code);
+ def_builtin (d->mask, d->name, void_ftype_pcvoid_int_int, d->code);
/* Initialize the predicates. */
dp = (struct builtin_description_predicates *) bdesc_altivec_preds;
@@ -7160,12 +7248,12 @@ rs6000_common_init_builtins (void)
= build_function_type_list (V16QI_type_node,
V16QI_type_node, V16QI_type_node,
V16QI_type_node, NULL_TREE);
- tree v4si_ftype_char
- = build_function_type_list (V4SI_type_node, char_type_node, NULL_TREE);
- tree v8hi_ftype_char
- = build_function_type_list (V8HI_type_node, char_type_node, NULL_TREE);
- tree v16qi_ftype_char
- = build_function_type_list (V16QI_type_node, char_type_node, NULL_TREE);
+ tree v4si_ftype_int
+ = build_function_type_list (V4SI_type_node, integer_type_node, NULL_TREE);
+ tree v8hi_ftype_int
+ = build_function_type_list (V8HI_type_node, integer_type_node, NULL_TREE);
+ tree v16qi_ftype_int
+ = build_function_type_list (V16QI_type_node, integer_type_node, NULL_TREE);
tree v8hi_ftype_v16qi
= build_function_type_list (V8HI_type_node, V16QI_type_node, NULL_TREE);
tree v4sf_ftype_v4sf
@@ -7223,37 +7311,37 @@ rs6000_common_init_builtins (void)
tree v4si_ftype_v4si_v4si
= build_function_type_list (V4SI_type_node,
V4SI_type_node, V4SI_type_node, NULL_TREE);
- tree v4sf_ftype_v4si_char
+ tree v4sf_ftype_v4si_int
= build_function_type_list (V4SF_type_node,
- V4SI_type_node, char_type_node, NULL_TREE);
- tree v4si_ftype_v4sf_char
+ V4SI_type_node, integer_type_node, NULL_TREE);
+ tree v4si_ftype_v4sf_int
= build_function_type_list (V4SI_type_node,
- V4SF_type_node, char_type_node, NULL_TREE);
- tree v4si_ftype_v4si_char
+ V4SF_type_node, integer_type_node, NULL_TREE);
+ tree v4si_ftype_v4si_int
= build_function_type_list (V4SI_type_node,
- V4SI_type_node, char_type_node, NULL_TREE);
- tree v8hi_ftype_v8hi_char
+ V4SI_type_node, integer_type_node, NULL_TREE);
+ tree v8hi_ftype_v8hi_int
= build_function_type_list (V8HI_type_node,
- V8HI_type_node, char_type_node, NULL_TREE);
- tree v16qi_ftype_v16qi_char
+ V8HI_type_node, integer_type_node, NULL_TREE);
+ tree v16qi_ftype_v16qi_int
= build_function_type_list (V16QI_type_node,
- V16QI_type_node, char_type_node, NULL_TREE);
- tree v16qi_ftype_v16qi_v16qi_char
+ V16QI_type_node, integer_type_node, NULL_TREE);
+ tree v16qi_ftype_v16qi_v16qi_int
= build_function_type_list (V16QI_type_node,
V16QI_type_node, V16QI_type_node,
- char_type_node, NULL_TREE);
- tree v8hi_ftype_v8hi_v8hi_char
+ integer_type_node, NULL_TREE);
+ tree v8hi_ftype_v8hi_v8hi_int
= build_function_type_list (V8HI_type_node,
V8HI_type_node, V8HI_type_node,
- char_type_node, NULL_TREE);
- tree v4si_ftype_v4si_v4si_char
+ integer_type_node, NULL_TREE);
+ tree v4si_ftype_v4si_v4si_int
= build_function_type_list (V4SI_type_node,
V4SI_type_node, V4SI_type_node,
- char_type_node, NULL_TREE);
- tree v4sf_ftype_v4sf_v4sf_char
+ integer_type_node, NULL_TREE);
+ tree v4sf_ftype_v4sf_v4sf_int
= build_function_type_list (V4SF_type_node,
V4SF_type_node, V4SF_type_node,
- char_type_node, NULL_TREE);
+ integer_type_node, NULL_TREE);
tree v4sf_ftype_v4sf_v4sf
= build_function_type_list (V4SF_type_node,
V4SF_type_node, V4SF_type_node, NULL_TREE);
@@ -7396,22 +7484,22 @@ rs6000_common_init_builtins (void)
/* vchar, vchar, vchar, 4 bit literal. */
else if (mode0 == V16QImode && mode1 == mode0 && mode2 == mode0
&& mode3 == QImode)
- type = v16qi_ftype_v16qi_v16qi_char;
+ type = v16qi_ftype_v16qi_v16qi_int;
/* vshort, vshort, vshort, 4 bit literal. */
else if (mode0 == V8HImode && mode1 == mode0 && mode2 == mode0
&& mode3 == QImode)
- type = v8hi_ftype_v8hi_v8hi_char;
+ type = v8hi_ftype_v8hi_v8hi_int;
/* vint, vint, vint, 4 bit literal. */
else if (mode0 == V4SImode && mode1 == mode0 && mode2 == mode0
&& mode3 == QImode)
- type = v4si_ftype_v4si_v4si_char;
+ type = v4si_ftype_v4si_v4si_int;
/* vfloat, vfloat, vfloat, 4 bit literal. */
else if (mode0 == V4SFmode && mode1 == mode0 && mode2 == mode0
&& mode3 == QImode)
- type = v4sf_ftype_v4sf_v4sf_char;
+ type = v4sf_ftype_v4sf_v4sf_int;
else
abort ();
@@ -7500,23 +7588,23 @@ rs6000_common_init_builtins (void)
/* vint, vint, 5 bit literal. */
else if (mode0 == V4SImode && mode1 == V4SImode && mode2 == QImode)
- type = v4si_ftype_v4si_char;
+ type = v4si_ftype_v4si_int;
/* vshort, vshort, 5 bit literal. */
else if (mode0 == V8HImode && mode1 == V8HImode && mode2 == QImode)
- type = v8hi_ftype_v8hi_char;
+ type = v8hi_ftype_v8hi_int;
/* vchar, vchar, 5 bit literal. */
else if (mode0 == V16QImode && mode1 == V16QImode && mode2 == QImode)
- type = v16qi_ftype_v16qi_char;
+ type = v16qi_ftype_v16qi_int;
/* vfloat, vint, 5 bit literal. */
else if (mode0 == V4SFmode && mode1 == V4SImode && mode2 == QImode)
- type = v4sf_ftype_v4si_char;
+ type = v4sf_ftype_v4si_int;
/* vint, vfloat, 5 bit literal. */
else if (mode0 == V4SImode && mode1 == V4SFmode && mode2 == QImode)
- type = v4si_ftype_v4sf_char;
+ type = v4si_ftype_v4sf_int;
else if (mode0 == V2SImode && mode1 == SImode && mode2 == SImode)
type = v2si_ftype_int_int;
@@ -7569,11 +7657,11 @@ rs6000_common_init_builtins (void)
mode1 = insn_data[d->icode].operand[1].mode;
if (mode0 == V4SImode && mode1 == QImode)
- type = v4si_ftype_char;
+ type = v4si_ftype_int;
else if (mode0 == V8HImode && mode1 == QImode)
- type = v8hi_ftype_char;
+ type = v8hi_ftype_int;
else if (mode0 == V16QImode && mode1 == QImode)
- type = v16qi_ftype_char;
+ type = v16qi_ftype_int;
else if (mode0 == V4SFmode && mode1 == V4SFmode)
type = v4sf_ftype_v4sf;
else if (mode0 == V8HImode && mode1 == V16QImode)
@@ -7614,11 +7702,21 @@ rs6000_init_libfuncs (void)
set_conv_libfunc (ufix_optab, SImode, TFmode, "_quitrunc");
}
- /* Standard AIX/Darwin/64-bit SVR4 quad floating point routines. */
- set_optab_libfunc (add_optab, TFmode, "_xlqadd");
- set_optab_libfunc (sub_optab, TFmode, "_xlqsub");
- set_optab_libfunc (smul_optab, TFmode, "_xlqmul");
- set_optab_libfunc (sdiv_optab, TFmode, "_xlqdiv");
+ /* AIX/Darwin/64-bit Linux quad floating point routines. */
+ if (!TARGET_XL_COMPAT)
+ {
+ set_optab_libfunc (add_optab, TFmode, "__gcc_qadd");
+ set_optab_libfunc (sub_optab, TFmode, "__gcc_qsub");
+ set_optab_libfunc (smul_optab, TFmode, "__gcc_qmul");
+ set_optab_libfunc (sdiv_optab, TFmode, "__gcc_qdiv");
+ }
+ else
+ {
+ set_optab_libfunc (add_optab, TFmode, "_xlqadd");
+ set_optab_libfunc (sub_optab, TFmode, "_xlqsub");
+ set_optab_libfunc (smul_optab, TFmode, "_xlqmul");
+ set_optab_libfunc (sdiv_optab, TFmode, "_xlqdiv");
+ }
}
else
{
@@ -8982,12 +9080,12 @@ print_operand (FILE *file, rtx x, int code)
return;
case 'D':
- /* Like 'J' but get to the GT bit. */
+ /* Like 'J' but get to the EQ bit. */
if (GET_CODE (x) != REG)
abort ();
- /* Bit 1 is GT bit. */
- i = 4 * (REGNO (x) - CR0_REGNO) + 1;
+ /* Bit 1 is EQ bit. */
+ i = 4 * (REGNO (x) - CR0_REGNO) + 2;
/* If we want bit 31, write a shift count of zero, not 32. */
fprintf (file, "%d", i == 31 ? 0 : i + 1);
@@ -9182,12 +9280,12 @@ print_operand (FILE *file, rtx x, int code)
case 'P':
/* The operand must be an indirect memory reference. The result
- is the register number. */
+ is the register name. */
if (GET_CODE (x) != MEM || GET_CODE (XEXP (x, 0)) != REG
|| REGNO (XEXP (x, 0)) >= 32)
output_operand_lossage ("invalid %%P value");
else
- fprintf (file, "%d", REGNO (XEXP (x, 0)));
+ fprintf (file, "%s", reg_names[REGNO (XEXP (x, 0))]);
return;
case 'q':
@@ -9659,7 +9757,7 @@ rs6000_assemble_integer (rtx x, unsigned int size, int aligned_p)
{
#ifdef RELOCATABLE_NEEDS_FIXUP
/* Special handling for SI values. */
- if (size == 4 && aligned_p)
+ if (RELOCATABLE_NEEDS_FIXUP && size == 4 && aligned_p)
{
extern int in_toc_section (void);
static int recurse = 0;
@@ -9858,10 +9956,34 @@ rs6000_generate_compare (enum rtx_code code)
emit_insn (cmp);
}
else
- emit_insn (gen_rtx_SET (VOIDmode, compare_result,
- gen_rtx_COMPARE (comp_mode,
- rs6000_compare_op0,
- rs6000_compare_op1)));
+ {
+ /* Generate XLC-compatible TFmode compare as PARALLEL with extra
+ CLOBBERs to match cmptf_internal2 pattern. */
+ if (comp_mode == CCFPmode && TARGET_XL_COMPAT
+ && GET_MODE (rs6000_compare_op0) == TFmode
+ && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_DARWIN)
+ && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128)
+ emit_insn (gen_rtx_PARALLEL (VOIDmode,
+ gen_rtvec (9,
+ gen_rtx_SET (VOIDmode,
+ compare_result,
+ gen_rtx_COMPARE (comp_mode,
+ rs6000_compare_op0,
+ rs6000_compare_op1)),
+ gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
+ gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
+ gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
+ gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
+ gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
+ gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
+ gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
+ gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)))));
+ else
+ emit_insn (gen_rtx_SET (VOIDmode, compare_result,
+ gen_rtx_COMPARE (comp_mode,
+ rs6000_compare_op0,
+ rs6000_compare_op1)));
+ }
/* Some kinds of FP comparisons need an OR operation;
under flag_finite_math_only we don't bother. */
@@ -9929,9 +10051,9 @@ rs6000_emit_sCOND (enum rtx_code code, rtx result)
abort ();
if (cond_code == NE)
- emit_insn (gen_e500_flip_gt_bit (t, t));
+ emit_insn (gen_e500_flip_eq_bit (t, t));
- emit_insn (gen_move_from_CR_gt_bit (result, t));
+ emit_insn (gen_move_from_CR_eq_bit (result, t));
return;
}
@@ -10112,9 +10234,9 @@ output_cbranch (rtx op, const char *label, int reversed, rtx insn)
return string;
}
-/* Return the string to flip the GT bit on a CR. */
+/* Return the string to flip the EQ bit on a CR. */
char *
-output_e500_flip_gt_bit (rtx dst, rtx src)
+output_e500_flip_eq_bit (rtx dst, rtx src)
{
static char string[64];
int a, b;
@@ -10123,9 +10245,9 @@ output_e500_flip_gt_bit (rtx dst, rtx src)
|| GET_CODE (src) != REG || ! CR_REGNO_P (REGNO (src)))
abort ();
- /* GT bit. */
- a = 4 * (REGNO (dst) - CR0_REGNO) + 1;
- b = 4 * (REGNO (src) - CR0_REGNO) + 1;
+ /* EQ bit. */
+ a = 4 * (REGNO (dst) - CR0_REGNO) + 2;
+ b = 4 * (REGNO (src) - CR0_REGNO) + 2;
sprintf (string, "crnot %d,%d", a, b);
return string;
@@ -10435,22 +10557,27 @@ rs6000_split_multireg_move (rtx dst, rtx src)
: gen_adddi3 (breg, breg, delta_rtx));
src = gen_rtx_MEM (mode, breg);
}
+ else if (! offsettable_memref_p (src))
+ {
+ rtx newsrc, basereg;
+ basereg = gen_rtx_REG (Pmode, reg);
+ emit_insn (gen_rtx_SET (VOIDmode, basereg, XEXP (src, 0)));
+ newsrc = gen_rtx_MEM (GET_MODE (src), basereg);
+ MEM_COPY_ATTRIBUTES (newsrc, src);
+ src = newsrc;
+ }
- /* We have now address involving an base register only.
- If we use one of the registers to address memory,
- we have change that register last. */
-
- breg = (GET_CODE (XEXP (src, 0)) == PLUS
- ? XEXP (XEXP (src, 0), 0)
- : XEXP (src, 0));
-
- if (!REG_P (breg))
- abort();
+ breg = XEXP (src, 0);
+ if (GET_CODE (breg) == PLUS || GET_CODE (breg) == LO_SUM)
+ breg = XEXP (breg, 0);
- if (REGNO (breg) >= REGNO (dst)
+ /* If the base register we are using to address memory is
+ also a destination reg, then change that register last. */
+ if (REG_P (breg)
+ && REGNO (breg) >= REGNO (dst)
&& REGNO (breg) < REGNO (dst) + nregs)
j = REGNO (breg) - REGNO (dst);
- }
+ }
if (GET_CODE (dst) == MEM && INT_REGNO_P (reg))
{
@@ -10482,6 +10609,8 @@ rs6000_split_multireg_move (rtx dst, rtx src)
: gen_adddi3 (breg, breg, delta_rtx));
dst = gen_rtx_MEM (mode, breg);
}
+ else if (! offsettable_memref_p (dst))
+ abort ();
}
for (i = 0; i < nregs; i++)
@@ -10491,7 +10620,7 @@ rs6000_split_multireg_move (rtx dst, rtx src)
if (j == nregs)
j = 0;
- /* If compiler already emited move of first word by
+ /* If compiler already emitted move of first word by
store with update, no need to do anything. */
if (j == 0 && used_update)
continue;
@@ -10523,7 +10652,8 @@ first_reg_to_save (void)
&& (! call_used_regs[first_reg]
|| (first_reg == RS6000_PIC_OFFSET_TABLE_REGNUM
&& ((DEFAULT_ABI == ABI_V4 && flag_pic != 0)
- || (DEFAULT_ABI == ABI_DARWIN && flag_pic)))))
+ || (DEFAULT_ABI == ABI_DARWIN && flag_pic)
+ || (TARGET_TOC && TARGET_MINIMAL_TOC)))))
break;
#if TARGET_MACHO
@@ -10719,6 +10849,7 @@ rs6000_stack_info (void)
rs6000_stack_t *info_ptr = &info;
int reg_size = TARGET_32BIT ? 4 : 8;
int ehrd_size;
+ int save_align;
HOST_WIDE_INT non_fixed_size;
/* Zero all fields portably. */
@@ -10936,6 +11067,7 @@ rs6000_stack_info (void)
break;
}
+ save_align = (TARGET_ALTIVEC_ABI || DEFAULT_ABI == ABI_DARWIN) ? 16 : 8;
info_ptr->save_size = RS6000_ALIGN (info_ptr->fp_size
+ info_ptr->gp_size
+ info_ptr->altivec_size
@@ -10947,8 +11079,7 @@ rs6000_stack_info (void)
+ info_ptr->lr_size
+ info_ptr->vrsave_size
+ info_ptr->toc_size,
- (TARGET_ALTIVEC_ABI || ABI_DARWIN)
- ? 16 : 8);
+ save_align);
non_fixed_size = (info_ptr->vars_size
+ info_ptr->parm_size
@@ -11342,7 +11473,6 @@ rs6000_emit_load_toc_table (int fromprolog)
rtx temp0 = (fromprolog
? gen_rtx_REG (Pmode, 0)
: gen_reg_rtx (Pmode));
- rtx symF;
/* possibly create the toc section */
if (! toc_initialized)
@@ -11353,7 +11483,7 @@ rs6000_emit_load_toc_table (int fromprolog)
if (fromprolog)
{
- rtx symL;
+ rtx symF, symL;
ASM_GENERATE_INTERNAL_LABEL (buf, "LCF", rs6000_pic_labelno);
symF = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
@@ -11371,14 +11501,9 @@ rs6000_emit_load_toc_table (int fromprolog)
else
{
rtx tocsym;
- static int reload_toc_labelno = 0;
tocsym = gen_rtx_SYMBOL_REF (Pmode, toc_label_name);
-
- ASM_GENERATE_INTERNAL_LABEL (buf, "LCG", reload_toc_labelno++);
- symF = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
-
- emit_insn (gen_load_toc_v4_PIC_1b (tempLR, symF, tocsym));
+ emit_insn (gen_load_toc_v4_PIC_1b (tempLR, tocsym));
emit_move_insn (dest, tempLR);
emit_move_insn (temp0, gen_rtx_MEM (Pmode, dest));
}
@@ -12007,8 +12132,10 @@ rs6000_emit_prologue (void)
rtx reg, mem, vrsave;
int offset;
- /* Get VRSAVE onto a GPR. */
- reg = gen_rtx_REG (SImode, 12);
+ /* Get VRSAVE onto a GPR. Note that ABI_V4 might be using r12
+ as frame_reg_rtx and r11 as the static chain pointer for
+ nested functions. */
+ reg = gen_rtx_REG (SImode, 0);
vrsave = gen_rtx_REG (SImode, VRSAVE_REGNO);
if (TARGET_MACHO)
emit_insn (gen_get_vrsave_internal (reg));
@@ -12117,7 +12244,10 @@ rs6000_emit_prologue (void)
int i;
for (i = 0; i < 32 - info->first_gp_reg_save; i++)
if ((regs_ever_live[info->first_gp_reg_save+i]
- && ! call_used_regs[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
+ && TARGET_TOC && TARGET_MINIMAL_TOC)))
|| (i+info->first_gp_reg_save == RS6000_PIC_OFFSET_TABLE_REGNUM
&& ((DEFAULT_ABI == ABI_V4 && flag_pic != 0)
|| (DEFAULT_ABI == ABI_DARWIN && flag_pic))))
@@ -12566,7 +12696,9 @@ rs6000_emit_epilogue (int sibcall)
else
for (i = 0; i < 32 - info->first_gp_reg_save; i++)
if ((regs_ever_live[info->first_gp_reg_save+i]
- && ! call_used_regs[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
+ && TARGET_TOC && TARGET_MINIMAL_TOC)))
|| (i+info->first_gp_reg_save == RS6000_PIC_OFFSET_TABLE_REGNUM
&& ((DEFAULT_ABI == ABI_V4 && flag_pic != 0)
|| (DEFAULT_ABI == ABI_DARWIN && flag_pic))))
@@ -14845,11 +14977,117 @@ rs6000_initialize_trampoline (rtx addr, rtx fnaddr, rtx cxt)
const struct attribute_spec rs6000_attribute_table[] =
{
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+ { "altivec", 1, 1, false, true, false, rs6000_handle_altivec_attribute },
{ "longcall", 0, 0, false, true, true, rs6000_handle_longcall_attribute },
{ "shortcall", 0, 0, false, true, true, rs6000_handle_longcall_attribute },
{ NULL, 0, 0, false, false, false, NULL }
};
+/* Handle the "altivec" attribute. The attribute may have
+ arguments as follows:
+
+ __attribute__((altivec(vector__)))
+ __attribute__((altivec(pixel__))) (always followed by 'unsigned short')
+ __attribute__((altivec(bool__))) (always followed by 'unsigned')
+
+ and may appear more than once (e.g., 'vector bool char') in a
+ given declaration. */
+
+static tree
+rs6000_handle_altivec_attribute (tree *node, tree name, tree args,
+ int flags ATTRIBUTE_UNUSED,
+ bool *no_add_attrs)
+{
+ tree type = *node, result = NULL_TREE;
+ enum machine_mode mode;
+ int unsigned_p;
+ char altivec_type
+ = ((args && TREE_CODE (args) == TREE_LIST && TREE_VALUE (args)
+ && TREE_CODE (TREE_VALUE (args)) == IDENTIFIER_NODE)
+ ? *IDENTIFIER_POINTER (TREE_VALUE (args))
+ : '?');
+
+ while (POINTER_TYPE_P (type)
+ || TREE_CODE (type) == FUNCTION_TYPE
+ || TREE_CODE (type) == METHOD_TYPE
+ || TREE_CODE (type) == ARRAY_TYPE)
+ type = TREE_TYPE (type);
+
+ mode = TYPE_MODE (type);
+
+ if (rs6000_warn_altivec_long
+ && (type == long_unsigned_type_node || type == long_integer_type_node))
+ warning ("use of 'long' in AltiVec types is deprecated; use 'int'");
+
+ switch (altivec_type)
+ {
+ case 'v':
+ unsigned_p = TREE_UNSIGNED (type);
+ switch (mode)
+ {
+ case SImode:
+ result = (unsigned_p ? unsigned_V4SI_type_node : V4SI_type_node);
+ break;
+ case HImode:
+ result = (unsigned_p ? unsigned_V8HI_type_node : V8HI_type_node);
+ break;
+ case QImode:
+ result = (unsigned_p ? unsigned_V16QI_type_node : V16QI_type_node);
+ break;
+ case SFmode: result = V4SF_type_node; break;
+ /* If the user says 'vector int bool', we may be handed the 'bool'
+ attribute _before_ the 'vector' attribute, and so select the proper
+ type in the 'b' case below. */
+ case V4SImode: case V8HImode: case V16QImode: result = type;
+ default: break;
+ }
+ break;
+ case 'b':
+ switch (mode)
+ {
+ case SImode: case V4SImode: result = bool_V4SI_type_node; break;
+ case HImode: case V8HImode: result = bool_V8HI_type_node; break;
+ case QImode: case V16QImode: result = bool_V16QI_type_node;
+ default: break;
+ }
+ break;
+ case 'p':
+ switch (mode)
+ {
+ case V8HImode: result = pixel_V8HI_type_node;
+ default: break;
+ }
+ default: break;
+ }
+
+ if (result && result != type && TYPE_READONLY (type))
+ result = build_qualified_type (result, TYPE_QUAL_CONST);
+
+ *no_add_attrs = true; /* No need to hang on to the attribute. */
+
+ if (!result)
+ warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ else
+ *node = reconstruct_complex_type (*node, result);
+
+ return NULL_TREE;
+}
+
+/* AltiVec defines four built-in scalar types that serve as vector
+ elements; we must teach the compiler how to mangle them. */
+
+static const char *
+rs6000_mangle_fundamental_type (tree type)
+{
+ if (type == bool_char_type_node) return "U6__boolc";
+ if (type == bool_short_type_node) return "U6__bools";
+ if (type == pixel_type_node) return "u7__pixel";
+ if (type == bool_int_type_node) return "U6__booli";
+
+ /* For all other types, use normal C++ mangling. */
+ return NULL;
+}
+
/* Handle a "longcall" or "shortcall" attribute; arguments as in
struct attribute_spec.handler. */
@@ -14998,6 +15236,18 @@ rs6000_elf_in_small_data_p (tree decl)
if (rs6000_sdata == SDATA_NONE)
return false;
+ /* We want to merge strings, so we never consider them small data. */
+ if (TREE_CODE (decl) == STRING_CST)
+ return false;
+
+ /* Functions are never in the small data area. */
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ return false;
+
+ /* Thread-local vars can't go in the small data area. */
+ if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl))
+ return false;
+
if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl))
{
const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
@@ -15539,6 +15789,13 @@ rs6000_elf_declare_function_name (FILE *file, const char *name, tree decl)
}
ASM_OUTPUT_LABEL (file, name);
}
+
+static void
+rs6000_elf_end_indicate_exec_stack (void)
+{
+ if (TARGET_32BIT)
+ file_end_indicate_exec_stack ();
+}
#endif
#if TARGET_XCOFF
OpenPOWER on IntegriCloud