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.c4684
1 files changed, 3283 insertions, 1401 deletions
diff --git a/contrib/gcc/config/rs6000/rs6000.c b/contrib/gcc/config/rs6000/rs6000.c
index 89808cc..591f77d 100644
--- a/contrib/gcc/config/rs6000/rs6000.c
+++ b/contrib/gcc/config/rs6000/rs6000.c
@@ -74,7 +74,25 @@ int rs6000_long_double_type_size;
/* Whether -mabi=altivec has appeared */
int rs6000_altivec_abi;
-/* Set to non-zero once AIX common-mode calls have been defined. */
+/* Whether VRSAVE instructions should be generated. */
+int rs6000_altivec_vrsave;
+
+/* String from -mvrsave= option. */
+const char *rs6000_altivec_vrsave_string;
+
+/* Nonzero if we want SPE ABI extensions. */
+int rs6000_spe_abi;
+
+/* Whether isel instructions should be generated. */
+int rs6000_isel;
+
+/* Nonzero if we have FPRs. */
+int rs6000_fprs = 1;
+
+/* String from -misel=. */
+const char *rs6000_isel_string;
+
+/* Set to nonzero once AIX common-mode calls have been defined. */
static int common_mode_defined;
/* Private copy of original value of flag_pic for ABI_AIX. */
@@ -114,6 +132,14 @@ const char *rs6000_debug_name;
int rs6000_debug_stack; /* debug stack applications */
int rs6000_debug_arg; /* debug argument handling */
+const char *rs6000_traceback_name;
+static enum {
+ traceback_default = 0,
+ traceback_none,
+ traceback_part,
+ traceback_full
+} rs6000_traceback;
+
/* Flag to say the TOC is initialized */
int toc_initialized;
char toc_label_name[10];
@@ -121,6 +147,24 @@ char toc_label_name[10];
/* Alias set for saves and restores from the rs6000 stack. */
static 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. */
+int rs6000_default_long_calls;
+const char *rs6000_longcall_switch;
+
+struct builtin_description
+{
+ /* mask is not const because we're going to alter it below. This
+ nonsense will go away when we rewrite the -march infrastructure
+ to give us more target flag bits. */
+ unsigned int mask;
+ const enum insn_code icode;
+ const char *const name;
+ const enum rs6000_builtins code;
+};
+
static void rs6000_add_gc_roots PARAMS ((void));
static int num_insns_constant_wide PARAMS ((HOST_WIDE_INT));
static void validate_condition_mode
@@ -129,6 +173,9 @@ static rtx rs6000_generate_compare PARAMS ((enum rtx_code));
static void rs6000_maybe_dead PARAMS ((rtx));
static void rs6000_emit_stack_tie PARAMS ((void));
static void rs6000_frame_related PARAMS ((rtx, rtx, HOST_WIDE_INT, rtx, rtx));
+static void emit_frame_save PARAMS ((rtx, rtx, enum machine_mode,
+ unsigned int, int, int));
+static rtx gen_frame_mem_offset PARAMS ((enum machine_mode, rtx, int));
static void rs6000_emit_allocate_stack PARAMS ((HOST_WIDE_INT, int));
static unsigned rs6000_hash_constant PARAMS ((rtx));
static unsigned toc_hash_function PARAMS ((const void *));
@@ -136,14 +183,19 @@ static int toc_hash_eq PARAMS ((const void *, const void *));
static int toc_hash_mark_entry PARAMS ((void **, void *));
static void toc_hash_mark_table PARAMS ((void *));
static int constant_pool_expr_1 PARAMS ((rtx, int *, int *));
-static void rs6000_free_machine_status PARAMS ((struct function *));
-static void rs6000_init_machine_status PARAMS ((struct function *));
+static struct machine_function * rs6000_init_machine_status PARAMS ((void));
static bool rs6000_assemble_integer PARAMS ((rtx, unsigned int, int));
+#ifdef HAVE_GAS_HIDDEN
+static void rs6000_assemble_visibility PARAMS ((tree, int));
+#endif
static int rs6000_ra_ever_killed PARAMS ((void));
static tree rs6000_handle_longcall_attribute PARAMS ((tree *, tree, tree, int, bool *));
const struct attribute_spec rs6000_attribute_table[];
+static void rs6000_set_default_type_attributes PARAMS ((tree));
static void rs6000_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
static void rs6000_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
+static void rs6000_output_mi_thunk PARAMS ((FILE *, tree, HOST_WIDE_INT,
+ HOST_WIDE_INT, tree));
static rtx rs6000_emit_set_long_const PARAMS ((rtx,
HOST_WIDE_INT, HOST_WIDE_INT));
#if TARGET_ELF
@@ -151,30 +203,64 @@ static unsigned int rs6000_elf_section_type_flags PARAMS ((tree, const char *,
int));
static void rs6000_elf_asm_out_constructor PARAMS ((rtx, int));
static void rs6000_elf_asm_out_destructor PARAMS ((rtx, int));
+static void rs6000_elf_select_section PARAMS ((tree, int,
+ unsigned HOST_WIDE_INT));
+static void rs6000_elf_unique_section PARAMS ((tree, int));
+static void rs6000_elf_select_rtx_section PARAMS ((enum machine_mode, rtx,
+ unsigned HOST_WIDE_INT));
+static void rs6000_elf_encode_section_info PARAMS ((tree, int))
+ ATTRIBUTE_UNUSED;
+static const char *rs6000_elf_strip_name_encoding PARAMS ((const char *));
+static bool rs6000_elf_in_small_data_p PARAMS ((tree));
#endif
-#ifdef OBJECT_FORMAT_COFF
-static void xcoff_asm_named_section PARAMS ((const char *, unsigned int));
+#if TARGET_XCOFF
+static void rs6000_xcoff_asm_globalize_label PARAMS ((FILE *, const char *));
+static void rs6000_xcoff_asm_named_section PARAMS ((const char *, unsigned int));
+static void rs6000_xcoff_select_section PARAMS ((tree, int,
+ unsigned HOST_WIDE_INT));
+static void rs6000_xcoff_unique_section PARAMS ((tree, int));
+static void rs6000_xcoff_select_rtx_section PARAMS ((enum machine_mode, rtx,
+ unsigned HOST_WIDE_INT));
+static const char * rs6000_xcoff_strip_name_encoding PARAMS ((const char *));
+static unsigned int rs6000_xcoff_section_type_flags PARAMS ((tree, const char *, int));
#endif
+static void rs6000_xcoff_encode_section_info PARAMS ((tree, int))
+ ATTRIBUTE_UNUSED;
static bool rs6000_binds_local_p PARAMS ((tree));
static int rs6000_adjust_cost PARAMS ((rtx, rtx, rtx, int));
static int rs6000_adjust_priority PARAMS ((rtx, int));
static int rs6000_issue_rate PARAMS ((void));
static void rs6000_init_builtins PARAMS ((void));
-static void altivec_init_builtins PARAMS ((void));
+static rtx rs6000_expand_unop_builtin PARAMS ((enum insn_code, tree, rtx));
+static rtx rs6000_expand_binop_builtin PARAMS ((enum insn_code, tree, rtx));
+static rtx rs6000_expand_ternop_builtin PARAMS ((enum insn_code, tree, rtx));
static rtx rs6000_expand_builtin PARAMS ((tree, rtx, rtx, enum machine_mode, int));
-static rtx altivec_expand_builtin PARAMS ((tree, rtx));
-static rtx altivec_expand_unop_builtin PARAMS ((enum insn_code, tree, rtx));
-static rtx altivec_expand_binop_builtin PARAMS ((enum insn_code, tree, rtx));
+static void altivec_init_builtins PARAMS ((void));
+static void rs6000_common_init_builtins PARAMS ((void));
+
+static void enable_mask_for_builtins PARAMS ((struct builtin_description *,
+ int, enum rs6000_builtins,
+ enum rs6000_builtins));
+static void spe_init_builtins PARAMS ((void));
+static rtx spe_expand_builtin PARAMS ((tree, rtx, bool *));
+static rtx spe_expand_predicate_builtin PARAMS ((enum insn_code, tree, rtx));
+static rtx spe_expand_evsel_builtin PARAMS ((enum insn_code, tree, rtx));
+static int rs6000_emit_int_cmove PARAMS ((rtx, rtx, rtx, rtx));
+
+static rtx altivec_expand_builtin PARAMS ((tree, rtx, bool *));
+static rtx altivec_expand_ld_builtin PARAMS ((tree, rtx, bool *));
+static rtx altivec_expand_st_builtin PARAMS ((tree, rtx, bool *));
+static rtx altivec_expand_dst_builtin PARAMS ((tree, rtx, bool *));
static rtx altivec_expand_abs_builtin PARAMS ((enum insn_code, tree, rtx));
static rtx altivec_expand_predicate_builtin PARAMS ((enum insn_code, const char *, tree, rtx));
-static rtx altivec_expand_ternop_builtin PARAMS ((enum insn_code, tree, rtx));
static rtx altivec_expand_stv_builtin PARAMS ((enum insn_code, tree));
static void rs6000_parse_abi_options PARAMS ((void));
+static void rs6000_parse_vrsave_option PARAMS ((void));
+static void rs6000_parse_isel_option PARAMS ((void));
static int first_altivec_reg_to_save PARAMS ((void));
static unsigned int compute_vrsave_mask PARAMS ((void));
static void is_altivec_return_reg PARAMS ((rtx, void *));
-int vrsave_operation PARAMS ((rtx, enum machine_mode));
static rtx generate_set_vrsave PARAMS ((rtx, rs6000_stack_t *, int));
static void altivec_frame_fixup PARAMS ((rtx, rtx, HOST_WIDE_INT));
static int easy_vector_constant PARAMS ((rtx));
@@ -198,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
@@ -215,22 +303,29 @@ 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
#ifndef MASK_STRICT_ALIGN
#define MASK_STRICT_ALIGN 0
#endif
+
+/* The VRSAVE bitmask puts bit %v0 as the most significant bit. */
+#define ALTIVEC_REG_BIT(REGNO) (0x80000000 >> ((REGNO) - FIRST_ALTIVEC_REGNO))
/* Initialize the GCC target structure. */
#undef TARGET_ATTRIBUTE_TABLE
#define TARGET_ATTRIBUTE_TABLE rs6000_attribute_table
+#undef TARGET_SET_DEFAULT_TYPE_ATTRIBUTES
+#define TARGET_SET_DEFAULT_TYPE_ATTRIBUTES rs6000_set_default_type_attributes
#undef TARGET_ASM_ALIGNED_DI_OP
#define TARGET_ASM_ALIGNED_DI_OP DOUBLE_INT_ASM_OP
@@ -238,7 +333,7 @@ static const char alt_reg_names[][8] =
/* Default unaligned ops are only provided for ELF. Find the ops needed
for non-ELF systems. */
#ifndef OBJECT_FORMAT_ELF
-#ifdef OBJECT_FORMAT_COFF
+#if TARGET_XCOFF
/* For XCOFF. rs6000_assemble_integer will handle unaligned DIs on
64-bit targets. */
#undef TARGET_ASM_UNALIGNED_HI_OP
@@ -261,16 +356,16 @@ static const char alt_reg_names[][8] =
#undef TARGET_ASM_INTEGER
#define TARGET_ASM_INTEGER rs6000_assemble_integer
+#ifdef HAVE_GAS_HIDDEN
+#undef TARGET_ASM_ASSEMBLE_VISIBILITY
+#define TARGET_ASM_ASSEMBLE_VISIBILITY rs6000_assemble_visibility
+#endif
+
#undef TARGET_ASM_FUNCTION_PROLOGUE
#define TARGET_ASM_FUNCTION_PROLOGUE rs6000_output_function_prologue
#undef TARGET_ASM_FUNCTION_EPILOGUE
#define TARGET_ASM_FUNCTION_EPILOGUE rs6000_output_function_epilogue
-#if TARGET_ELF
-#undef TARGET_SECTION_TYPE_FLAGS
-#define TARGET_SECTION_TYPE_FLAGS rs6000_elf_section_type_flags
-#endif
-
#undef TARGET_SCHED_ISSUE_RATE
#define TARGET_SCHED_ISSUE_RATE rs6000_issue_rate
#undef TARGET_SCHED_ADJUST_COST
@@ -284,8 +379,18 @@ static const char alt_reg_names[][8] =
#undef TARGET_EXPAND_BUILTIN
#define TARGET_EXPAND_BUILTIN rs6000_expand_builtin
-/* The VRSAVE bitmask puts bit %v0 as the most significant bit. */
-#define ALTIVEC_REG_BIT(REGNO) (0x80000000 >> ((REGNO) - FIRST_ALTIVEC_REGNO))
+#undef TARGET_BINDS_LOCAL_P
+#define TARGET_BINDS_LOCAL_P rs6000_binds_local_p
+
+#undef TARGET_ASM_OUTPUT_MI_THUNK
+#define TARGET_ASM_OUTPUT_MI_THUNK rs6000_output_mi_thunk
+
+/* ??? Should work everywhere, but ask dje@watson.ibm.com before
+ enabling for AIX. */
+#if TARGET_OBJECT_FORMAT != OBJECT_XCOFF
+#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
+#define TARGET_ASM_CAN_OUTPUT_MI_THUNK default_can_output_mi_thunk_no_vcall
+#endif
struct gcc_target targetm = TARGET_INITIALIZER;
@@ -325,6 +430,9 @@ rs6000_override_options (default_cpu)
{"power3", PROCESSOR_PPC630,
MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
POWER_MASKS | MASK_PPC_GPOPT},
+ {"power4", PROCESSOR_POWER4,
+ MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
+ POWER_MASKS | MASK_PPC_GPOPT},
{"powerpc", PROCESSOR_POWERPC,
MASK_POWERPC | MASK_NEW_MNEMONICS,
POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
@@ -400,6 +508,9 @@ rs6000_override_options (default_cpu)
{"7450", PROCESSOR_PPC7450,
MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
+ {"8540", PROCESSOR_PPC8540,
+ MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
+ POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
{"801", PROCESSOR_MPCCORE,
MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS,
POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
@@ -413,7 +524,7 @@ rs6000_override_options (default_cpu)
MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS,
POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64}};
- size_t ptt_size = sizeof (processor_target_table) / sizeof (struct ptt);
+ const size_t ptt_size = ARRAY_SIZE (processor_target_table);
/* Save current -mmultiple/-mno-multiple status. */
int multiple = TARGET_MULTIPLE;
@@ -448,10 +559,13 @@ rs6000_override_options (default_cpu)
}
}
- /* If we are optimizing big endian systems for space, use the store
- multiple instructions. */
+ if (rs6000_cpu == PROCESSOR_PPC8540)
+ rs6000_isel = 1;
+
+ /* If we are optimizing big endian systems for space, use the load/store
+ multiple and string instructions. */
if (BYTES_BIG_ENDIAN && optimize_size)
- target_flags |= MASK_MULTIPLE;
+ target_flags |= MASK_MULTIPLE | MASK_STRING;
/* If -mmultiple or -mno-multiple was explicitly used, don't
override with the processor default */
@@ -492,20 +606,9 @@ rs6000_override_options (default_cpu)
flag_pic = 0;
}
-#ifdef XCOFF_DEBUGGING_INFO
- if (flag_function_sections && (write_symbols != NO_DEBUG)
- && DEFAULT_ABI == ABI_AIX)
- {
- warning ("-ffunction-sections disabled on AIX when debugging");
- flag_function_sections = 0;
- }
-
- if (flag_data_sections && (DEFAULT_ABI == ABI_AIX))
- {
- warning ("-fdata-sections not supported on AIX");
- flag_data_sections = 0;
- }
-#endif
+ /* For Darwin, always silently make -fpic and -fPIC identical. */
+ if (flag_pic == 1 && DEFAULT_ABI == ABI_DARWIN)
+ flag_pic = 2;
/* Set debug flags */
if (rs6000_debug_name)
@@ -520,6 +623,19 @@ rs6000_override_options (default_cpu)
error ("unknown -mdebug-%s switch", rs6000_debug_name);
}
+ if (rs6000_traceback_name)
+ {
+ if (! strncmp (rs6000_traceback_name, "full", 4))
+ rs6000_traceback = traceback_full;
+ else if (! strncmp (rs6000_traceback_name, "part", 4))
+ rs6000_traceback = traceback_part;
+ else if (! strncmp (rs6000_traceback_name, "no", 2))
+ rs6000_traceback = traceback_none;
+ else
+ error ("unknown -mtraceback arg `%s'; expecting `full', `partial' or `none'",
+ rs6000_traceback_name);
+ }
+
/* Set size of long double */
rs6000_long_double_type_size = 64;
if (rs6000_long_double_size_string)
@@ -536,12 +652,11 @@ rs6000_override_options (default_cpu)
/* Handle -mabi= options. */
rs6000_parse_abi_options ();
-#ifdef TARGET_REGNAMES
- /* If the user desires alternate register names, copy in the
- alternate names now. */
- if (TARGET_REGNAMES)
- memcpy (rs6000_reg_names, alt_reg_names, sizeof (rs6000_reg_names));
-#endif
+ /* Handle -mvrsave= option. */
+ rs6000_parse_vrsave_option ();
+
+ /* Handle -misel= option. */
+ rs6000_parse_isel_option ();
#ifdef SUBTARGET_OVERRIDE_OPTIONS
SUBTARGET_OVERRIDE_OPTIONS;
@@ -550,6 +665,29 @@ rs6000_override_options (default_cpu)
SUBSUBTARGET_OVERRIDE_OPTIONS;
#endif
+ /* Handle -m(no-)longcall option. This is a bit of a cheap hack,
+ using TARGET_OPTIONS to handle a toggle switch, but we're out of
+ bits in target_flags so TARGET_SWITCHES cannot be used.
+ Assumption here is that rs6000_longcall_switch points into the
+ text of the complete option, rather than being a copy, so we can
+ scan back for the presence or absence of the no- modifier. */
+ if (rs6000_longcall_switch)
+ {
+ const char *base = rs6000_longcall_switch;
+ while (base[-1] != 'm') base--;
+
+ if (*rs6000_longcall_switch != '\0')
+ error ("invalid option `%s'", base);
+ rs6000_default_long_calls = (base[0] != 'n');
+ }
+
+#ifdef TARGET_REGNAMES
+ /* If the user desires alternate register names, copy in the
+ alternate names now. */
+ if (TARGET_REGNAMES)
+ memcpy (rs6000_reg_names, alt_reg_names, sizeof (rs6000_reg_names));
+#endif
+
/* Set TARGET_AIX_STRUCT_RET last, after the ABI is determined.
If -maix-struct-return or -msvr4-struct-return was explicitly
used, don't override with the ABI default. */
@@ -561,6 +699,10 @@ rs6000_override_options (default_cpu)
target_flags |= MASK_AIX_STRUCT_RET;
}
+ if (TARGET_LONG_DOUBLE_128
+ && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_DARWIN))
+ real_format_for_mode[TFmode - QFmode] = &ibm_extended_format;
+
/* Register global variables with the garbage collector. */
rs6000_add_gc_roots ();
@@ -580,7 +722,36 @@ rs6000_override_options (default_cpu)
/* Arrange to save and restore machine status around nested functions. */
init_machine_status = rs6000_init_machine_status;
- free_machine_status = rs6000_free_machine_status;
+}
+
+/* Handle -misel= option. */
+static void
+rs6000_parse_isel_option ()
+{
+ if (rs6000_isel_string == 0)
+ return;
+ else if (! strcmp (rs6000_isel_string, "yes"))
+ rs6000_isel = 1;
+ else if (! strcmp (rs6000_isel_string, "no"))
+ rs6000_isel = 0;
+ else
+ error ("unknown -misel= option specified: '%s'",
+ rs6000_isel_string);
+}
+
+/* Handle -mvrsave= options. */
+static void
+rs6000_parse_vrsave_option ()
+{
+ /* Generate VRSAVE instructions by default. */
+ if (rs6000_altivec_vrsave_string == 0
+ || ! strcmp (rs6000_altivec_vrsave_string, "yes"))
+ rs6000_altivec_vrsave = 1;
+ else if (! strcmp (rs6000_altivec_vrsave_string, "no"))
+ rs6000_altivec_vrsave = 0;
+ else
+ error ("unknown -mvrsave= option specified: '%s'",
+ rs6000_altivec_vrsave_string);
}
/* Handle -mabi= options. */
@@ -593,6 +764,10 @@ rs6000_parse_abi_options ()
rs6000_altivec_abi = 1;
else if (! strcmp (rs6000_abi_string, "no-altivec"))
rs6000_altivec_abi = 0;
+ else if (! strcmp (rs6000_abi_string, "spe"))
+ rs6000_spe_abi = 1;
+ else if (! strcmp (rs6000_abi_string, "no-spe"))
+ rs6000_spe_abi = 0;
else
error ("unknown ABI specified: '%s'", rs6000_abi_string);
}
@@ -651,21 +826,8 @@ rs6000_file_start (file, default_cpu)
putc ('\n', file);
}
}
-
-
-/* Create a CONST_DOUBLE from a string. */
-
-struct rtx_def *
-rs6000_float_const (string, mode)
- const char *string;
- enum machine_mode mode;
-{
- REAL_VALUE_TYPE value;
- value = REAL_VALUE_ATOF (string, mode);
- return immed_real_const_1 (value, mode);
-}
-/* Return non-zero if this function is known to have a null epilogue. */
+/* Return nonzero if this function is known to have a null epilogue. */
int
direct_return ()
@@ -936,8 +1098,9 @@ reg_or_add_cint64_operand (op, mode)
{
return (gpc_reg_operand (op, mode)
|| (GET_CODE (op) == CONST_INT
+#if HOST_BITS_PER_WIDE_INT == 32
&& INTVAL (op) < 0x7fff8000
-#if HOST_BITS_PER_WIDE_INT != 32
+#else
&& ((unsigned HOST_WIDE_INT) (INTVAL (op) + 0x80008000)
< 0x100000000ll)
#endif
@@ -954,8 +1117,9 @@ reg_or_sub_cint64_operand (op, mode)
{
return (gpc_reg_operand (op, mode)
|| (GET_CODE (op) == CONST_INT
+#if HOST_BITS_PER_WIDE_INT == 32
&& (- INTVAL (op)) < 0x7fff8000
-#if HOST_BITS_PER_WIDE_INT != 32
+#else
&& ((unsigned HOST_WIDE_INT) ((- INTVAL (op)) + 0x80008000)
< 0x100000000ll)
#endif
@@ -1037,20 +1201,16 @@ num_insns_constant_wide (value)
#if HOST_BITS_PER_WIDE_INT == 64
else if (TARGET_POWERPC64)
{
- HOST_WIDE_INT low = value & 0xffffffff;
- HOST_WIDE_INT high = value >> 32;
+ HOST_WIDE_INT low = ((value & 0xffffffff) ^ 0x80000000) - 0x80000000;
+ HOST_WIDE_INT high = value >> 31;
- low = (low ^ 0x80000000) - 0x80000000; /* sign extend */
-
- if (high == 0 && (low & 0x80000000) == 0)
+ if (high == 0 || high == -1)
return 2;
- else if (high == -1 && (low & 0x80000000) != 0)
- return 2;
+ high >>= 1;
- else if (! low)
+ if (low == 0)
return num_insns_constant_wide (high) + 1;
-
else
return (num_insns_constant_wide (high)
+ num_insns_constant_wide (low) + 1);
@@ -1151,7 +1311,8 @@ easy_fp_constant (op, mode)
return 0;
/* Consider all constants with -msoft-float to be easy. */
- if (TARGET_SOFT_FLOAT && mode != DImode)
+ if ((TARGET_SOFT_FLOAT || !TARGET_FPRS)
+ && mode != DImode)
return 1;
/* If we are using V.4 style PIC, consider all constants to be hard. */
@@ -1165,7 +1326,21 @@ easy_fp_constant (op, mode)
return 0;
#endif
- if (mode == DFmode)
+ if (mode == TFmode)
+ {
+ long k[4];
+ REAL_VALUE_TYPE rv;
+
+ REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
+ REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, k);
+
+ return (num_insns_constant_wide ((HOST_WIDE_INT) k[0]) == 1
+ && num_insns_constant_wide ((HOST_WIDE_INT) k[1]) == 1
+ && num_insns_constant_wide ((HOST_WIDE_INT) k[2]) == 1
+ && num_insns_constant_wide ((HOST_WIDE_INT) k[3]) == 1);
+ }
+
+ else if (mode == DFmode)
{
long k[2];
REAL_VALUE_TYPE rv;
@@ -1173,8 +1348,8 @@ easy_fp_constant (op, mode)
REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
REAL_VALUE_TO_TARGET_DOUBLE (rv, k);
- return (num_insns_constant_wide ((HOST_WIDE_INT)k[0]) == 1
- && num_insns_constant_wide ((HOST_WIDE_INT)k[1]) == 1);
+ return (num_insns_constant_wide ((HOST_WIDE_INT) k[0]) == 1
+ && num_insns_constant_wide ((HOST_WIDE_INT) k[1]) == 1);
}
else if (mode == SFmode)
@@ -1439,64 +1614,187 @@ mask_operand (op, mode)
return c == -lsb;
}
+/* Return 1 for the PowerPC64 rlwinm corner case. */
+
+int
+mask_operand_wrap (op, mode)
+ rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ HOST_WIDE_INT c, lsb;
+
+ if (GET_CODE (op) != CONST_INT)
+ return 0;
+
+ c = INTVAL (op);
+
+ if ((c & 0x80000001) != 0x80000001)
+ return 0;
+
+ c = ~c;
+ if (c == 0)
+ return 0;
+
+ lsb = c & -c;
+ c = ~c;
+ c &= -lsb;
+ lsb = c & -c;
+ return c == -lsb;
+}
+
/* Return 1 if the operand is a constant that is a PowerPC64 mask.
It is if there are no more than one 1->0 or 0->1 transitions.
- Reject all ones and all zeros, since these should have been optimized
- away and confuse the making of MB and ME. */
+ Reject all zeros, since zero should have been optimized away and
+ confuses the making of MB and ME. */
int
mask64_operand (op, mode)
rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
if (GET_CODE (op) == CONST_INT)
{
HOST_WIDE_INT c, lsb;
- /* We don't change the number of transitions by inverting,
- so make sure we start with the LS bit zero. */
c = INTVAL (op);
- if (c & 1)
- c = ~c;
- /* Reject all zeros or all ones. */
+ /* Reject all zeros. */
if (c == 0)
return 0;
+ /* We don't change the number of transitions by inverting,
+ so make sure we start with the LS bit zero. */
+ if (c & 1)
+ c = ~c;
+
/* Find the transition, and check that all bits above are 1's. */
lsb = c & -c;
return c == -lsb;
}
- else if (GET_CODE (op) == CONST_DOUBLE
- && (mode == VOIDmode || mode == DImode))
+ return 0;
+}
+
+/* Like mask64_operand, but allow up to three transitions. This
+ predicate is used by insn patterns that generate two rldicl or
+ rldicr machine insns. */
+
+int
+mask64_2_operand (op, mode)
+ rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ if (GET_CODE (op) == CONST_INT)
{
- HOST_WIDE_INT low, high, lsb;
+ HOST_WIDE_INT c, lsb;
- if (HOST_BITS_PER_WIDE_INT < 64)
- high = CONST_DOUBLE_HIGH (op);
+ c = INTVAL (op);
- low = CONST_DOUBLE_LOW (op);
- if (low & 1)
- {
- if (HOST_BITS_PER_WIDE_INT < 64)
- high = ~high;
- low = ~low;
- }
+ /* Disallow all zeros. */
+ if (c == 0)
+ return 0;
- if (low == 0)
- {
- if (HOST_BITS_PER_WIDE_INT >= 64 || high == 0)
- return 0;
+ /* We don't change the number of transitions by inverting,
+ so make sure we start with the LS bit zero. */
+ if (c & 1)
+ c = ~c;
- lsb = high & -high;
- return high == -lsb;
- }
+ /* Find the first transition. */
+ lsb = c & -c;
- lsb = low & -low;
- return low == -lsb && (HOST_BITS_PER_WIDE_INT >= 64 || high == ~0);
+ /* Invert to look for a second transition. */
+ c = ~c;
+
+ /* Erase first transition. */
+ c &= -lsb;
+
+ /* Find the second transition. */
+ lsb = c & -c;
+
+ /* Invert to look for a third transition. */
+ c = ~c;
+
+ /* Erase second transition. */
+ c &= -lsb;
+
+ /* Find the third transition (if any). */
+ lsb = c & -c;
+
+ /* Match if all the bits above are 1's (or c is zero). */
+ return c == -lsb;
+ }
+ return 0;
+}
+
+/* Generates shifts and masks for a pair of rldicl or rldicr insns to
+ implement ANDing by the mask IN. */
+void
+build_mask64_2_operands (in, out)
+ rtx in;
+ rtx *out;
+{
+#if HOST_BITS_PER_WIDE_INT >= 64
+ unsigned HOST_WIDE_INT c, lsb, m1, m2;
+ int shift;
+
+ if (GET_CODE (in) != CONST_INT)
+ abort ();
+
+ c = INTVAL (in);
+ if (c & 1)
+ {
+ /* Assume c initially something like 0x00fff000000fffff. The idea
+ is to rotate the word so that the middle ^^^^^^ group of zeros
+ is at the MS end and can be cleared with an rldicl mask. We then
+ rotate back and clear off the MS ^^ group of zeros with a
+ second rldicl. */
+ c = ~c; /* c == 0xff000ffffff00000 */
+ lsb = c & -c; /* lsb == 0x0000000000100000 */
+ m1 = -lsb; /* m1 == 0xfffffffffff00000 */
+ c = ~c; /* c == 0x00fff000000fffff */
+ c &= -lsb; /* c == 0x00fff00000000000 */
+ lsb = c & -c; /* lsb == 0x0000100000000000 */
+ c = ~c; /* c == 0xff000fffffffffff */
+ c &= -lsb; /* c == 0xff00000000000000 */
+ shift = 0;
+ while ((lsb >>= 1) != 0)
+ shift++; /* shift == 44 on exit from loop */
+ m1 <<= 64 - shift; /* m1 == 0xffffff0000000000 */
+ m1 = ~m1; /* m1 == 0x000000ffffffffff */
+ m2 = ~c; /* m2 == 0x00ffffffffffffff */
}
else
- return 0;
+ {
+ /* Assume c initially something like 0xff000f0000000000. The idea
+ is to rotate the word so that the ^^^ middle group of zeros
+ is at the LS end and can be cleared with an rldicr mask. We then
+ rotate back and clear off the LS group of ^^^^^^^^^^ zeros with
+ a second rldicr. */
+ lsb = c & -c; /* lsb == 0x0000010000000000 */
+ m2 = -lsb; /* m2 == 0xffffff0000000000 */
+ c = ~c; /* c == 0x00fff0ffffffffff */
+ c &= -lsb; /* c == 0x00fff00000000000 */
+ lsb = c & -c; /* lsb == 0x0000100000000000 */
+ c = ~c; /* c == 0xff000fffffffffff */
+ c &= -lsb; /* c == 0xff00000000000000 */
+ shift = 0;
+ while ((lsb >>= 1) != 0)
+ shift++; /* shift == 44 on exit from loop */
+ m1 = ~c; /* m1 == 0x00ffffffffffffff */
+ m1 >>= shift; /* m1 == 0x0000000000000fff */
+ m1 = ~m1; /* m1 == 0xfffffffffffff000 */
+ }
+
+ /* Note that when we only have two 0->1 and 1->0 transitions, one of the
+ masks will be all 1's. We are guaranteed more than one transition. */
+ out[0] = GEN_INT (64 - shift);
+ out[1] = GEN_INT (m1);
+ out[2] = GEN_INT (shift);
+ out[3] = GEN_INT (m2);
+#else
+ (void)in;
+ (void)out;
+ abort ();
+#endif
}
/* Return 1 if the operand is either a non-special register or a constant
@@ -1513,6 +1811,20 @@ and64_operand (op, mode)
return (logical_operand (op, mode) || mask64_operand (op, mode));
}
+/* Like the above, but also match constants that can be implemented
+ with two rldicl or rldicr insns. */
+
+int
+and64_2_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ if (fixed_regs[CR0_REGNO]) /* CR0 not available, don't do andi./andis. */
+ return gpc_reg_operand (op, mode) || mask64_2_operand (op, mode);
+
+ return logical_operand (op, mode) || mask64_2_operand (op, mode);
+}
+
/* Return 1 if the operand is either a non-special register or a
constant that can be used as the operand of an RS/6000 logical AND insn. */
@@ -1562,9 +1874,21 @@ lwa_operand (op, mode)
|| INTVAL (XEXP (XEXP (inner, 0), 1)) % 4 == 0));
}
+/* Return 1 if the operand, used inside a MEM, is a SYMBOL_REF. */
+
+int
+symbol_ref_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ if (mode != VOIDmode && GET_MODE (op) != mode)
+ return 0;
+
+ return (GET_CODE (op) == SYMBOL_REF);
+}
+
/* Return 1 if the operand, used inside a MEM, is a valid first argument
- to CALL. This is a SYMBOL_REF or a pseudo-register, which will be
- forced to lr. */
+ to CALL. This is a SYMBOL_REF, a pseudo-register, LR or CTR. */
int
call_operand (op, mode)
@@ -1575,7 +1899,10 @@ call_operand (op, mode)
return 0;
return (GET_CODE (op) == SYMBOL_REF
- || (GET_CODE (op) == REG && REGNO (op) >= FIRST_PSEUDO_REGISTER));
+ || (GET_CODE (op) == REG
+ && (REGNO (op) == LINK_REGISTER_REGNUM
+ || REGNO (op) == COUNT_REGISTER_REGNUM
+ || REGNO (op) >= FIRST_PSEUDO_REGISTER)));
}
/* Return 1 if the operand is a SYMBOL_REF for a function known to be in
@@ -1790,10 +2117,8 @@ rs6000_legitimize_address (x, oldx, mode)
{
HOST_WIDE_INT high_int, low_int;
rtx sum;
- high_int = INTVAL (XEXP (x, 1)) & (~ (HOST_WIDE_INT) 0xffff);
- low_int = INTVAL (XEXP (x, 1)) & 0xffff;
- if (low_int & 0x8000)
- high_int += 0x10000, low_int |= ((HOST_WIDE_INT) -1) << 16;
+ low_int = ((INTVAL (XEXP (x, 1)) & 0xffff) ^ 0x8000) - 0x8000;
+ high_int = INTVAL (XEXP (x, 1)) - low_int;
sum = force_operand (gen_rtx_PLUS (Pmode, XEXP (x, 0),
GEN_INT (high_int)), 0);
return gen_rtx_PLUS (Pmode, sum, GEN_INT (low_int));
@@ -1802,7 +2127,9 @@ rs6000_legitimize_address (x, oldx, mode)
&& GET_CODE (XEXP (x, 0)) == REG
&& GET_CODE (XEXP (x, 1)) != CONST_INT
&& GET_MODE_NUNITS (mode) == 1
- && (TARGET_HARD_FLOAT || TARGET_POWERPC64 || mode != DFmode)
+ && ((TARGET_HARD_FLOAT && TARGET_FPRS)
+ || TARGET_POWERPC64
+ || (mode != DFmode && mode != TFmode))
&& (TARGET_POWERPC64 || mode != DImode)
&& mode != TImode)
{
@@ -1821,13 +2148,34 @@ rs6000_legitimize_address (x, oldx, mode)
reg = force_reg (Pmode, x);
return reg;
}
+ else if (SPE_VECTOR_MODE (mode))
+ {
+ /* We accept [reg + reg] and [reg + OFFSET]. */
+
+ if (GET_CODE (x) == PLUS)
+ {
+ rtx op1 = XEXP (x, 0);
+ rtx op2 = XEXP (x, 1);
+
+ op1 = force_reg (Pmode, op1);
+
+ if (GET_CODE (op2) != REG
+ && (GET_CODE (op2) != CONST_INT
+ || !SPE_CONST_OFFSET_OK (INTVAL (op2))))
+ op2 = force_reg (Pmode, op2);
+
+ return gen_rtx_PLUS (Pmode, op1, op2);
+ }
+
+ return force_reg (Pmode, x);
+ }
else if (TARGET_ELF && TARGET_32BIT && TARGET_NO_TOC && ! flag_pic
&& GET_CODE (x) != CONST_INT
&& GET_CODE (x) != CONST_DOUBLE
&& CONSTANT_P (x)
&& GET_MODE_NUNITS (mode) == 1
&& (GET_MODE_BITSIZE (mode) <= 32
- || (TARGET_HARD_FLOAT && mode == DFmode)))
+ || ((TARGET_HARD_FLOAT && TARGET_FPRS) && mode == DFmode)))
{
rtx reg = gen_reg_rtx (Pmode);
emit_insn (gen_elf_high (reg, (x)));
@@ -1838,7 +2186,7 @@ rs6000_legitimize_address (x, oldx, mode)
&& GET_CODE (x) != CONST_INT
&& GET_CODE (x) != CONST_DOUBLE
&& CONSTANT_P (x)
- && (TARGET_HARD_FLOAT || mode != DFmode)
+ && ((TARGET_HARD_FLOAT && TARGET_FPRS) || mode != DFmode)
&& mode != DImode
&& mode != TImode)
{
@@ -1925,6 +2273,7 @@ rs6000_legitimize_reload_address (x, mode, opnum, type, ind_levels, win)
&& REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER
&& REG_MODE_OK_FOR_BASE_P (XEXP (x, 0), mode)
&& GET_CODE (XEXP (x, 1)) == CONST_INT
+ && !SPE_VECTOR_MODE (mode)
&& !ALTIVEC_VECTOR_MODE (mode))
{
HOST_WIDE_INT val = INTVAL (XEXP (x, 1));
@@ -2013,6 +2362,7 @@ rs6000_legitimate_address (mode, x, reg_ok_strict)
return 1;
if ((GET_CODE (x) == PRE_INC || GET_CODE (x) == PRE_DEC)
&& !ALTIVEC_VECTOR_MODE (mode)
+ && !SPE_VECTOR_MODE (mode)
&& TARGET_UPDATE
&& LEGITIMATE_INDIRECT_ADDRESS_P (XEXP (x, 0), reg_ok_strict))
return 1;
@@ -2030,7 +2380,9 @@ rs6000_legitimate_address (mode, x, reg_ok_strict)
if (LEGITIMATE_OFFSET_ADDRESS_P (mode, x, reg_ok_strict))
return 1;
if (mode != TImode
- && (TARGET_HARD_FLOAT || TARGET_POWERPC64 || mode != DFmode)
+ && ((TARGET_HARD_FLOAT && TARGET_FPRS)
+ || TARGET_POWERPC64
+ || (mode != DFmode && mode != TFmode))
&& (TARGET_POWERPC64 || mode != DImode)
&& LEGITIMATE_INDEXED_ADDRESS_P (x, reg_ok_strict))
return 1;
@@ -2051,35 +2403,59 @@ rs6000_emit_set_const (dest, mode, source, n)
enum machine_mode mode;
int n ATTRIBUTE_UNUSED;
{
+ rtx result, insn, set;
HOST_WIDE_INT c0, c1;
- if (mode == QImode || mode == HImode || mode == SImode)
+ if (mode == QImode || mode == HImode)
{
if (dest == NULL)
dest = gen_reg_rtx (mode);
emit_insn (gen_rtx_SET (VOIDmode, dest, source));
return dest;
}
-
- if (GET_CODE (source) == CONST_INT)
+ else if (mode == SImode)
{
- c0 = INTVAL (source);
- c1 = -(c0 < 0);
+ result = no_new_pseudos ? dest : gen_reg_rtx (SImode);
+
+ emit_insn (gen_rtx_SET (VOIDmode, result,
+ GEN_INT (INTVAL (source)
+ & (~ (HOST_WIDE_INT) 0xffff))));
+ emit_insn (gen_rtx_SET (VOIDmode, dest,
+ gen_rtx_IOR (SImode, result,
+ GEN_INT (INTVAL (source) & 0xffff))));
+ result = dest;
}
- else if (GET_CODE (source) == CONST_DOUBLE)
+ else if (mode == DImode)
{
+ if (GET_CODE (source) == CONST_INT)
+ {
+ c0 = INTVAL (source);
+ c1 = -(c0 < 0);
+ }
+ else if (GET_CODE (source) == CONST_DOUBLE)
+ {
#if HOST_BITS_PER_WIDE_INT >= 64
- c0 = CONST_DOUBLE_LOW (source);
- c1 = -(c0 < 0);
+ c0 = CONST_DOUBLE_LOW (source);
+ c1 = -(c0 < 0);
#else
- c0 = CONST_DOUBLE_LOW (source);
- c1 = CONST_DOUBLE_HIGH (source);
+ c0 = CONST_DOUBLE_LOW (source);
+ c1 = CONST_DOUBLE_HIGH (source);
#endif
+ }
+ else
+ abort ();
+
+ result = rs6000_emit_set_long_const (dest, c0, c1);
}
else
abort ();
- return rs6000_emit_set_long_const (dest, c0, c1);
+ insn = get_last_insn ();
+ set = single_set (insn);
+ if (! CONSTANT_P (SET_SRC (set)))
+ set_unique_reg_note (insn, REG_EQUAL, source);
+
+ return result;
}
/* Having failed to find a 3 insn sequence in rs6000_emit_set_const,
@@ -2190,8 +2566,7 @@ rs6000_emit_move (dest, source, mode)
/* FIXME. This should never happen. */
/* Since it seems that it does, do the safe thing and convert
to a CONST_INT. */
- operands[1] =
- GEN_INT (trunc_int_for_mode (CONST_DOUBLE_LOW (operands[1]), mode));
+ operands[1] = gen_int_mode (CONST_DOUBLE_LOW (operands[1]), mode);
}
if (GET_CODE (operands[1]) == CONST_DOUBLE
&& ! FLOAT_MODE_P (mode)
@@ -2223,10 +2598,25 @@ rs6000_emit_move (dest, source, mode)
return;
}
- if (! no_new_pseudos && GET_CODE (operands[0]) != REG)
- operands[1] = force_reg (mode, operands[1]);
+ if (!no_new_pseudos)
+ {
+ if (GET_CODE (operands[1]) == MEM && optimize > 0
+ && (mode == QImode || mode == HImode || mode == SImode)
+ && GET_MODE_SIZE (mode) < GET_MODE_SIZE (word_mode))
+ {
+ rtx reg = gen_reg_rtx (word_mode);
+
+ emit_insn (gen_rtx_SET (word_mode, reg,
+ gen_rtx_ZERO_EXTEND (word_mode,
+ operands[1])));
+ operands[1] = gen_lowpart (mode, reg);
+ }
+ if (GET_CODE (operands[0]) != REG)
+ operands[1] = force_reg (mode, operands[1]);
+ }
- if (mode == SFmode && ! TARGET_POWERPC && TARGET_HARD_FLOAT
+ if (mode == SFmode && ! TARGET_POWERPC
+ && TARGET_HARD_FLOAT && TARGET_FPRS
&& GET_CODE (operands[0]) == MEM)
{
int regnum;
@@ -2250,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 (!VECTOR_MODE_P (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
@@ -2285,6 +2674,10 @@ rs6000_emit_move (dest, source, mode)
case V8HImode:
case V4SFmode:
case V4SImode:
+ case V4HImode:
+ case V2SFmode:
+ case V2SImode:
+ case V1DImode:
if (CONSTANT_P (operands[1])
&& !easy_vector_constant (operands[1]))
operands[1] = force_const_mem (mode, operands[1]);
@@ -2451,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:
@@ -2460,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
@@ -2477,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;
@@ -2490,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)
@@ -2506,8 +2909,10 @@ init_cumulative_args (cum, fntype, libname, incoming)
cum->orig_nargs = cum->nargs_prototype;
- /* Check for longcall's */
- if (fntype && lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype)))
+ /* 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 (TARGET_DEBUG_ARG)
@@ -2568,6 +2973,8 @@ function_arg_boundary (mode, type)
{
if (DEFAULT_ABI == ABI_V4 && (mode == DImode || mode == DFmode))
return 64;
+ else if (SPE_VECTOR_MODE (mode))
+ return 64;
else if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
return 128;
else
@@ -2594,9 +3001,12 @@ function_arg_advance (cum, mode, type, named)
else
cum->words += RS6000_ARG_SIZE (mode, type);
}
+ else if (TARGET_SPE_ABI && TARGET_SPE && SPE_VECTOR_MODE (mode)
+ && named && cum->sysv_gregno <= GP_ARG_MAX_REG)
+ cum->sysv_gregno++;
else if (DEFAULT_ABI == ABI_V4)
{
- if (TARGET_HARD_FLOAT
+ if (TARGET_HARD_FLOAT && TARGET_FPRS
&& (mode == SFmode || mode == DFmode))
{
if (cum->fregno <= FP_ARG_V4_MAX_REG)
@@ -2620,11 +3030,12 @@ function_arg_advance (cum, mode, type, named)
else
n_words = RS6000_ARG_SIZE (mode, type);
- /* Long long is put in odd registers. */
+ /* Long long and SPE vectors are put in odd registers. */
if (n_words == 2 && (gregno & 1) == 0)
gregno += 1;
- /* Long long is not split between registers and stack. */
+ /* Long long and SPE vectors are not split between registers
+ and stack. */
if (gregno + n_words - 1 > GP_ARG_MAX_REG)
{
/* Long long is aligned on the stack. */
@@ -2656,8 +3067,9 @@ function_arg_advance (cum, mode, type, named)
cum->words += align + RS6000_ARG_SIZE (mode, type);
- if (GET_MODE_CLASS (mode) == MODE_FLOAT && TARGET_HARD_FLOAT)
- cum->fregno++;
+ if (GET_MODE_CLASS (mode) == MODE_FLOAT
+ && TARGET_HARD_FLOAT && TARGET_FPRS)
+ cum->fregno += (mode == TFmode ? 2 : 1);
if (TARGET_DEBUG_ARG)
{
@@ -2689,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. */
@@ -2709,14 +3121,18 @@ function_arg (cum, mode, type, named)
if (mode == VOIDmode)
{
if (abi == ABI_V4
- && TARGET_HARD_FLOAT
&& cum->nargs_prototype < 0
- && type && (cum->prototype || TARGET_NO_PROTOTYPE))
+ && (cum->call_cookie & CALL_LIBCALL) == 0
+ && (cum->prototype || TARGET_NO_PROTOTYPE))
{
- return GEN_INT (cum->call_cookie
- | ((cum->fregno == FP_ARG_MIN_REG)
- ? CALL_V4_SET_FP_ARGS
- : CALL_V4_CLEAR_FP_ARGS));
+ /* For the SPE, we need to crxor CR6 always. */
+ if (TARGET_SPE_ABI)
+ return GEN_INT (cum->call_cookie | CALL_V4_SET_FP_ARGS);
+ else if (TARGET_HARD_FLOAT && TARGET_FPRS)
+ return GEN_INT (cum->call_cookie
+ | ((cum->fregno == FP_ARG_MIN_REG)
+ ? CALL_V4_SET_FP_ARGS
+ : CALL_V4_CLEAR_FP_ARGS));
}
return GEN_INT (cum->call_cookie);
@@ -2729,9 +3145,16 @@ function_arg (cum, mode, type, named)
else
return NULL;
}
+ else if (TARGET_SPE_ABI && TARGET_SPE && SPE_VECTOR_MODE (mode) && named)
+ {
+ if (cum->sysv_gregno <= GP_ARG_MAX_REG)
+ return gen_rtx_REG (mode, cum->sysv_gregno);
+ else
+ return NULL;
+ }
else if (abi == ABI_V4)
{
- if (TARGET_HARD_FLOAT
+ if (TARGET_HARD_FLOAT && TARGET_FPRS
&& (mode == SFmode || mode == DFmode))
{
if (cum->fregno <= FP_ARG_V4_MAX_REG)
@@ -2751,13 +3174,29 @@ function_arg (cum, mode, type, named)
else
n_words = RS6000_ARG_SIZE (mode, type);
- /* Long long is put in odd registers. */
+ /* Long long and SPE vectors are put in odd registers. */
if (n_words == 2 && (gregno & 1) == 0)
gregno += 1;
- /* Long long is not split between registers and stack. */
+ /* Long long and SPE vectors are not split between registers
+ and stack. */
if (gregno + n_words - 1 <= GP_ARG_MAX_REG)
- return gen_rtx_REG (mode, gregno);
+ {
+ /* SPE vectors in ... get split into 2 registers. */
+ if (TARGET_SPE && TARGET_SPE_ABI
+ && SPE_VECTOR_MODE (mode) && !named)
+ {
+ rtx r1, r2;
+ enum machine_mode m = SImode;
+
+ r1 = gen_rtx_REG (m, gregno);
+ r1 = gen_rtx_EXPR_LIST (m, r1, const0_rtx);
+ r2 = gen_rtx_REG (m, gregno + 1);
+ r2 = gen_rtx_EXPR_LIST (m, r2, GEN_INT (4));
+ return gen_rtx_PARALLEL (mode, gen_rtvec (2, r1, r2));
+ }
+ return gen_rtx_REG (mode, gregno);
+ }
else
return NULL;
}
@@ -2850,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)
@@ -2868,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
@@ -2916,8 +3357,6 @@ setup_incoming_varargs (cum, mode, type, pretend_size, no_rtl)
if (DEFAULT_ABI == ABI_V4)
{
/* Indicate to allocate space on the stack for varargs save area. */
- /* ??? Does this really have to be located at a magic spot on the
- stack, or can we allocate this with assign_stack_local instead. */
cfun->machine->sysv_varargs_p = 1;
if (! no_rtl)
save_area = plus_constant (virtual_stack_vars_rtx,
@@ -2955,7 +3394,8 @@ setup_incoming_varargs (cum, mode, type, pretend_size, no_rtl)
/* Save FP registers if needed. */
if (DEFAULT_ABI == ABI_V4
- && TARGET_HARD_FLOAT && ! no_rtl
+ && TARGET_HARD_FLOAT && TARGET_FPRS
+ && ! no_rtl
&& next_cum.fregno <= FP_ARG_V4_MAX_REG)
{
int fregno = next_cum.fregno;
@@ -2996,7 +3436,7 @@ rs6000_build_va_list ()
if (DEFAULT_ABI != ABI_V4)
return build_pointer_type (char_type_node);
- record = make_lang_type (RECORD_TYPE);
+ record = (*lang_hooks.types.make_type) (RECORD_TYPE);
type_decl = build_decl (TYPE_DECL, get_identifier ("__va_list_tag"), record);
f_gpr = build_decl (FIELD_DECL, get_identifier ("gpr"),
@@ -3029,8 +3469,7 @@ rs6000_build_va_list ()
/* Implement va_start. */
void
-rs6000_va_start (stdarg_p, valist, nextarg)
- int stdarg_p;
+rs6000_va_start (valist, nextarg)
tree valist;
rtx nextarg;
{
@@ -3041,7 +3480,7 @@ rs6000_va_start (stdarg_p, valist, nextarg)
/* Only SVR4 needs something special. */
if (DEFAULT_ABI != ABI_V4)
{
- std_expand_builtin_va_start (stdarg_p, valist, nextarg);
+ std_expand_builtin_va_start (valist, nextarg);
return;
}
@@ -3109,13 +3548,29 @@ rs6000_va_arg (valist, type)
int indirect_p, size, rsize, n_reg, sav_ofs, sav_scale;
rtx lab_false, lab_over, addr_rtx, r;
- /* For AIX, the rule is that structures are passed left-aligned in
- their stack slot. However, GCC does not presently do this:
- structures which are the same size as integer types are passed
- right-aligned, as if they were in fact integers. This only
- matters for structures of size 1 or 2, or 4 when TARGET_64BIT. */
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);
@@ -3142,7 +3597,7 @@ rs6000_va_arg (valist, type)
size = UNITS_PER_WORD;
rsize = 1;
}
- else if (FLOAT_TYPE_P (type) && ! TARGET_SOFT_FLOAT)
+ else if (FLOAT_TYPE_P (type) && TARGET_HARD_FLOAT && TARGET_FPRS)
{
/* FP args go in FP registers, if present. */
indirect_p = 0;
@@ -3167,8 +3622,8 @@ rs6000_va_arg (valist, type)
lab_over = gen_label_rtx ();
addr_rtx = gen_reg_rtx (Pmode);
- /* Vectors never go in registers. */
- if (TREE_CODE (type) != VECTOR_TYPE)
+ /* AltiVec vectors never go in registers. */
+ if (!TARGET_ALTIVEC || TREE_CODE (type) != VECTOR_TYPE)
{
TREE_THIS_VOLATILE (reg) = 1;
emit_cmp_and_jump_insns
@@ -3222,7 +3677,8 @@ rs6000_va_arg (valist, type)
All AltiVec vectors go in the overflow area. So in the AltiVec
case we need to get the vectors from the overflow area, but
remember where the GPRs and FPRs are. */
- if (n_reg > 1 && TREE_CODE (type) != VECTOR_TYPE)
+ if (n_reg > 1 && (TREE_CODE (type) != VECTOR_TYPE
+ || !TARGET_ALTIVEC))
{
t = build (MODIFY_EXPR, TREE_TYPE (reg), reg, build_int_2 (8, 0));
TREE_SIDE_EFFECTS (t) = 1;
@@ -3236,8 +3692,8 @@ rs6000_va_arg (valist, type)
{
int align;
- /* Vectors are 16 byte aligned. */
- if (TREE_CODE (type) == VECTOR_TYPE)
+ /* AltiVec vectors are 16 byte aligned. */
+ if (TARGET_ALTIVEC && TREE_CODE (type) == VECTOR_TYPE)
align = 15;
else
align = 7;
@@ -3270,20 +3726,13 @@ rs6000_va_arg (valist, type)
/* Builtins. */
-#define def_builtin(MASK, NAME, TYPE, CODE) \
-do { \
- if ((MASK) & target_flags) \
- builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, NULL); \
+#define def_builtin(MASK, NAME, TYPE, CODE) \
+do { \
+ if ((MASK) & target_flags) \
+ builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, \
+ NULL, NULL_TREE); \
} while (0)
-struct builtin_description
-{
- const unsigned int mask;
- const enum insn_code icode;
- const char *const name;
- const enum rs6000_builtins code;
-};
-
/* Simple ternary operations: VECd = foo (VECa, VECb, VECc). */
static const struct builtin_description bdesc_3arg[] =
@@ -3325,7 +3774,7 @@ static const struct builtin_description bdesc_dst[] =
/* Simple binary operations: VECc = foo (VECa, VECb). */
-static const struct builtin_description bdesc_2arg[] =
+static struct builtin_description bdesc_2arg[] =
{
{ MASK_ALTIVEC, CODE_FOR_addv16qi3, "__builtin_altivec_vaddubm", ALTIVEC_BUILTIN_VADDUBM },
{ MASK_ALTIVEC, CODE_FOR_addv8hi3, "__builtin_altivec_vadduhm", ALTIVEC_BUILTIN_VADDUHM },
@@ -3365,11 +3814,11 @@ static const struct builtin_description bdesc_2arg[] =
{ MASK_ALTIVEC, CODE_FOR_altivec_vctuxs, "__builtin_altivec_vctuxs", ALTIVEC_BUILTIN_VCTUXS },
{ MASK_ALTIVEC, CODE_FOR_umaxv16qi3, "__builtin_altivec_vmaxub", ALTIVEC_BUILTIN_VMAXUB },
{ MASK_ALTIVEC, CODE_FOR_smaxv16qi3, "__builtin_altivec_vmaxsb", ALTIVEC_BUILTIN_VMAXSB },
- { MASK_ALTIVEC, CODE_FOR_uminv8hi3, "__builtin_altivec_vmaxuh", ALTIVEC_BUILTIN_VMAXUH },
- { MASK_ALTIVEC, CODE_FOR_sminv8hi3, "__builtin_altivec_vmaxsh", ALTIVEC_BUILTIN_VMAXSH },
- { MASK_ALTIVEC, CODE_FOR_uminv4si3, "__builtin_altivec_vmaxuw", ALTIVEC_BUILTIN_VMAXUW },
- { MASK_ALTIVEC, CODE_FOR_sminv4si3, "__builtin_altivec_vmaxsw", ALTIVEC_BUILTIN_VMAXSW },
- { MASK_ALTIVEC, CODE_FOR_sminv4sf3, "__builtin_altivec_vmaxfp", ALTIVEC_BUILTIN_VMAXFP },
+ { MASK_ALTIVEC, CODE_FOR_umaxv8hi3, "__builtin_altivec_vmaxuh", ALTIVEC_BUILTIN_VMAXUH },
+ { MASK_ALTIVEC, CODE_FOR_smaxv8hi3, "__builtin_altivec_vmaxsh", ALTIVEC_BUILTIN_VMAXSH },
+ { MASK_ALTIVEC, CODE_FOR_umaxv4si3, "__builtin_altivec_vmaxuw", ALTIVEC_BUILTIN_VMAXUW },
+ { MASK_ALTIVEC, CODE_FOR_smaxv4si3, "__builtin_altivec_vmaxsw", ALTIVEC_BUILTIN_VMAXSW },
+ { MASK_ALTIVEC, CODE_FOR_smaxv4sf3, "__builtin_altivec_vmaxfp", ALTIVEC_BUILTIN_VMAXFP },
{ MASK_ALTIVEC, CODE_FOR_altivec_vmrghb, "__builtin_altivec_vmrghb", ALTIVEC_BUILTIN_VMRGHB },
{ MASK_ALTIVEC, CODE_FOR_altivec_vmrghh, "__builtin_altivec_vmrghh", ALTIVEC_BUILTIN_VMRGHH },
{ MASK_ALTIVEC, CODE_FOR_altivec_vmrghw, "__builtin_altivec_vmrghw", ALTIVEC_BUILTIN_VMRGHW },
@@ -3440,6 +3889,150 @@ static const struct builtin_description bdesc_2arg[] =
{ MASK_ALTIVEC, CODE_FOR_altivec_vsum2sws, "__builtin_altivec_vsum2sws", ALTIVEC_BUILTIN_VSUM2SWS },
{ MASK_ALTIVEC, CODE_FOR_altivec_vsumsws, "__builtin_altivec_vsumsws", ALTIVEC_BUILTIN_VSUMSWS },
{ MASK_ALTIVEC, CODE_FOR_xorv4si3, "__builtin_altivec_vxor", ALTIVEC_BUILTIN_VXOR },
+
+ /* Place holder, leave as first spe builtin. */
+ { 0, CODE_FOR_spe_evaddw, "__builtin_spe_evaddw", SPE_BUILTIN_EVADDW },
+ { 0, CODE_FOR_spe_evand, "__builtin_spe_evand", SPE_BUILTIN_EVAND },
+ { 0, CODE_FOR_spe_evandc, "__builtin_spe_evandc", SPE_BUILTIN_EVANDC },
+ { 0, CODE_FOR_spe_evdivws, "__builtin_spe_evdivws", SPE_BUILTIN_EVDIVWS },
+ { 0, CODE_FOR_spe_evdivwu, "__builtin_spe_evdivwu", SPE_BUILTIN_EVDIVWU },
+ { 0, CODE_FOR_spe_eveqv, "__builtin_spe_eveqv", SPE_BUILTIN_EVEQV },
+ { 0, CODE_FOR_spe_evfsadd, "__builtin_spe_evfsadd", SPE_BUILTIN_EVFSADD },
+ { 0, CODE_FOR_spe_evfsdiv, "__builtin_spe_evfsdiv", SPE_BUILTIN_EVFSDIV },
+ { 0, CODE_FOR_spe_evfsmul, "__builtin_spe_evfsmul", SPE_BUILTIN_EVFSMUL },
+ { 0, CODE_FOR_spe_evfssub, "__builtin_spe_evfssub", SPE_BUILTIN_EVFSSUB },
+ { 0, CODE_FOR_spe_evmergehi, "__builtin_spe_evmergehi", SPE_BUILTIN_EVMERGEHI },
+ { 0, CODE_FOR_spe_evmergehilo, "__builtin_spe_evmergehilo", SPE_BUILTIN_EVMERGEHILO },
+ { 0, CODE_FOR_spe_evmergelo, "__builtin_spe_evmergelo", SPE_BUILTIN_EVMERGELO },
+ { 0, CODE_FOR_spe_evmergelohi, "__builtin_spe_evmergelohi", SPE_BUILTIN_EVMERGELOHI },
+ { 0, CODE_FOR_spe_evmhegsmfaa, "__builtin_spe_evmhegsmfaa", SPE_BUILTIN_EVMHEGSMFAA },
+ { 0, CODE_FOR_spe_evmhegsmfan, "__builtin_spe_evmhegsmfan", SPE_BUILTIN_EVMHEGSMFAN },
+ { 0, CODE_FOR_spe_evmhegsmiaa, "__builtin_spe_evmhegsmiaa", SPE_BUILTIN_EVMHEGSMIAA },
+ { 0, CODE_FOR_spe_evmhegsmian, "__builtin_spe_evmhegsmian", SPE_BUILTIN_EVMHEGSMIAN },
+ { 0, CODE_FOR_spe_evmhegumiaa, "__builtin_spe_evmhegumiaa", SPE_BUILTIN_EVMHEGUMIAA },
+ { 0, CODE_FOR_spe_evmhegumian, "__builtin_spe_evmhegumian", SPE_BUILTIN_EVMHEGUMIAN },
+ { 0, CODE_FOR_spe_evmhesmf, "__builtin_spe_evmhesmf", SPE_BUILTIN_EVMHESMF },
+ { 0, CODE_FOR_spe_evmhesmfa, "__builtin_spe_evmhesmfa", SPE_BUILTIN_EVMHESMFA },
+ { 0, CODE_FOR_spe_evmhesmfaaw, "__builtin_spe_evmhesmfaaw", SPE_BUILTIN_EVMHESMFAAW },
+ { 0, CODE_FOR_spe_evmhesmfanw, "__builtin_spe_evmhesmfanw", SPE_BUILTIN_EVMHESMFANW },
+ { 0, CODE_FOR_spe_evmhesmi, "__builtin_spe_evmhesmi", SPE_BUILTIN_EVMHESMI },
+ { 0, CODE_FOR_spe_evmhesmia, "__builtin_spe_evmhesmia", SPE_BUILTIN_EVMHESMIA },
+ { 0, CODE_FOR_spe_evmhesmiaaw, "__builtin_spe_evmhesmiaaw", SPE_BUILTIN_EVMHESMIAAW },
+ { 0, CODE_FOR_spe_evmhesmianw, "__builtin_spe_evmhesmianw", SPE_BUILTIN_EVMHESMIANW },
+ { 0, CODE_FOR_spe_evmhessf, "__builtin_spe_evmhessf", SPE_BUILTIN_EVMHESSF },
+ { 0, CODE_FOR_spe_evmhessfa, "__builtin_spe_evmhessfa", SPE_BUILTIN_EVMHESSFA },
+ { 0, CODE_FOR_spe_evmhessfaaw, "__builtin_spe_evmhessfaaw", SPE_BUILTIN_EVMHESSFAAW },
+ { 0, CODE_FOR_spe_evmhessfanw, "__builtin_spe_evmhessfanw", SPE_BUILTIN_EVMHESSFANW },
+ { 0, CODE_FOR_spe_evmhessiaaw, "__builtin_spe_evmhessiaaw", SPE_BUILTIN_EVMHESSIAAW },
+ { 0, CODE_FOR_spe_evmhessianw, "__builtin_spe_evmhessianw", SPE_BUILTIN_EVMHESSIANW },
+ { 0, CODE_FOR_spe_evmheumi, "__builtin_spe_evmheumi", SPE_BUILTIN_EVMHEUMI },
+ { 0, CODE_FOR_spe_evmheumia, "__builtin_spe_evmheumia", SPE_BUILTIN_EVMHEUMIA },
+ { 0, CODE_FOR_spe_evmheumiaaw, "__builtin_spe_evmheumiaaw", SPE_BUILTIN_EVMHEUMIAAW },
+ { 0, CODE_FOR_spe_evmheumianw, "__builtin_spe_evmheumianw", SPE_BUILTIN_EVMHEUMIANW },
+ { 0, CODE_FOR_spe_evmheusiaaw, "__builtin_spe_evmheusiaaw", SPE_BUILTIN_EVMHEUSIAAW },
+ { 0, CODE_FOR_spe_evmheusianw, "__builtin_spe_evmheusianw", SPE_BUILTIN_EVMHEUSIANW },
+ { 0, CODE_FOR_spe_evmhogsmfaa, "__builtin_spe_evmhogsmfaa", SPE_BUILTIN_EVMHOGSMFAA },
+ { 0, CODE_FOR_spe_evmhogsmfan, "__builtin_spe_evmhogsmfan", SPE_BUILTIN_EVMHOGSMFAN },
+ { 0, CODE_FOR_spe_evmhogsmiaa, "__builtin_spe_evmhogsmiaa", SPE_BUILTIN_EVMHOGSMIAA },
+ { 0, CODE_FOR_spe_evmhogsmian, "__builtin_spe_evmhogsmian", SPE_BUILTIN_EVMHOGSMIAN },
+ { 0, CODE_FOR_spe_evmhogumiaa, "__builtin_spe_evmhogumiaa", SPE_BUILTIN_EVMHOGUMIAA },
+ { 0, CODE_FOR_spe_evmhogumian, "__builtin_spe_evmhogumian", SPE_BUILTIN_EVMHOGUMIAN },
+ { 0, CODE_FOR_spe_evmhosmf, "__builtin_spe_evmhosmf", SPE_BUILTIN_EVMHOSMF },
+ { 0, CODE_FOR_spe_evmhosmfa, "__builtin_spe_evmhosmfa", SPE_BUILTIN_EVMHOSMFA },
+ { 0, CODE_FOR_spe_evmhosmfaaw, "__builtin_spe_evmhosmfaaw", SPE_BUILTIN_EVMHOSMFAAW },
+ { 0, CODE_FOR_spe_evmhosmfanw, "__builtin_spe_evmhosmfanw", SPE_BUILTIN_EVMHOSMFANW },
+ { 0, CODE_FOR_spe_evmhosmi, "__builtin_spe_evmhosmi", SPE_BUILTIN_EVMHOSMI },
+ { 0, CODE_FOR_spe_evmhosmia, "__builtin_spe_evmhosmia", SPE_BUILTIN_EVMHOSMIA },
+ { 0, CODE_FOR_spe_evmhosmiaaw, "__builtin_spe_evmhosmiaaw", SPE_BUILTIN_EVMHOSMIAAW },
+ { 0, CODE_FOR_spe_evmhosmianw, "__builtin_spe_evmhosmianw", SPE_BUILTIN_EVMHOSMIANW },
+ { 0, CODE_FOR_spe_evmhossf, "__builtin_spe_evmhossf", SPE_BUILTIN_EVMHOSSF },
+ { 0, CODE_FOR_spe_evmhossfa, "__builtin_spe_evmhossfa", SPE_BUILTIN_EVMHOSSFA },
+ { 0, CODE_FOR_spe_evmhossfaaw, "__builtin_spe_evmhossfaaw", SPE_BUILTIN_EVMHOSSFAAW },
+ { 0, CODE_FOR_spe_evmhossfanw, "__builtin_spe_evmhossfanw", SPE_BUILTIN_EVMHOSSFANW },
+ { 0, CODE_FOR_spe_evmhossiaaw, "__builtin_spe_evmhossiaaw", SPE_BUILTIN_EVMHOSSIAAW },
+ { 0, CODE_FOR_spe_evmhossianw, "__builtin_spe_evmhossianw", SPE_BUILTIN_EVMHOSSIANW },
+ { 0, CODE_FOR_spe_evmhoumi, "__builtin_spe_evmhoumi", SPE_BUILTIN_EVMHOUMI },
+ { 0, CODE_FOR_spe_evmhoumia, "__builtin_spe_evmhoumia", SPE_BUILTIN_EVMHOUMIA },
+ { 0, CODE_FOR_spe_evmhoumiaaw, "__builtin_spe_evmhoumiaaw", SPE_BUILTIN_EVMHOUMIAAW },
+ { 0, CODE_FOR_spe_evmhoumianw, "__builtin_spe_evmhoumianw", SPE_BUILTIN_EVMHOUMIANW },
+ { 0, CODE_FOR_spe_evmhousiaaw, "__builtin_spe_evmhousiaaw", SPE_BUILTIN_EVMHOUSIAAW },
+ { 0, CODE_FOR_spe_evmhousianw, "__builtin_spe_evmhousianw", SPE_BUILTIN_EVMHOUSIANW },
+ { 0, CODE_FOR_spe_evmwhsmf, "__builtin_spe_evmwhsmf", SPE_BUILTIN_EVMWHSMF },
+ { 0, CODE_FOR_spe_evmwhsmfa, "__builtin_spe_evmwhsmfa", SPE_BUILTIN_EVMWHSMFA },
+ { 0, CODE_FOR_spe_evmwhsmi, "__builtin_spe_evmwhsmi", SPE_BUILTIN_EVMWHSMI },
+ { 0, CODE_FOR_spe_evmwhsmia, "__builtin_spe_evmwhsmia", SPE_BUILTIN_EVMWHSMIA },
+ { 0, CODE_FOR_spe_evmwhssf, "__builtin_spe_evmwhssf", SPE_BUILTIN_EVMWHSSF },
+ { 0, CODE_FOR_spe_evmwhssfa, "__builtin_spe_evmwhssfa", SPE_BUILTIN_EVMWHSSFA },
+ { 0, CODE_FOR_spe_evmwhumi, "__builtin_spe_evmwhumi", SPE_BUILTIN_EVMWHUMI },
+ { 0, CODE_FOR_spe_evmwhumia, "__builtin_spe_evmwhumia", SPE_BUILTIN_EVMWHUMIA },
+ { 0, CODE_FOR_spe_evmwlsmiaaw, "__builtin_spe_evmwlsmiaaw", SPE_BUILTIN_EVMWLSMIAAW },
+ { 0, CODE_FOR_spe_evmwlsmianw, "__builtin_spe_evmwlsmianw", SPE_BUILTIN_EVMWLSMIANW },
+ { 0, CODE_FOR_spe_evmwlssiaaw, "__builtin_spe_evmwlssiaaw", SPE_BUILTIN_EVMWLSSIAAW },
+ { 0, CODE_FOR_spe_evmwlssianw, "__builtin_spe_evmwlssianw", SPE_BUILTIN_EVMWLSSIANW },
+ { 0, CODE_FOR_spe_evmwlumi, "__builtin_spe_evmwlumi", SPE_BUILTIN_EVMWLUMI },
+ { 0, CODE_FOR_spe_evmwlumia, "__builtin_spe_evmwlumia", SPE_BUILTIN_EVMWLUMIA },
+ { 0, CODE_FOR_spe_evmwlumiaaw, "__builtin_spe_evmwlumiaaw", SPE_BUILTIN_EVMWLUMIAAW },
+ { 0, CODE_FOR_spe_evmwlumianw, "__builtin_spe_evmwlumianw", SPE_BUILTIN_EVMWLUMIANW },
+ { 0, CODE_FOR_spe_evmwlusiaaw, "__builtin_spe_evmwlusiaaw", SPE_BUILTIN_EVMWLUSIAAW },
+ { 0, CODE_FOR_spe_evmwlusianw, "__builtin_spe_evmwlusianw", SPE_BUILTIN_EVMWLUSIANW },
+ { 0, CODE_FOR_spe_evmwsmf, "__builtin_spe_evmwsmf", SPE_BUILTIN_EVMWSMF },
+ { 0, CODE_FOR_spe_evmwsmfa, "__builtin_spe_evmwsmfa", SPE_BUILTIN_EVMWSMFA },
+ { 0, CODE_FOR_spe_evmwsmfaa, "__builtin_spe_evmwsmfaa", SPE_BUILTIN_EVMWSMFAA },
+ { 0, CODE_FOR_spe_evmwsmfan, "__builtin_spe_evmwsmfan", SPE_BUILTIN_EVMWSMFAN },
+ { 0, CODE_FOR_spe_evmwsmi, "__builtin_spe_evmwsmi", SPE_BUILTIN_EVMWSMI },
+ { 0, CODE_FOR_spe_evmwsmia, "__builtin_spe_evmwsmia", SPE_BUILTIN_EVMWSMIA },
+ { 0, CODE_FOR_spe_evmwsmiaa, "__builtin_spe_evmwsmiaa", SPE_BUILTIN_EVMWSMIAA },
+ { 0, CODE_FOR_spe_evmwsmian, "__builtin_spe_evmwsmian", SPE_BUILTIN_EVMWSMIAN },
+ { 0, CODE_FOR_spe_evmwssf, "__builtin_spe_evmwssf", SPE_BUILTIN_EVMWSSF },
+ { 0, CODE_FOR_spe_evmwssfa, "__builtin_spe_evmwssfa", SPE_BUILTIN_EVMWSSFA },
+ { 0, CODE_FOR_spe_evmwssfaa, "__builtin_spe_evmwssfaa", SPE_BUILTIN_EVMWSSFAA },
+ { 0, CODE_FOR_spe_evmwssfan, "__builtin_spe_evmwssfan", SPE_BUILTIN_EVMWSSFAN },
+ { 0, CODE_FOR_spe_evmwumi, "__builtin_spe_evmwumi", SPE_BUILTIN_EVMWUMI },
+ { 0, CODE_FOR_spe_evmwumia, "__builtin_spe_evmwumia", SPE_BUILTIN_EVMWUMIA },
+ { 0, CODE_FOR_spe_evmwumiaa, "__builtin_spe_evmwumiaa", SPE_BUILTIN_EVMWUMIAA },
+ { 0, CODE_FOR_spe_evmwumian, "__builtin_spe_evmwumian", SPE_BUILTIN_EVMWUMIAN },
+ { 0, CODE_FOR_spe_evnand, "__builtin_spe_evnand", SPE_BUILTIN_EVNAND },
+ { 0, CODE_FOR_spe_evnor, "__builtin_spe_evnor", SPE_BUILTIN_EVNOR },
+ { 0, CODE_FOR_spe_evor, "__builtin_spe_evor", SPE_BUILTIN_EVOR },
+ { 0, CODE_FOR_spe_evorc, "__builtin_spe_evorc", SPE_BUILTIN_EVORC },
+ { 0, CODE_FOR_spe_evrlw, "__builtin_spe_evrlw", SPE_BUILTIN_EVRLW },
+ { 0, CODE_FOR_spe_evslw, "__builtin_spe_evslw", SPE_BUILTIN_EVSLW },
+ { 0, CODE_FOR_spe_evsrws, "__builtin_spe_evsrws", SPE_BUILTIN_EVSRWS },
+ { 0, CODE_FOR_spe_evsrwu, "__builtin_spe_evsrwu", SPE_BUILTIN_EVSRWU },
+ { 0, CODE_FOR_spe_evsubfw, "__builtin_spe_evsubfw", SPE_BUILTIN_EVSUBFW },
+
+ /* SPE binary operations expecting a 5-bit unsigned literal. */
+ { 0, CODE_FOR_spe_evaddiw, "__builtin_spe_evaddiw", SPE_BUILTIN_EVADDIW },
+
+ { 0, CODE_FOR_spe_evrlwi, "__builtin_spe_evrlwi", SPE_BUILTIN_EVRLWI },
+ { 0, CODE_FOR_spe_evslwi, "__builtin_spe_evslwi", SPE_BUILTIN_EVSLWI },
+ { 0, CODE_FOR_spe_evsrwis, "__builtin_spe_evsrwis", SPE_BUILTIN_EVSRWIS },
+ { 0, CODE_FOR_spe_evsrwiu, "__builtin_spe_evsrwiu", SPE_BUILTIN_EVSRWIU },
+ { 0, CODE_FOR_spe_evsubifw, "__builtin_spe_evsubifw", SPE_BUILTIN_EVSUBIFW },
+ { 0, CODE_FOR_spe_evmwhssfaa, "__builtin_spe_evmwhssfaa", SPE_BUILTIN_EVMWHSSFAA },
+ { 0, CODE_FOR_spe_evmwhssmaa, "__builtin_spe_evmwhssmaa", SPE_BUILTIN_EVMWHSSMAA },
+ { 0, CODE_FOR_spe_evmwhsmfaa, "__builtin_spe_evmwhsmfaa", SPE_BUILTIN_EVMWHSMFAA },
+ { 0, CODE_FOR_spe_evmwhsmiaa, "__builtin_spe_evmwhsmiaa", SPE_BUILTIN_EVMWHSMIAA },
+ { 0, CODE_FOR_spe_evmwhusiaa, "__builtin_spe_evmwhusiaa", SPE_BUILTIN_EVMWHUSIAA },
+ { 0, CODE_FOR_spe_evmwhumiaa, "__builtin_spe_evmwhumiaa", SPE_BUILTIN_EVMWHUMIAA },
+ { 0, CODE_FOR_spe_evmwhssfan, "__builtin_spe_evmwhssfan", SPE_BUILTIN_EVMWHSSFAN },
+ { 0, CODE_FOR_spe_evmwhssian, "__builtin_spe_evmwhssian", SPE_BUILTIN_EVMWHSSIAN },
+ { 0, CODE_FOR_spe_evmwhsmfan, "__builtin_spe_evmwhsmfan", SPE_BUILTIN_EVMWHSMFAN },
+ { 0, CODE_FOR_spe_evmwhsmian, "__builtin_spe_evmwhsmian", SPE_BUILTIN_EVMWHSMIAN },
+ { 0, CODE_FOR_spe_evmwhusian, "__builtin_spe_evmwhusian", SPE_BUILTIN_EVMWHUSIAN },
+ { 0, CODE_FOR_spe_evmwhumian, "__builtin_spe_evmwhumian", SPE_BUILTIN_EVMWHUMIAN },
+ { 0, CODE_FOR_spe_evmwhgssfaa, "__builtin_spe_evmwhgssfaa", SPE_BUILTIN_EVMWHGSSFAA },
+ { 0, CODE_FOR_spe_evmwhgsmfaa, "__builtin_spe_evmwhgsmfaa", SPE_BUILTIN_EVMWHGSMFAA },
+ { 0, CODE_FOR_spe_evmwhgsmiaa, "__builtin_spe_evmwhgsmiaa", SPE_BUILTIN_EVMWHGSMIAA },
+ { 0, CODE_FOR_spe_evmwhgumiaa, "__builtin_spe_evmwhgumiaa", SPE_BUILTIN_EVMWHGUMIAA },
+ { 0, CODE_FOR_spe_evmwhgssfan, "__builtin_spe_evmwhgssfan", SPE_BUILTIN_EVMWHGSSFAN },
+ { 0, CODE_FOR_spe_evmwhgsmfan, "__builtin_spe_evmwhgsmfan", SPE_BUILTIN_EVMWHGSMFAN },
+ { 0, CODE_FOR_spe_evmwhgsmian, "__builtin_spe_evmwhgsmian", SPE_BUILTIN_EVMWHGSMIAN },
+ { 0, CODE_FOR_spe_evmwhgumian, "__builtin_spe_evmwhgumian", SPE_BUILTIN_EVMWHGUMIAN },
+ { 0, CODE_FOR_spe_brinc, "__builtin_spe_brinc", SPE_BUILTIN_BRINC },
+
+ /* Place-holder. Leave as last binary SPE builtin. */
+ { 0, CODE_FOR_spe_evxor, "__builtin_spe_evxor", SPE_BUILTIN_EVXOR },
};
/* AltiVec predicates. */
@@ -3470,6 +4063,42 @@ static const struct builtin_description_predicates bdesc_altivec_preds[] =
{ MASK_ALTIVEC, CODE_FOR_altivec_predicate_v16qi, "*vcmpgtub.", "__builtin_altivec_vcmpgtub_p", ALTIVEC_BUILTIN_VCMPGTUB_P }
};
+/* SPE predicates. */
+static struct builtin_description bdesc_spe_predicates[] =
+{
+ /* Place-holder. Leave as first. */
+ { 0, CODE_FOR_spe_evcmpeq, "__builtin_spe_evcmpeq", SPE_BUILTIN_EVCMPEQ },
+ { 0, CODE_FOR_spe_evcmpgts, "__builtin_spe_evcmpgts", SPE_BUILTIN_EVCMPGTS },
+ { 0, CODE_FOR_spe_evcmpgtu, "__builtin_spe_evcmpgtu", SPE_BUILTIN_EVCMPGTU },
+ { 0, CODE_FOR_spe_evcmplts, "__builtin_spe_evcmplts", SPE_BUILTIN_EVCMPLTS },
+ { 0, CODE_FOR_spe_evcmpltu, "__builtin_spe_evcmpltu", SPE_BUILTIN_EVCMPLTU },
+ { 0, CODE_FOR_spe_evfscmpeq, "__builtin_spe_evfscmpeq", SPE_BUILTIN_EVFSCMPEQ },
+ { 0, CODE_FOR_spe_evfscmpgt, "__builtin_spe_evfscmpgt", SPE_BUILTIN_EVFSCMPGT },
+ { 0, CODE_FOR_spe_evfscmplt, "__builtin_spe_evfscmplt", SPE_BUILTIN_EVFSCMPLT },
+ { 0, CODE_FOR_spe_evfststeq, "__builtin_spe_evfststeq", SPE_BUILTIN_EVFSTSTEQ },
+ { 0, CODE_FOR_spe_evfststgt, "__builtin_spe_evfststgt", SPE_BUILTIN_EVFSTSTGT },
+ /* Place-holder. Leave as last. */
+ { 0, CODE_FOR_spe_evfststlt, "__builtin_spe_evfststlt", SPE_BUILTIN_EVFSTSTLT },
+};
+
+/* SPE evsel predicates. */
+static struct builtin_description bdesc_spe_evsel[] =
+{
+ /* Place-holder. Leave as first. */
+ { 0, CODE_FOR_spe_evcmpgts, "__builtin_spe_evsel_gts", SPE_BUILTIN_EVSEL_CMPGTS },
+ { 0, CODE_FOR_spe_evcmpgtu, "__builtin_spe_evsel_gtu", SPE_BUILTIN_EVSEL_CMPGTU },
+ { 0, CODE_FOR_spe_evcmplts, "__builtin_spe_evsel_lts", SPE_BUILTIN_EVSEL_CMPLTS },
+ { 0, CODE_FOR_spe_evcmpltu, "__builtin_spe_evsel_ltu", SPE_BUILTIN_EVSEL_CMPLTU },
+ { 0, CODE_FOR_spe_evcmpeq, "__builtin_spe_evsel_eq", SPE_BUILTIN_EVSEL_CMPEQ },
+ { 0, CODE_FOR_spe_evfscmpgt, "__builtin_spe_evsel_fsgt", SPE_BUILTIN_EVSEL_FSCMPGT },
+ { 0, CODE_FOR_spe_evfscmplt, "__builtin_spe_evsel_fslt", SPE_BUILTIN_EVSEL_FSCMPLT },
+ { 0, CODE_FOR_spe_evfscmpeq, "__builtin_spe_evsel_fseq", SPE_BUILTIN_EVSEL_FSCMPEQ },
+ { 0, CODE_FOR_spe_evfststgt, "__builtin_spe_evsel_fststgt", SPE_BUILTIN_EVSEL_FSTSTGT },
+ { 0, CODE_FOR_spe_evfststlt, "__builtin_spe_evsel_fststlt", SPE_BUILTIN_EVSEL_FSTSTLT },
+ /* Place-holder. Leave as last. */
+ { 0, CODE_FOR_spe_evfststeq, "__builtin_spe_evsel_fststeq", SPE_BUILTIN_EVSEL_FSTSTEQ },
+};
+
/* ABS* opreations. */
static const struct builtin_description bdesc_abs[] =
@@ -3486,7 +4115,7 @@ static const struct builtin_description bdesc_abs[] =
/* Simple unary operations: VECb = foo (unsigned literal) or VECb =
foo (VECa). */
-static const struct builtin_description bdesc_1arg[] =
+static struct builtin_description bdesc_1arg[] =
{
{ MASK_ALTIVEC, CODE_FOR_altivec_vexptefp, "__builtin_altivec_vexptefp", ALTIVEC_BUILTIN_VEXPTEFP },
{ MASK_ALTIVEC, CODE_FOR_altivec_vlogefp, "__builtin_altivec_vlogefp", ALTIVEC_BUILTIN_VLOGEFP },
@@ -3505,10 +4134,46 @@ static const struct builtin_description bdesc_1arg[] =
{ MASK_ALTIVEC, CODE_FOR_altivec_vupklsb, "__builtin_altivec_vupklsb", ALTIVEC_BUILTIN_VUPKLSB },
{ MASK_ALTIVEC, CODE_FOR_altivec_vupklpx, "__builtin_altivec_vupklpx", ALTIVEC_BUILTIN_VUPKLPX },
{ MASK_ALTIVEC, CODE_FOR_altivec_vupklsh, "__builtin_altivec_vupklsh", ALTIVEC_BUILTIN_VUPKLSH },
+
+ /* The SPE unary builtins must start with SPE_BUILTIN_EVABS and
+ end with SPE_BUILTIN_EVSUBFUSIAAW. */
+ { 0, CODE_FOR_spe_evabs, "__builtin_spe_evabs", SPE_BUILTIN_EVABS },
+ { 0, CODE_FOR_spe_evaddsmiaaw, "__builtin_spe_evaddsmiaaw", SPE_BUILTIN_EVADDSMIAAW },
+ { 0, CODE_FOR_spe_evaddssiaaw, "__builtin_spe_evaddssiaaw", SPE_BUILTIN_EVADDSSIAAW },
+ { 0, CODE_FOR_spe_evaddumiaaw, "__builtin_spe_evaddumiaaw", SPE_BUILTIN_EVADDUMIAAW },
+ { 0, CODE_FOR_spe_evaddusiaaw, "__builtin_spe_evaddusiaaw", SPE_BUILTIN_EVADDUSIAAW },
+ { 0, CODE_FOR_spe_evcntlsw, "__builtin_spe_evcntlsw", SPE_BUILTIN_EVCNTLSW },
+ { 0, CODE_FOR_spe_evcntlzw, "__builtin_spe_evcntlzw", SPE_BUILTIN_EVCNTLZW },
+ { 0, CODE_FOR_spe_evextsb, "__builtin_spe_evextsb", SPE_BUILTIN_EVEXTSB },
+ { 0, CODE_FOR_spe_evextsh, "__builtin_spe_evextsh", SPE_BUILTIN_EVEXTSH },
+ { 0, CODE_FOR_spe_evfsabs, "__builtin_spe_evfsabs", SPE_BUILTIN_EVFSABS },
+ { 0, CODE_FOR_spe_evfscfsf, "__builtin_spe_evfscfsf", SPE_BUILTIN_EVFSCFSF },
+ { 0, CODE_FOR_spe_evfscfsi, "__builtin_spe_evfscfsi", SPE_BUILTIN_EVFSCFSI },
+ { 0, CODE_FOR_spe_evfscfuf, "__builtin_spe_evfscfuf", SPE_BUILTIN_EVFSCFUF },
+ { 0, CODE_FOR_spe_evfscfui, "__builtin_spe_evfscfui", SPE_BUILTIN_EVFSCFUI },
+ { 0, CODE_FOR_spe_evfsctsf, "__builtin_spe_evfsctsf", SPE_BUILTIN_EVFSCTSF },
+ { 0, CODE_FOR_spe_evfsctsi, "__builtin_spe_evfsctsi", SPE_BUILTIN_EVFSCTSI },
+ { 0, CODE_FOR_spe_evfsctsiz, "__builtin_spe_evfsctsiz", SPE_BUILTIN_EVFSCTSIZ },
+ { 0, CODE_FOR_spe_evfsctuf, "__builtin_spe_evfsctuf", SPE_BUILTIN_EVFSCTUF },
+ { 0, CODE_FOR_spe_evfsctui, "__builtin_spe_evfsctui", SPE_BUILTIN_EVFSCTUI },
+ { 0, CODE_FOR_spe_evfsctuiz, "__builtin_spe_evfsctuiz", SPE_BUILTIN_EVFSCTUIZ },
+ { 0, CODE_FOR_spe_evfsnabs, "__builtin_spe_evfsnabs", SPE_BUILTIN_EVFSNABS },
+ { 0, CODE_FOR_spe_evfsneg, "__builtin_spe_evfsneg", SPE_BUILTIN_EVFSNEG },
+ { 0, CODE_FOR_spe_evmra, "__builtin_spe_evmra", SPE_BUILTIN_EVMRA },
+ { 0, CODE_FOR_spe_evneg, "__builtin_spe_evneg", SPE_BUILTIN_EVNEG },
+ { 0, CODE_FOR_spe_evrndw, "__builtin_spe_evrndw", SPE_BUILTIN_EVRNDW },
+ { 0, CODE_FOR_spe_evsubfsmiaaw, "__builtin_spe_evsubfsmiaaw", SPE_BUILTIN_EVSUBFSMIAAW },
+ { 0, CODE_FOR_spe_evsubfssiaaw, "__builtin_spe_evsubfssiaaw", SPE_BUILTIN_EVSUBFSSIAAW },
+ { 0, CODE_FOR_spe_evsubfumiaaw, "__builtin_spe_evsubfumiaaw", SPE_BUILTIN_EVSUBFUMIAAW },
+ { 0, CODE_FOR_spe_evsplatfi, "__builtin_spe_evsplatfi", SPE_BUILTIN_EVSPLATFI },
+ { 0, CODE_FOR_spe_evsplati, "__builtin_spe_evsplati", SPE_BUILTIN_EVSPLATI },
+
+ /* Place-holder. Leave as last unary SPE builtin. */
+ { 0, CODE_FOR_spe_evsubfusiaaw, "__builtin_spe_evsubfusiaaw", SPE_BUILTIN_EVSUBFUSIAAW },
};
static rtx
-altivec_expand_unop_builtin (icode, arglist, target)
+rs6000_expand_unop_builtin (icode, arglist, target)
enum insn_code icode;
tree arglist;
rtx target;
@@ -3519,9 +4184,29 @@ altivec_expand_unop_builtin (icode, arglist, target)
enum machine_mode tmode = insn_data[icode].operand[0].mode;
enum machine_mode mode0 = insn_data[icode].operand[1].mode;
+ if (icode == CODE_FOR_nothing)
+ /* Builtin not supported on this processor. */
+ return 0;
+
/* If we got invalid arguments bail out before generating bad rtl. */
if (arg0 == error_mark_node)
- return NULL_RTX;
+ return const0_rtx;
+
+ if (icode == CODE_FOR_altivec_vspltisb
+ || icode == CODE_FOR_altivec_vspltish
+ || icode == CODE_FOR_altivec_vspltisw
+ || icode == CODE_FOR_spe_evsplatfi
+ || icode == CODE_FOR_spe_evsplati)
+ {
+ /* Only allow 5-bit *signed* literals. */
+ if (GET_CODE (op0) != CONST_INT
+ || INTVAL (op0) > 0x1f
+ || INTVAL (op0) < -0x1f)
+ {
+ error ("argument 1 must be a 5-bit signed literal");
+ return const0_rtx;
+ }
+ }
if (target == 0
|| GET_MODE (target) != tmode
@@ -3553,7 +4238,7 @@ altivec_expand_abs_builtin (icode, arglist, target)
/* If we have invalid arguments, bail out before generating bad rtl. */
if (arg0 == error_mark_node)
- return NULL_RTX;
+ return const0_rtx;
if (target == 0
|| GET_MODE (target) != tmode
@@ -3575,7 +4260,7 @@ altivec_expand_abs_builtin (icode, arglist, target)
}
static rtx
-altivec_expand_binop_builtin (icode, arglist, target)
+rs6000_expand_binop_builtin (icode, arglist, target)
enum insn_code icode;
tree arglist;
rtx target;
@@ -3589,9 +4274,46 @@ altivec_expand_binop_builtin (icode, arglist, target)
enum machine_mode mode0 = insn_data[icode].operand[1].mode;
enum machine_mode mode1 = insn_data[icode].operand[2].mode;
+ if (icode == CODE_FOR_nothing)
+ /* Builtin not supported on this processor. */
+ return 0;
+
/* If we got invalid arguments bail out before generating bad rtl. */
if (arg0 == error_mark_node || arg1 == error_mark_node)
- return NULL_RTX;
+ return const0_rtx;
+
+ if (icode == CODE_FOR_altivec_vcfux
+ || icode == CODE_FOR_altivec_vcfsx
+ || icode == CODE_FOR_altivec_vctsxs
+ || icode == CODE_FOR_altivec_vctuxs
+ || icode == CODE_FOR_altivec_vspltb
+ || icode == CODE_FOR_altivec_vsplth
+ || icode == CODE_FOR_altivec_vspltw
+ || icode == CODE_FOR_spe_evaddiw
+ || icode == CODE_FOR_spe_evldd
+ || icode == CODE_FOR_spe_evldh
+ || icode == CODE_FOR_spe_evldw
+ || icode == CODE_FOR_spe_evlhhesplat
+ || icode == CODE_FOR_spe_evlhhossplat
+ || icode == CODE_FOR_spe_evlhhousplat
+ || icode == CODE_FOR_spe_evlwhe
+ || icode == CODE_FOR_spe_evlwhos
+ || icode == CODE_FOR_spe_evlwhou
+ || icode == CODE_FOR_spe_evlwhsplat
+ || icode == CODE_FOR_spe_evlwwsplat
+ || icode == CODE_FOR_spe_evrlwi
+ || icode == CODE_FOR_spe_evslwi
+ || icode == CODE_FOR_spe_evsrwis
+ || icode == CODE_FOR_spe_evsrwiu)
+ {
+ /* Only allow 5-bit unsigned literals. */
+ if (TREE_CODE (arg1) != INTEGER_CST
+ || TREE_INT_CST_LOW (arg1) & ~0x1f)
+ {
+ error ("argument 2 must be a 5-bit unsigned literal");
+ return const0_rtx;
+ }
+ }
if (target == 0
|| GET_MODE (target) != tmode
@@ -3632,7 +4354,7 @@ altivec_expand_predicate_builtin (icode, opcode, arglist, target)
if (TREE_CODE (cr6_form) != INTEGER_CST)
{
error ("argument 1 of __builtin_altivec_predicate must be a constant");
- return NULL_RTX;
+ return const0_rtx;
}
else
cr6_form_int = TREE_INT_CST_LOW (cr6_form);
@@ -3642,7 +4364,7 @@ altivec_expand_predicate_builtin (icode, opcode, arglist, target)
/* If we have invalid arguments, bail out before generating bad rtl. */
if (arg0 == error_mark_node || arg1 == error_mark_node)
- return NULL_RTX;
+ return const0_rtx;
if (target == 0
|| GET_MODE (target) != tmode
@@ -3712,7 +4434,7 @@ altivec_expand_stv_builtin (icode, arglist)
if (arg0 == error_mark_node
|| arg1 == error_mark_node
|| arg2 == error_mark_node)
- return NULL_RTX;
+ return const0_rtx;
if (! (*insn_data[icode].operand[2].predicate) (op0, mode2))
op0 = copy_to_mode_reg (mode2, op0);
@@ -3728,7 +4450,7 @@ altivec_expand_stv_builtin (icode, arglist)
}
static rtx
-altivec_expand_ternop_builtin (icode, arglist, target)
+rs6000_expand_ternop_builtin (icode, arglist, target)
enum insn_code icode;
tree arglist;
rtx target;
@@ -3745,11 +4467,29 @@ altivec_expand_ternop_builtin (icode, arglist, target)
enum machine_mode mode1 = insn_data[icode].operand[2].mode;
enum machine_mode mode2 = insn_data[icode].operand[3].mode;
+ if (icode == CODE_FOR_nothing)
+ /* Builtin not supported on this processor. */
+ return 0;
+
/* If we got invalid arguments bail out before generating bad rtl. */
if (arg0 == error_mark_node
|| arg1 == error_mark_node
|| arg2 == error_mark_node)
- return NULL_RTX;
+ return const0_rtx;
+
+ if (icode == CODE_FOR_altivec_vsldoi_4sf
+ || icode == CODE_FOR_altivec_vsldoi_4si
+ || icode == CODE_FOR_altivec_vsldoi_8hi
+ || icode == CODE_FOR_altivec_vsldoi_16qi)
+ {
+ /* Only allow 4-bit unsigned literals. */
+ if (TREE_CODE (arg2) != INTEGER_CST
+ || TREE_INT_CST_LOW (arg2) & ~0xf)
+ {
+ error ("argument 3 must be a 4-bit unsigned literal");
+ return const0_rtx;
+ }
+ }
if (target == 0
|| GET_MODE (target) != tmode
@@ -3770,184 +4510,214 @@ altivec_expand_ternop_builtin (icode, arglist, target)
return target;
}
+
+/* Expand the lvx builtins. */
static rtx
-altivec_expand_builtin (exp, target)
+altivec_expand_ld_builtin (exp, target, expandedp)
tree exp;
rtx target;
+ bool *expandedp;
{
- struct builtin_description *d;
- struct builtin_description_predicates *dp;
- size_t i;
- enum insn_code icode;
tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
tree arglist = TREE_OPERAND (exp, 1);
- tree arg0, arg1, arg2;
- rtx op0, op1, op2, pat;
- enum machine_mode tmode, mode0, mode1, mode2;
unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
-
+ tree arg0;
+ enum machine_mode tmode, mode0;
+ rtx pat, op0;
+ enum insn_code icode;
+
switch (fcode)
{
case ALTIVEC_BUILTIN_LD_INTERNAL_16qi:
icode = CODE_FOR_altivec_lvx_16qi;
- arg0 = TREE_VALUE (arglist);
- op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
- tmode = insn_data[icode].operand[0].mode;
- mode0 = insn_data[icode].operand[1].mode;
-
- if (target == 0
- || GET_MODE (target) != tmode
- || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
- target = gen_reg_rtx (tmode);
-
- if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
- op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
-
- pat = GEN_FCN (icode) (target, op0);
- if (! pat)
- return 0;
- emit_insn (pat);
- return target;
-
+ break;
case ALTIVEC_BUILTIN_LD_INTERNAL_8hi:
icode = CODE_FOR_altivec_lvx_8hi;
- arg0 = TREE_VALUE (arglist);
- op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
- tmode = insn_data[icode].operand[0].mode;
- mode0 = insn_data[icode].operand[1].mode;
+ break;
+ case ALTIVEC_BUILTIN_LD_INTERNAL_4si:
+ icode = CODE_FOR_altivec_lvx_4si;
+ break;
+ case ALTIVEC_BUILTIN_LD_INTERNAL_4sf:
+ icode = CODE_FOR_altivec_lvx_4sf;
+ break;
+ default:
+ *expandedp = false;
+ return NULL_RTX;
+ }
- if (target == 0
- || GET_MODE (target) != tmode
- || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
- target = gen_reg_rtx (tmode);
+ *expandedp = true;
- if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
- op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
+ arg0 = TREE_VALUE (arglist);
+ op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
+ tmode = insn_data[icode].operand[0].mode;
+ mode0 = insn_data[icode].operand[1].mode;
- pat = GEN_FCN (icode) (target, op0);
- if (! pat)
- return 0;
- emit_insn (pat);
- return target;
+ if (target == 0
+ || GET_MODE (target) != tmode
+ || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
+ target = gen_reg_rtx (tmode);
- case ALTIVEC_BUILTIN_LD_INTERNAL_4si:
- icode = CODE_FOR_altivec_lvx_4si;
- arg0 = TREE_VALUE (arglist);
- op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
- tmode = insn_data[icode].operand[0].mode;
- mode0 = insn_data[icode].operand[1].mode;
+ if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
+ op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
- if (target == 0
- || GET_MODE (target) != tmode
- || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
- target = gen_reg_rtx (tmode);
+ pat = GEN_FCN (icode) (target, op0);
+ if (! pat)
+ return 0;
+ emit_insn (pat);
+ return target;
+}
- if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
- op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
+/* Expand the stvx builtins. */
+static rtx
+altivec_expand_st_builtin (exp, target, expandedp)
+ tree exp;
+ rtx target ATTRIBUTE_UNUSED;
+ bool *expandedp;
+{
+ tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
+ tree arglist = TREE_OPERAND (exp, 1);
+ unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
+ tree arg0, arg1;
+ enum machine_mode mode0, mode1;
+ rtx pat, op0, op1;
+ enum insn_code icode;
- pat = GEN_FCN (icode) (target, op0);
- if (! pat)
- return 0;
- emit_insn (pat);
- return target;
+ switch (fcode)
+ {
+ case ALTIVEC_BUILTIN_ST_INTERNAL_16qi:
+ icode = CODE_FOR_altivec_stvx_16qi;
+ break;
+ case ALTIVEC_BUILTIN_ST_INTERNAL_8hi:
+ icode = CODE_FOR_altivec_stvx_8hi;
+ break;
+ case ALTIVEC_BUILTIN_ST_INTERNAL_4si:
+ icode = CODE_FOR_altivec_stvx_4si;
+ break;
+ case ALTIVEC_BUILTIN_ST_INTERNAL_4sf:
+ icode = CODE_FOR_altivec_stvx_4sf;
+ break;
+ default:
+ *expandedp = false;
+ return NULL_RTX;
+ }
- case ALTIVEC_BUILTIN_LD_INTERNAL_4sf:
- icode = CODE_FOR_altivec_lvx_4sf;
- arg0 = TREE_VALUE (arglist);
- op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
- tmode = insn_data[icode].operand[0].mode;
- mode0 = insn_data[icode].operand[1].mode;
+ arg0 = TREE_VALUE (arglist);
+ arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+ op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
+ op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
+ mode0 = insn_data[icode].operand[0].mode;
+ mode1 = insn_data[icode].operand[1].mode;
- if (target == 0
- || GET_MODE (target) != tmode
- || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
- target = gen_reg_rtx (tmode);
+ if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
+ op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
+ if (! (*insn_data[icode].operand[1].predicate) (op1, mode1))
+ op1 = copy_to_mode_reg (mode1, op1);
- if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
- op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
+ pat = GEN_FCN (icode) (op0, op1);
+ if (pat)
+ emit_insn (pat);
- pat = GEN_FCN (icode) (target, op0);
- if (! pat)
- return 0;
- emit_insn (pat);
- return target;
+ *expandedp = true;
+ return NULL_RTX;
+}
- case ALTIVEC_BUILTIN_ST_INTERNAL_16qi:
- icode = CODE_FOR_altivec_stvx_16qi;
- arg0 = TREE_VALUE (arglist);
- arg1 = TREE_VALUE (TREE_CHAIN (arglist));
- op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
- op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
- mode0 = insn_data[icode].operand[0].mode;
- mode1 = insn_data[icode].operand[1].mode;
+/* Expand the dst builtins. */
+static rtx
+altivec_expand_dst_builtin (exp, target, expandedp)
+ tree exp;
+ rtx target ATTRIBUTE_UNUSED;
+ bool *expandedp;
+{
+ tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
+ tree arglist = TREE_OPERAND (exp, 1);
+ unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
+ tree arg0, arg1, arg2;
+ enum machine_mode mode0, mode1, mode2;
+ rtx pat, op0, op1, op2;
+ struct builtin_description *d;
+ size_t i;
- if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
- op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
- if (! (*insn_data[icode].operand[1].predicate) (op1, mode1))
- op1 = copy_to_mode_reg (mode1, op1);
+ *expandedp = false;
- pat = GEN_FCN (icode) (op0, op1);
- if (pat)
- emit_insn (pat);
- return NULL_RTX;
+ /* Handle DST variants. */
+ d = (struct builtin_description *) bdesc_dst;
+ for (i = 0; i < ARRAY_SIZE (bdesc_dst); i++, d++)
+ if (d->code == fcode)
+ {
+ arg0 = TREE_VALUE (arglist);
+ arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+ arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+ op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
+ op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
+ op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
+ mode0 = insn_data[d->icode].operand[0].mode;
+ mode1 = insn_data[d->icode].operand[1].mode;
+ mode2 = insn_data[d->icode].operand[2].mode;
- case ALTIVEC_BUILTIN_ST_INTERNAL_8hi:
- icode = CODE_FOR_altivec_stvx_8hi;
- arg0 = TREE_VALUE (arglist);
- arg1 = TREE_VALUE (TREE_CHAIN (arglist));
- op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
- op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
- mode0 = insn_data[icode].operand[0].mode;
- mode1 = insn_data[icode].operand[1].mode;
+ /* Invalid arguments, bail out before generating bad rtl. */
+ if (arg0 == error_mark_node
+ || arg1 == error_mark_node
+ || arg2 == error_mark_node)
+ return const0_rtx;
- if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
- op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
- if (! (*insn_data[icode].operand[1].predicate) (op1, mode1))
- op1 = copy_to_mode_reg (mode1, op1);
+ if (TREE_CODE (arg2) != INTEGER_CST
+ || TREE_INT_CST_LOW (arg2) & ~0x3)
+ {
+ error ("argument to `%s' must be a 2-bit unsigned literal", d->name);
+ return const0_rtx;
+ }
- pat = GEN_FCN (icode) (op0, op1);
- if (pat)
- emit_insn (pat);
- return NULL_RTX;
+ if (! (*insn_data[d->icode].operand[0].predicate) (op0, mode0))
+ op0 = copy_to_mode_reg (mode0, op0);
+ if (! (*insn_data[d->icode].operand[1].predicate) (op1, mode1))
+ op1 = copy_to_mode_reg (mode1, op1);
- case ALTIVEC_BUILTIN_ST_INTERNAL_4si:
- icode = CODE_FOR_altivec_stvx_4si;
- arg0 = TREE_VALUE (arglist);
- arg1 = TREE_VALUE (TREE_CHAIN (arglist));
- op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
- op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
- mode0 = insn_data[icode].operand[0].mode;
- mode1 = insn_data[icode].operand[1].mode;
+ pat = GEN_FCN (d->icode) (op0, op1, op2);
+ if (pat != 0)
+ emit_insn (pat);
- if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
- op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
- if (! (*insn_data[icode].operand[1].predicate) (op1, mode1))
- op1 = copy_to_mode_reg (mode1, op1);
+ *expandedp = true;
+ return NULL_RTX;
+ }
- pat = GEN_FCN (icode) (op0, op1);
- if (pat)
- emit_insn (pat);
- return NULL_RTX;
+ return NULL_RTX;
+}
- case ALTIVEC_BUILTIN_ST_INTERNAL_4sf:
- icode = CODE_FOR_altivec_stvx_4sf;
- arg0 = TREE_VALUE (arglist);
- arg1 = TREE_VALUE (TREE_CHAIN (arglist));
- op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
- op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
- mode0 = insn_data[icode].operand[0].mode;
- mode1 = insn_data[icode].operand[1].mode;
+/* Expand the builtin in EXP and store the result in TARGET. Store
+ true in *EXPANDEDP if we found a builtin to expand. */
+static rtx
+altivec_expand_builtin (exp, target, expandedp)
+ tree exp;
+ rtx target;
+ bool *expandedp;
+{
+ struct builtin_description *d;
+ struct builtin_description_predicates *dp;
+ size_t i;
+ enum insn_code icode;
+ tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
+ tree arglist = TREE_OPERAND (exp, 1);
+ tree arg0;
+ rtx op0, pat;
+ enum machine_mode tmode, mode0;
+ unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
- if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
- op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
- if (! (*insn_data[icode].operand[1].predicate) (op1, mode1))
- op1 = copy_to_mode_reg (mode1, op1);
+ target = altivec_expand_ld_builtin (exp, target, expandedp);
+ if (*expandedp)
+ return target;
- pat = GEN_FCN (icode) (op0, op1);
- if (pat)
- emit_insn (pat);
- return NULL_RTX;
+ target = altivec_expand_st_builtin (exp, target, expandedp);
+ if (*expandedp)
+ return target;
+
+ target = altivec_expand_dst_builtin (exp, target, expandedp);
+ if (*expandedp)
+ return target;
+
+ *expandedp = true;
+ switch (fcode)
+ {
case ALTIVEC_BUILTIN_STVX:
return altivec_expand_stv_builtin (CODE_FOR_altivec_stvx, arglist);
case ALTIVEC_BUILTIN_STVEBX:
@@ -3958,7 +4728,7 @@ altivec_expand_builtin (exp, target)
return altivec_expand_stv_builtin (CODE_FOR_altivec_stvewx, arglist);
case ALTIVEC_BUILTIN_STVXL:
return altivec_expand_stv_builtin (CODE_FOR_altivec_stvxl, arglist);
-
+
case ALTIVEC_BUILTIN_MFVSCR:
icode = CODE_FOR_altivec_mfvscr;
tmode = insn_data[icode].operand[0].mode;
@@ -3982,7 +4752,7 @@ altivec_expand_builtin (exp, target)
/* If we got invalid arguments bail out before generating bad rtl. */
if (arg0 == error_mark_node)
- return NULL_RTX;
+ return const0_rtx;
if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
op0 = copy_to_mode_reg (mode0, op0);
@@ -3991,7 +4761,7 @@ altivec_expand_builtin (exp, target)
if (pat)
emit_insn (pat);
return NULL_RTX;
-
+
case ALTIVEC_BUILTIN_DSSALL:
emit_insn (gen_altivec_dssall ());
return NULL_RTX;
@@ -4004,7 +4774,14 @@ altivec_expand_builtin (exp, target)
/* If we got invalid arguments bail out before generating bad rtl. */
if (arg0 == error_mark_node)
- return NULL_RTX;
+ return const0_rtx;
+
+ if (TREE_CODE (arg0) != INTEGER_CST
+ || TREE_INT_CST_LOW (arg0) & ~0x3)
+ {
+ error ("argument to dss must be a 2-bit unsigned literal");
+ return const0_rtx;
+ }
if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
op0 = copy_to_mode_reg (mode0, op0);
@@ -4013,66 +4790,15 @@ altivec_expand_builtin (exp, target)
return NULL_RTX;
}
- /* Handle DST variants. */
- d = (struct builtin_description *) bdesc_dst;
- for (i = 0; i < sizeof (bdesc_dst) / sizeof *d; i++, d++)
- if (d->code == fcode)
- {
- arg0 = TREE_VALUE (arglist);
- arg1 = TREE_VALUE (TREE_CHAIN (arglist));
- arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
- op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
- op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
- op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
- mode0 = insn_data[d->icode].operand[0].mode;
- mode1 = insn_data[d->icode].operand[1].mode;
- mode2 = insn_data[d->icode].operand[2].mode;
-
- /* Invalid arguments, bail out before generating bad rtl. */
- if (arg0 == error_mark_node
- || arg1 == error_mark_node
- || arg2 == error_mark_node)
- return NULL_RTX;
-
- if (! (*insn_data[d->icode].operand[0].predicate) (op0, mode0))
- op0 = copy_to_mode_reg (mode0, op0);
- if (! (*insn_data[d->icode].operand[1].predicate) (op1, mode1))
- op1 = copy_to_mode_reg (mode1, op1);
-
- if (GET_CODE (op2) != CONST_INT || INTVAL (op2) > 3)
- {
- error ("argument 3 of `%s' must be a 2-bit literal", d->name);
- return NULL_RTX;
- }
-
- pat = GEN_FCN (d->icode) (op0, op1, op2);
- if (pat != 0)
- emit_insn (pat);
-
- return NULL_RTX;
- }
-
/* Expand abs* operations. */
d = (struct builtin_description *) bdesc_abs;
- for (i = 0; i < sizeof (bdesc_abs) / sizeof *d; i++, d++)
+ for (i = 0; i < ARRAY_SIZE (bdesc_abs); i++, d++)
if (d->code == fcode)
return altivec_expand_abs_builtin (d->icode, arglist, target);
- /* Handle simple unary operations. */
- d = (struct builtin_description *) bdesc_1arg;
- for (i = 0; i < sizeof (bdesc_1arg) / sizeof *d; i++, d++)
- if (d->code == fcode)
- return altivec_expand_unop_builtin (d->icode, arglist, target);
-
- /* Handle simple binary operations. */
- d = (struct builtin_description *) bdesc_2arg;
- for (i = 0; i < sizeof (bdesc_2arg) / sizeof *d; i++, d++)
- if (d->code == fcode)
- return altivec_expand_binop_builtin (d->icode, arglist, target);
-
/* Expand the AltiVec predicates. */
dp = (struct builtin_description_predicates *) bdesc_altivec_preds;
- for (i = 0; i < sizeof (bdesc_altivec_preds) / sizeof *dp; i++, dp++)
+ for (i = 0; i < ARRAY_SIZE (bdesc_altivec_preds); i++, dp++)
if (dp->code == fcode)
return altivec_expand_predicate_builtin (dp->icode, dp->opcode, arglist, target);
@@ -4080,41 +4806,357 @@ altivec_expand_builtin (exp, target)
switch (fcode)
{
case ALTIVEC_BUILTIN_LVSL:
- return altivec_expand_binop_builtin (CODE_FOR_altivec_lvsl,
+ return rs6000_expand_binop_builtin (CODE_FOR_altivec_lvsl,
arglist, target);
case ALTIVEC_BUILTIN_LVSR:
- return altivec_expand_binop_builtin (CODE_FOR_altivec_lvsr,
- arglist, target);
+ return rs6000_expand_binop_builtin (CODE_FOR_altivec_lvsr,
+ arglist, target);
case ALTIVEC_BUILTIN_LVEBX:
- return altivec_expand_binop_builtin (CODE_FOR_altivec_lvebx,
- arglist, target);
+ return rs6000_expand_binop_builtin (CODE_FOR_altivec_lvebx,
+ arglist, target);
case ALTIVEC_BUILTIN_LVEHX:
- return altivec_expand_binop_builtin (CODE_FOR_altivec_lvehx,
- arglist, target);
+ return rs6000_expand_binop_builtin (CODE_FOR_altivec_lvehx,
+ arglist, target);
case ALTIVEC_BUILTIN_LVEWX:
- return altivec_expand_binop_builtin (CODE_FOR_altivec_lvewx,
- arglist, target);
+ return rs6000_expand_binop_builtin (CODE_FOR_altivec_lvewx,
+ arglist, target);
case ALTIVEC_BUILTIN_LVXL:
- return altivec_expand_binop_builtin (CODE_FOR_altivec_lvxl,
- arglist, target);
+ return rs6000_expand_binop_builtin (CODE_FOR_altivec_lvxl,
+ arglist, target);
case ALTIVEC_BUILTIN_LVX:
- return altivec_expand_binop_builtin (CODE_FOR_altivec_lvx,
- arglist, target);
+ return rs6000_expand_binop_builtin (CODE_FOR_altivec_lvx,
+ arglist, target);
default:
break;
/* Fall through. */
}
- /* Handle simple ternary operations. */
- d = (struct builtin_description *) bdesc_3arg;
- for (i = 0; i < sizeof (bdesc_3arg) / sizeof *d; i++, d++)
+ *expandedp = false;
+ return NULL_RTX;
+}
+
+/* Binops that need to be initialized manually, but can be expanded
+ automagically by rs6000_expand_binop_builtin. */
+static struct builtin_description bdesc_2arg_spe[] =
+{
+ { 0, CODE_FOR_spe_evlddx, "__builtin_spe_evlddx", SPE_BUILTIN_EVLDDX },
+ { 0, CODE_FOR_spe_evldwx, "__builtin_spe_evldwx", SPE_BUILTIN_EVLDWX },
+ { 0, CODE_FOR_spe_evldhx, "__builtin_spe_evldhx", SPE_BUILTIN_EVLDHX },
+ { 0, CODE_FOR_spe_evlwhex, "__builtin_spe_evlwhex", SPE_BUILTIN_EVLWHEX },
+ { 0, CODE_FOR_spe_evlwhoux, "__builtin_spe_evlwhoux", SPE_BUILTIN_EVLWHOUX },
+ { 0, CODE_FOR_spe_evlwhosx, "__builtin_spe_evlwhosx", SPE_BUILTIN_EVLWHOSX },
+ { 0, CODE_FOR_spe_evlwwsplatx, "__builtin_spe_evlwwsplatx", SPE_BUILTIN_EVLWWSPLATX },
+ { 0, CODE_FOR_spe_evlwhsplatx, "__builtin_spe_evlwhsplatx", SPE_BUILTIN_EVLWHSPLATX },
+ { 0, CODE_FOR_spe_evlhhesplatx, "__builtin_spe_evlhhesplatx", SPE_BUILTIN_EVLHHESPLATX },
+ { 0, CODE_FOR_spe_evlhhousplatx, "__builtin_spe_evlhhousplatx", SPE_BUILTIN_EVLHHOUSPLATX },
+ { 0, CODE_FOR_spe_evlhhossplatx, "__builtin_spe_evlhhossplatx", SPE_BUILTIN_EVLHHOSSPLATX },
+ { 0, CODE_FOR_spe_evldd, "__builtin_spe_evldd", SPE_BUILTIN_EVLDD },
+ { 0, CODE_FOR_spe_evldw, "__builtin_spe_evldw", SPE_BUILTIN_EVLDW },
+ { 0, CODE_FOR_spe_evldh, "__builtin_spe_evldh", SPE_BUILTIN_EVLDH },
+ { 0, CODE_FOR_spe_evlwhe, "__builtin_spe_evlwhe", SPE_BUILTIN_EVLWHE },
+ { 0, CODE_FOR_spe_evlwhou, "__builtin_spe_evlwhou", SPE_BUILTIN_EVLWHOU },
+ { 0, CODE_FOR_spe_evlwhos, "__builtin_spe_evlwhos", SPE_BUILTIN_EVLWHOS },
+ { 0, CODE_FOR_spe_evlwwsplat, "__builtin_spe_evlwwsplat", SPE_BUILTIN_EVLWWSPLAT },
+ { 0, CODE_FOR_spe_evlwhsplat, "__builtin_spe_evlwhsplat", SPE_BUILTIN_EVLWHSPLAT },
+ { 0, CODE_FOR_spe_evlhhesplat, "__builtin_spe_evlhhesplat", SPE_BUILTIN_EVLHHESPLAT },
+ { 0, CODE_FOR_spe_evlhhousplat, "__builtin_spe_evlhhousplat", SPE_BUILTIN_EVLHHOUSPLAT },
+ { 0, CODE_FOR_spe_evlhhossplat, "__builtin_spe_evlhhossplat", SPE_BUILTIN_EVLHHOSSPLAT }
+};
+
+/* Expand the builtin in EXP and store the result in TARGET. Store
+ true in *EXPANDEDP if we found a builtin to expand.
+
+ This expands the SPE builtins that are not simple unary and binary
+ operations. */
+static rtx
+spe_expand_builtin (exp, target, expandedp)
+ tree exp;
+ rtx target;
+ bool *expandedp;
+{
+ tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
+ tree arglist = TREE_OPERAND (exp, 1);
+ tree arg1, arg0;
+ unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
+ enum insn_code icode;
+ enum machine_mode tmode, mode0;
+ rtx pat, op0;
+ struct builtin_description *d;
+ size_t i;
+
+ *expandedp = true;
+
+ /* Syntax check for a 5-bit unsigned immediate. */
+ switch (fcode)
+ {
+ case SPE_BUILTIN_EVSTDD:
+ case SPE_BUILTIN_EVSTDH:
+ case SPE_BUILTIN_EVSTDW:
+ case SPE_BUILTIN_EVSTWHE:
+ case SPE_BUILTIN_EVSTWHO:
+ case SPE_BUILTIN_EVSTWWE:
+ case SPE_BUILTIN_EVSTWWO:
+ arg1 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+ if (TREE_CODE (arg1) != INTEGER_CST
+ || TREE_INT_CST_LOW (arg1) & ~0x1f)
+ {
+ error ("argument 2 must be a 5-bit unsigned literal");
+ return const0_rtx;
+ }
+ break;
+ default:
+ break;
+ }
+
+ d = (struct builtin_description *) bdesc_2arg_spe;
+ for (i = 0; i < ARRAY_SIZE (bdesc_2arg_spe); ++i, ++d)
if (d->code == fcode)
- return altivec_expand_ternop_builtin (d->icode, arglist, target);
+ return rs6000_expand_binop_builtin (d->icode, arglist, target);
- abort ();
+ d = (struct builtin_description *) bdesc_spe_predicates;
+ for (i = 0; i < ARRAY_SIZE (bdesc_spe_predicates); ++i, ++d)
+ if (d->code == fcode)
+ return spe_expand_predicate_builtin (d->icode, arglist, target);
+
+ d = (struct builtin_description *) bdesc_spe_evsel;
+ for (i = 0; i < ARRAY_SIZE (bdesc_spe_evsel); ++i, ++d)
+ if (d->code == fcode)
+ return spe_expand_evsel_builtin (d->icode, arglist, target);
+
+ switch (fcode)
+ {
+ case SPE_BUILTIN_EVSTDDX:
+ return altivec_expand_stv_builtin (CODE_FOR_spe_evstddx, arglist);
+ case SPE_BUILTIN_EVSTDHX:
+ return altivec_expand_stv_builtin (CODE_FOR_spe_evstdhx, arglist);
+ case SPE_BUILTIN_EVSTDWX:
+ return altivec_expand_stv_builtin (CODE_FOR_spe_evstdwx, arglist);
+ case SPE_BUILTIN_EVSTWHEX:
+ return altivec_expand_stv_builtin (CODE_FOR_spe_evstwhex, arglist);
+ case SPE_BUILTIN_EVSTWHOX:
+ return altivec_expand_stv_builtin (CODE_FOR_spe_evstwhox, arglist);
+ case SPE_BUILTIN_EVSTWWEX:
+ return altivec_expand_stv_builtin (CODE_FOR_spe_evstwwex, arglist);
+ case SPE_BUILTIN_EVSTWWOX:
+ return altivec_expand_stv_builtin (CODE_FOR_spe_evstwwox, arglist);
+ case SPE_BUILTIN_EVSTDD:
+ return altivec_expand_stv_builtin (CODE_FOR_spe_evstdd, arglist);
+ case SPE_BUILTIN_EVSTDH:
+ return altivec_expand_stv_builtin (CODE_FOR_spe_evstdh, arglist);
+ case SPE_BUILTIN_EVSTDW:
+ return altivec_expand_stv_builtin (CODE_FOR_spe_evstdw, arglist);
+ case SPE_BUILTIN_EVSTWHE:
+ return altivec_expand_stv_builtin (CODE_FOR_spe_evstwhe, arglist);
+ case SPE_BUILTIN_EVSTWHO:
+ return altivec_expand_stv_builtin (CODE_FOR_spe_evstwho, arglist);
+ case SPE_BUILTIN_EVSTWWE:
+ return altivec_expand_stv_builtin (CODE_FOR_spe_evstwwe, arglist);
+ case SPE_BUILTIN_EVSTWWO:
+ return altivec_expand_stv_builtin (CODE_FOR_spe_evstwwo, arglist);
+ case SPE_BUILTIN_MFSPEFSCR:
+ icode = CODE_FOR_spe_mfspefscr;
+ tmode = insn_data[icode].operand[0].mode;
+
+ if (target == 0
+ || GET_MODE (target) != tmode
+ || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
+ target = gen_reg_rtx (tmode);
+
+ pat = GEN_FCN (icode) (target);
+ if (! pat)
+ return 0;
+ emit_insn (pat);
+ return target;
+ case SPE_BUILTIN_MTSPEFSCR:
+ icode = CODE_FOR_spe_mtspefscr;
+ arg0 = TREE_VALUE (arglist);
+ op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
+ mode0 = insn_data[icode].operand[0].mode;
+
+ if (arg0 == error_mark_node)
+ return const0_rtx;
+
+ if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
+ op0 = copy_to_mode_reg (mode0, op0);
+
+ pat = GEN_FCN (icode) (op0);
+ if (pat)
+ emit_insn (pat);
+ return NULL_RTX;
+ default:
+ break;
+ }
+
+ *expandedp = false;
return NULL_RTX;
}
+static rtx
+spe_expand_predicate_builtin (icode, arglist, target)
+ enum insn_code icode;
+ tree arglist;
+ rtx target;
+{
+ rtx pat, scratch, tmp;
+ tree form = TREE_VALUE (arglist);
+ tree arg0 = TREE_VALUE (TREE_CHAIN (arglist));
+ tree arg1 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+ rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
+ rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
+ enum machine_mode mode0 = insn_data[icode].operand[1].mode;
+ enum machine_mode mode1 = insn_data[icode].operand[2].mode;
+ int form_int;
+ enum rtx_code code;
+
+ if (TREE_CODE (form) != INTEGER_CST)
+ {
+ error ("argument 1 of __builtin_spe_predicate must be a constant");
+ return const0_rtx;
+ }
+ else
+ form_int = TREE_INT_CST_LOW (form);
+
+ if (mode0 != mode1)
+ abort ();
+
+ if (arg0 == error_mark_node || arg1 == error_mark_node)
+ return const0_rtx;
+
+ if (target == 0
+ || GET_MODE (target) != SImode
+ || ! (*insn_data[icode].operand[0].predicate) (target, SImode))
+ target = gen_reg_rtx (SImode);
+
+ if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
+ op0 = copy_to_mode_reg (mode0, op0);
+ if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
+ op1 = copy_to_mode_reg (mode1, op1);
+
+ scratch = gen_reg_rtx (CCmode);
+
+ pat = GEN_FCN (icode) (scratch, op0, op1);
+ if (! pat)
+ return const0_rtx;
+ emit_insn (pat);
+
+ /* There are 4 variants for each predicate: _any_, _all_, _upper_,
+ _lower_. We use one compare, but look in different bits of the
+ CR for each variant.
+
+ There are 2 elements in each SPE simd type (upper/lower). The CR
+ bits are set as follows:
+
+ BIT0 | BIT 1 | BIT 2 | BIT 3
+ U | L | (U | L) | (U & L)
+
+ So, for an "all" relationship, BIT 3 would be set.
+ For an "any" relationship, BIT 2 would be set. Etc.
+
+ Following traditional nomenclature, these bits map to:
+
+ BIT0 | BIT 1 | BIT 2 | BIT 3
+ LT | GT | EQ | OV
+
+ Later, we will generate rtl to look in the LT/EQ/EQ/OV bits.
+ */
+
+ switch (form_int)
+ {
+ /* All variant. OV bit. */
+ case 0:
+ /* We need to get to the OV bit, which is the ORDERED bit. We
+ could generate (ordered:SI (reg:CC xx) (const_int 0)), but
+ that's ugly and will trigger a validate_condition_mode abort.
+ So let's just use another pattern. */
+ emit_insn (gen_move_from_CR_ov_bit (target, scratch));
+ return target;
+ /* Any variant. EQ bit. */
+ case 1:
+ code = EQ;
+ break;
+ /* Upper variant. LT bit. */
+ case 2:
+ code = LT;
+ break;
+ /* Lower variant. GT bit. */
+ case 3:
+ code = GT;
+ break;
+ default:
+ error ("argument 1 of __builtin_spe_predicate is out of range");
+ return const0_rtx;
+ }
+
+ tmp = gen_rtx_fmt_ee (code, SImode, scratch, const0_rtx);
+ emit_move_insn (target, tmp);
+
+ return target;
+}
+
+/* The evsel builtins look like this:
+
+ e = __builtin_spe_evsel_OP (a, b, c, d);
+
+ and work like this:
+
+ e[upper] = a[upper] *OP* b[upper] ? c[upper] : d[upper];
+ e[lower] = a[lower] *OP* b[lower] ? c[lower] : d[lower];
+*/
+
+static rtx
+spe_expand_evsel_builtin (icode, arglist, target)
+ enum insn_code icode;
+ tree arglist;
+ rtx target;
+{
+ rtx pat, scratch;
+ tree arg0 = TREE_VALUE (arglist);
+ tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+ tree arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+ tree arg3 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (arglist))));
+ rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
+ rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
+ rtx op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
+ rtx op3 = expand_expr (arg3, NULL_RTX, VOIDmode, 0);
+ enum machine_mode mode0 = insn_data[icode].operand[1].mode;
+ enum machine_mode mode1 = insn_data[icode].operand[2].mode;
+
+ if (mode0 != mode1)
+ abort ();
+
+ if (arg0 == error_mark_node || arg1 == error_mark_node
+ || arg2 == error_mark_node || arg3 == error_mark_node)
+ return const0_rtx;
+
+ if (target == 0
+ || GET_MODE (target) != mode0
+ || ! (*insn_data[icode].operand[0].predicate) (target, mode0))
+ target = gen_reg_rtx (mode0);
+
+ if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
+ op0 = copy_to_mode_reg (mode0, op0);
+ if (! (*insn_data[icode].operand[1].predicate) (op1, mode1))
+ op1 = copy_to_mode_reg (mode0, op1);
+ if (! (*insn_data[icode].operand[1].predicate) (op2, mode1))
+ op2 = copy_to_mode_reg (mode0, op2);
+ if (! (*insn_data[icode].operand[1].predicate) (op3, mode1))
+ op3 = copy_to_mode_reg (mode0, op3);
+
+ /* Generate the compare. */
+ scratch = gen_reg_rtx (CCmode);
+ pat = GEN_FCN (icode) (scratch, op0, op1);
+ if (! pat)
+ return const0_rtx;
+ emit_insn (pat);
+
+ if (mode0 == V2SImode)
+ emit_insn (gen_spe_evsel (target, op2, op3, scratch));
+ else
+ emit_insn (gen_spe_evsel_fs (target, op2, op3, scratch));
+
+ return target;
+}
+
/* Expand an expression EXP that calls a built-in function,
with result going to TARGET if that's convenient
(and in mode MODE if that's convenient).
@@ -4129,487 +5171,695 @@ rs6000_expand_builtin (exp, target, subtarget, mode, ignore)
enum machine_mode mode ATTRIBUTE_UNUSED;
int ignore ATTRIBUTE_UNUSED;
{
+ tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
+ tree arglist = TREE_OPERAND (exp, 1);
+ unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
+ struct builtin_description *d;
+ size_t i;
+ rtx ret;
+ bool success;
+
if (TARGET_ALTIVEC)
- return altivec_expand_builtin (exp, target);
+ {
+ ret = altivec_expand_builtin (exp, target, &success);
+
+ if (success)
+ return ret;
+ }
+ if (TARGET_SPE)
+ {
+ ret = spe_expand_builtin (exp, target, &success);
+
+ if (success)
+ return ret;
+ }
+
+ if (TARGET_ALTIVEC || TARGET_SPE)
+ {
+ /* Handle simple unary operations. */
+ d = (struct builtin_description *) bdesc_1arg;
+ for (i = 0; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
+ if (d->code == fcode)
+ return rs6000_expand_unop_builtin (d->icode, arglist, target);
+
+ /* Handle simple binary operations. */
+ d = (struct builtin_description *) bdesc_2arg;
+ for (i = 0; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
+ if (d->code == fcode)
+ return rs6000_expand_binop_builtin (d->icode, arglist, target);
+
+ /* Handle simple ternary operations. */
+ d = (struct builtin_description *) bdesc_3arg;
+ for (i = 0; i < ARRAY_SIZE (bdesc_3arg); i++, d++)
+ if (d->code == fcode)
+ return rs6000_expand_ternop_builtin (d->icode, arglist, target);
+ }
abort ();
+ return NULL_RTX;
}
static void
rs6000_init_builtins ()
{
+ if (TARGET_SPE)
+ spe_init_builtins ();
if (TARGET_ALTIVEC)
altivec_init_builtins ();
+ if (TARGET_ALTIVEC || TARGET_SPE)
+ rs6000_common_init_builtins ();
}
+/* Search through a set of builtins and enable the mask bits.
+ DESC is an array of builtins.
+ SIZE is the totaly number of builtins.
+ START is the builtin enum at which to start.
+ END is the builtin enum at which to end. */
static void
-altivec_init_builtins (void)
+enable_mask_for_builtins (desc, size, start, end)
+ struct builtin_description *desc;
+ int size;
+ enum rs6000_builtins start, end;
{
- struct builtin_description *d;
- struct builtin_description_predicates *dp;
- size_t i;
+ int i;
- tree endlink = void_list_node;
+ for (i = 0; i < size; ++i)
+ if (desc[i].code == start)
+ break;
- tree pint_type_node = build_pointer_type (integer_type_node);
- tree pvoid_type_node = build_pointer_type (void_type_node);
- tree pshort_type_node = build_pointer_type (short_integer_type_node);
- tree pchar_type_node = build_pointer_type (char_type_node);
- tree pfloat_type_node = build_pointer_type (float_type_node);
+ if (i == size)
+ return;
- tree v4sf_ftype_v4sf_v4sf_v16qi
- = build_function_type (V4SF_type_node,
- tree_cons (NULL_TREE, V4SF_type_node,
- tree_cons (NULL_TREE, V4SF_type_node,
- tree_cons (NULL_TREE,
- V16QI_type_node,
- endlink))));
- tree v4si_ftype_v4si_v4si_v16qi
- = build_function_type (V4SI_type_node,
- tree_cons (NULL_TREE, V4SI_type_node,
- tree_cons (NULL_TREE, V4SI_type_node,
- tree_cons (NULL_TREE,
- V16QI_type_node,
- endlink))));
- tree v8hi_ftype_v8hi_v8hi_v16qi
- = build_function_type (V8HI_type_node,
- tree_cons (NULL_TREE, V8HI_type_node,
- tree_cons (NULL_TREE, V8HI_type_node,
- tree_cons (NULL_TREE,
- V16QI_type_node,
- endlink))));
- tree v16qi_ftype_v16qi_v16qi_v16qi
- = build_function_type (V16QI_type_node,
- tree_cons (NULL_TREE, V16QI_type_node,
- tree_cons (NULL_TREE, V16QI_type_node,
- tree_cons (NULL_TREE,
- V16QI_type_node,
- endlink))));
+ for (; i < size; ++i)
+ {
+ /* Flip all the bits on. */
+ desc[i].mask = target_flags;
+ if (desc[i].code == end)
+ break;
+ }
+}
- /* V4SI foo (char). */
- tree v4si_ftype_char
- = build_function_type (V4SI_type_node,
- tree_cons (NULL_TREE, char_type_node, endlink));
+static void
+spe_init_builtins ()
+{
+ tree endlink = void_list_node;
+ tree puint_type_node = build_pointer_type (unsigned_type_node);
+ tree pushort_type_node = build_pointer_type (short_unsigned_type_node);
+ tree pv2si_type_node = build_pointer_type (V2SI_type_node);
+ struct builtin_description *d;
+ size_t i;
- /* V8HI foo (char). */
- tree v8hi_ftype_char
- = build_function_type (V8HI_type_node,
- tree_cons (NULL_TREE, char_type_node, endlink));
+ tree v2si_ftype_4_v2si
+ = build_function_type
+ (V2SI_type_node,
+ tree_cons (NULL_TREE, V2SI_type_node,
+ tree_cons (NULL_TREE, V2SI_type_node,
+ tree_cons (NULL_TREE, V2SI_type_node,
+ tree_cons (NULL_TREE, V2SI_type_node,
+ endlink)))));
+
+ tree v2sf_ftype_4_v2sf
+ = build_function_type
+ (V2SF_type_node,
+ tree_cons (NULL_TREE, V2SF_type_node,
+ tree_cons (NULL_TREE, V2SF_type_node,
+ tree_cons (NULL_TREE, V2SF_type_node,
+ tree_cons (NULL_TREE, V2SF_type_node,
+ endlink)))));
+
+ tree int_ftype_int_v2si_v2si
+ = build_function_type
+ (integer_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, V2SI_type_node,
+ tree_cons (NULL_TREE, V2SI_type_node,
+ endlink))));
- /* V16QI foo (char). */
- tree v16qi_ftype_char
- = build_function_type (V16QI_type_node,
- tree_cons (NULL_TREE, char_type_node, endlink));
- /* V4SF foo (V4SF). */
- tree v4sf_ftype_v4sf
- = build_function_type (V4SF_type_node,
- tree_cons (NULL_TREE, V4SF_type_node, endlink));
-
- /* V4SI foo (int *). */
- tree v4si_ftype_pint
- = build_function_type (V4SI_type_node,
- tree_cons (NULL_TREE, pint_type_node, endlink));
- /* V8HI foo (short *). */
- tree v8hi_ftype_pshort
- = build_function_type (V8HI_type_node,
- tree_cons (NULL_TREE, pshort_type_node, endlink));
- /* V16QI foo (char *). */
- tree v16qi_ftype_pchar
- = build_function_type (V16QI_type_node,
- tree_cons (NULL_TREE, pchar_type_node, endlink));
- /* V4SF foo (float *). */
- tree v4sf_ftype_pfloat
- = build_function_type (V4SF_type_node,
- tree_cons (NULL_TREE, pfloat_type_node, endlink));
-
- /* V8HI foo (V16QI). */
- tree v8hi_ftype_v16qi
- = build_function_type (V8HI_type_node,
- tree_cons (NULL_TREE, V16QI_type_node, endlink));
+ tree int_ftype_int_v2sf_v2sf
+ = build_function_type
+ (integer_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, V2SF_type_node,
+ tree_cons (NULL_TREE, V2SF_type_node,
+ endlink))));
- /* void foo (void *, int, char/literal). */
- tree void_ftype_pvoid_int_char
+ tree void_ftype_v2si_puint_int
= build_function_type (void_type_node,
- tree_cons (NULL_TREE, pvoid_type_node,
- tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, V2SI_type_node,
+ tree_cons (NULL_TREE, puint_type_node,
tree_cons (NULL_TREE,
- char_type_node,
+ integer_type_node,
endlink))));
- /* void foo (int *, V4SI). */
- tree void_ftype_pint_v4si
+ tree void_ftype_v2si_puint_char
= build_function_type (void_type_node,
- tree_cons (NULL_TREE, pint_type_node,
- tree_cons (NULL_TREE, V4SI_type_node,
- endlink)));
- /* void foo (short *, V8HI). */
- tree void_ftype_pshort_v8hi
- = build_function_type (void_type_node,
- tree_cons (NULL_TREE, pshort_type_node,
- tree_cons (NULL_TREE, V8HI_type_node,
- endlink)));
- /* void foo (char *, V16QI). */
- tree void_ftype_pchar_v16qi
- = build_function_type (void_type_node,
- tree_cons (NULL_TREE, pchar_type_node,
- tree_cons (NULL_TREE, V16QI_type_node,
- endlink)));
- /* void foo (float *, V4SF). */
- tree void_ftype_pfloat_v4sf
- = build_function_type (void_type_node,
- tree_cons (NULL_TREE, pfloat_type_node,
- tree_cons (NULL_TREE, V4SF_type_node,
- endlink)));
-
- /* void foo (V4SI). */
- tree void_ftype_v4si
- = build_function_type (void_type_node,
- tree_cons (NULL_TREE, V4SI_type_node,
- endlink));
-
- /* void foo (vint, int, void *). */
- tree void_ftype_v4si_int_pvoid
- = build_function_type (void_type_node,
- tree_cons (NULL_TREE, V4SI_type_node,
- tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, V2SI_type_node,
+ tree_cons (NULL_TREE, puint_type_node,
tree_cons (NULL_TREE,
- pvoid_type_node,
+ char_type_node,
endlink))));
- /* void foo (vchar, int, void *). */
- tree void_ftype_v16qi_int_pvoid
+ tree void_ftype_v2si_pv2si_int
= build_function_type (void_type_node,
- tree_cons (NULL_TREE, V16QI_type_node,
- tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, V2SI_type_node,
+ tree_cons (NULL_TREE, pv2si_type_node,
tree_cons (NULL_TREE,
- pvoid_type_node,
+ integer_type_node,
endlink))));
- /* void foo (vshort, int, void *). */
- tree void_ftype_v8hi_int_pvoid
+ tree void_ftype_v2si_pv2si_char
= build_function_type (void_type_node,
- tree_cons (NULL_TREE, V8HI_type_node,
- tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, V2SI_type_node,
+ tree_cons (NULL_TREE, pv2si_type_node,
tree_cons (NULL_TREE,
- pvoid_type_node,
+ char_type_node,
endlink))));
- /* void foo (char). */
- tree void_ftype_qi
+ tree void_ftype_int
= build_function_type (void_type_node,
- tree_cons (NULL_TREE, char_type_node,
- endlink));
+ tree_cons (NULL_TREE, integer_type_node, endlink));
- /* void foo (void). */
- tree void_ftype_void
- = build_function_type (void_type_node, void_list_node);
-
- /* vshort foo (void). */
- tree v8hi_ftype_void
- = build_function_type (V8HI_type_node, void_list_node);
+ tree int_ftype_void
+ = build_function_type (integer_type_node,
+ tree_cons (NULL_TREE, void_type_node, endlink));
- tree v4si_ftype_v4si_v4si
- = build_function_type (V4SI_type_node,
- tree_cons (NULL_TREE, V4SI_type_node,
- tree_cons (NULL_TREE, V4SI_type_node,
+ tree v2si_ftype_pv2si_int
+ = build_function_type (V2SI_type_node,
+ tree_cons (NULL_TREE, pv2si_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
endlink)));
- /* These are for the unsigned 5 bit literals. */
-
- tree v4sf_ftype_v4si_char
- = build_function_type (V4SF_type_node,
- tree_cons (NULL_TREE, V4SI_type_node,
- tree_cons (NULL_TREE, char_type_node,
- endlink)));
- tree v4si_ftype_v4sf_char
- = build_function_type (V4SI_type_node,
- tree_cons (NULL_TREE, V4SF_type_node,
- tree_cons (NULL_TREE, char_type_node,
- endlink)));
- tree v4si_ftype_v4si_char
- = build_function_type (V4SI_type_node,
- tree_cons (NULL_TREE, V4SI_type_node,
- tree_cons (NULL_TREE, char_type_node,
- endlink)));
- tree v8hi_ftype_v8hi_char
- = build_function_type (V8HI_type_node,
- tree_cons (NULL_TREE, V8HI_type_node,
- tree_cons (NULL_TREE, char_type_node,
+ tree v2si_ftype_puint_int
+ = build_function_type (V2SI_type_node,
+ tree_cons (NULL_TREE, puint_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
endlink)));
- tree v16qi_ftype_v16qi_char
- = build_function_type (V16QI_type_node,
- tree_cons (NULL_TREE, V16QI_type_node,
- tree_cons (NULL_TREE, char_type_node,
+
+ tree v2si_ftype_pushort_int
+ = build_function_type (V2SI_type_node,
+ tree_cons (NULL_TREE, pushort_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
endlink)));
- /* These are for the unsigned 4 bit literals. */
+ /* The initialization of the simple binary and unary builtins is
+ done in rs6000_common_init_builtins, but we have to enable the
+ mask bits here manually because we have run out of `target_flags'
+ bits. We really need to redesign this mask business. */
+
+ enable_mask_for_builtins ((struct builtin_description *) bdesc_2arg,
+ ARRAY_SIZE (bdesc_2arg),
+ SPE_BUILTIN_EVADDW,
+ SPE_BUILTIN_EVXOR);
+ enable_mask_for_builtins ((struct builtin_description *) bdesc_1arg,
+ ARRAY_SIZE (bdesc_1arg),
+ SPE_BUILTIN_EVABS,
+ SPE_BUILTIN_EVSUBFUSIAAW);
+ enable_mask_for_builtins ((struct builtin_description *) bdesc_spe_predicates,
+ ARRAY_SIZE (bdesc_spe_predicates),
+ SPE_BUILTIN_EVCMPEQ,
+ SPE_BUILTIN_EVFSTSTLT);
+ enable_mask_for_builtins ((struct builtin_description *) bdesc_spe_evsel,
+ ARRAY_SIZE (bdesc_spe_evsel),
+ SPE_BUILTIN_EVSEL_CMPGTS,
+ SPE_BUILTIN_EVSEL_FSTSTEQ);
+
+ /* Initialize irregular SPE builtins. */
+
+ def_builtin (target_flags, "__builtin_spe_mtspefscr", void_ftype_int, SPE_BUILTIN_MTSPEFSCR);
+ def_builtin (target_flags, "__builtin_spe_mfspefscr", int_ftype_void, SPE_BUILTIN_MFSPEFSCR);
+ def_builtin (target_flags, "__builtin_spe_evstddx", void_ftype_v2si_pv2si_int, SPE_BUILTIN_EVSTDDX);
+ def_builtin (target_flags, "__builtin_spe_evstdhx", void_ftype_v2si_pv2si_int, SPE_BUILTIN_EVSTDHX);
+ def_builtin (target_flags, "__builtin_spe_evstdwx", void_ftype_v2si_pv2si_int, SPE_BUILTIN_EVSTDWX);
+ def_builtin (target_flags, "__builtin_spe_evstwhex", void_ftype_v2si_puint_int, SPE_BUILTIN_EVSTWHEX);
+ def_builtin (target_flags, "__builtin_spe_evstwhox", void_ftype_v2si_puint_int, SPE_BUILTIN_EVSTWHOX);
+ def_builtin (target_flags, "__builtin_spe_evstwwex", void_ftype_v2si_puint_int, SPE_BUILTIN_EVSTWWEX);
+ def_builtin (target_flags, "__builtin_spe_evstwwox", void_ftype_v2si_puint_int, SPE_BUILTIN_EVSTWWOX);
+ def_builtin (target_flags, "__builtin_spe_evstdd", void_ftype_v2si_pv2si_char, SPE_BUILTIN_EVSTDD);
+ def_builtin (target_flags, "__builtin_spe_evstdh", void_ftype_v2si_pv2si_char, SPE_BUILTIN_EVSTDH);
+ def_builtin (target_flags, "__builtin_spe_evstdw", void_ftype_v2si_pv2si_char, SPE_BUILTIN_EVSTDW);
+ def_builtin (target_flags, "__builtin_spe_evstwhe", void_ftype_v2si_puint_char, SPE_BUILTIN_EVSTWHE);
+ def_builtin (target_flags, "__builtin_spe_evstwho", void_ftype_v2si_puint_char, SPE_BUILTIN_EVSTWHO);
+ def_builtin (target_flags, "__builtin_spe_evstwwe", void_ftype_v2si_puint_char, SPE_BUILTIN_EVSTWWE);
+ def_builtin (target_flags, "__builtin_spe_evstwwo", void_ftype_v2si_puint_char, SPE_BUILTIN_EVSTWWO);
+
+ /* Loads. */
+ def_builtin (target_flags, "__builtin_spe_evlddx", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDDX);
+ def_builtin (target_flags, "__builtin_spe_evldwx", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDWX);
+ def_builtin (target_flags, "__builtin_spe_evldhx", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDHX);
+ def_builtin (target_flags, "__builtin_spe_evlwhex", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHEX);
+ def_builtin (target_flags, "__builtin_spe_evlwhoux", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHOUX);
+ def_builtin (target_flags, "__builtin_spe_evlwhosx", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHOSX);
+ def_builtin (target_flags, "__builtin_spe_evlwwsplatx", v2si_ftype_puint_int, SPE_BUILTIN_EVLWWSPLATX);
+ def_builtin (target_flags, "__builtin_spe_evlwhsplatx", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHSPLATX);
+ def_builtin (target_flags, "__builtin_spe_evlhhesplatx", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHESPLATX);
+ def_builtin (target_flags, "__builtin_spe_evlhhousplatx", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHOUSPLATX);
+ def_builtin (target_flags, "__builtin_spe_evlhhossplatx", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHOSSPLATX);
+ def_builtin (target_flags, "__builtin_spe_evldd", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDD);
+ def_builtin (target_flags, "__builtin_spe_evldw", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDW);
+ def_builtin (target_flags, "__builtin_spe_evldh", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDH);
+ def_builtin (target_flags, "__builtin_spe_evlhhesplat", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHESPLAT);
+ def_builtin (target_flags, "__builtin_spe_evlhhossplat", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHOSSPLAT);
+ def_builtin (target_flags, "__builtin_spe_evlhhousplat", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHOUSPLAT);
+ def_builtin (target_flags, "__builtin_spe_evlwhe", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHE);
+ def_builtin (target_flags, "__builtin_spe_evlwhos", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHOS);
+ def_builtin (target_flags, "__builtin_spe_evlwhou", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHOU);
+ def_builtin (target_flags, "__builtin_spe_evlwhsplat", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHSPLAT);
+ def_builtin (target_flags, "__builtin_spe_evlwwsplat", v2si_ftype_puint_int, SPE_BUILTIN_EVLWWSPLAT);
+
+ /* Predicates. */
+ d = (struct builtin_description *) bdesc_spe_predicates;
+ for (i = 0; i < ARRAY_SIZE (bdesc_spe_predicates); ++i, d++)
+ {
+ tree type;
- tree v16qi_ftype_v16qi_v16qi_char
- = build_function_type (V16QI_type_node,
- tree_cons (NULL_TREE, V16QI_type_node,
- tree_cons (NULL_TREE, V16QI_type_node,
- tree_cons (NULL_TREE,
- char_type_node,
- endlink))));
+ switch (insn_data[d->icode].operand[1].mode)
+ {
+ case V2SImode:
+ type = int_ftype_int_v2si_v2si;
+ break;
+ case V2SFmode:
+ type = int_ftype_int_v2sf_v2sf;
+ break;
+ default:
+ abort ();
+ }
- tree v8hi_ftype_v8hi_v8hi_char
- = build_function_type (V8HI_type_node,
- tree_cons (NULL_TREE, V8HI_type_node,
- tree_cons (NULL_TREE, V8HI_type_node,
- tree_cons (NULL_TREE,
- char_type_node,
- endlink))));
+ def_builtin (d->mask, d->name, type, d->code);
+ }
- tree v4si_ftype_v4si_v4si_char
- = build_function_type (V4SI_type_node,
- tree_cons (NULL_TREE, V4SI_type_node,
- tree_cons (NULL_TREE, V4SI_type_node,
- tree_cons (NULL_TREE,
- char_type_node,
- endlink))));
+ /* Evsel predicates. */
+ d = (struct builtin_description *) bdesc_spe_evsel;
+ for (i = 0; i < ARRAY_SIZE (bdesc_spe_evsel); ++i, d++)
+ {
+ tree type;
- tree v4sf_ftype_v4sf_v4sf_char
- = build_function_type (V4SF_type_node,
- tree_cons (NULL_TREE, V4SF_type_node,
- tree_cons (NULL_TREE, V4SF_type_node,
- tree_cons (NULL_TREE,
- char_type_node,
- endlink))));
+ switch (insn_data[d->icode].operand[1].mode)
+ {
+ case V2SImode:
+ type = v2si_ftype_4_v2si;
+ break;
+ case V2SFmode:
+ type = v2sf_ftype_4_v2sf;
+ break;
+ default:
+ abort ();
+ }
- /* End of 4 bit literals. */
+ def_builtin (d->mask, d->name, type, d->code);
+ }
+}
- tree v4sf_ftype_v4sf_v4sf
- = build_function_type (V4SF_type_node,
- tree_cons (NULL_TREE, V4SF_type_node,
- tree_cons (NULL_TREE, V4SF_type_node,
- endlink)));
- tree v4sf_ftype_v4sf_v4sf_v4si
- = build_function_type (V4SF_type_node,
- tree_cons (NULL_TREE, V4SF_type_node,
- tree_cons (NULL_TREE, V4SF_type_node,
- tree_cons (NULL_TREE,
- V4SI_type_node,
- endlink))));
- tree v4sf_ftype_v4sf_v4sf_v4sf
- = build_function_type (V4SF_type_node,
- tree_cons (NULL_TREE, V4SF_type_node,
- tree_cons (NULL_TREE, V4SF_type_node,
- tree_cons (NULL_TREE,
- V4SF_type_node,
- endlink))));
- tree v4si_ftype_v4si_v4si_v4si
- = build_function_type (V4SI_type_node,
- tree_cons (NULL_TREE, V4SI_type_node,
- tree_cons (NULL_TREE, V4SI_type_node,
- tree_cons (NULL_TREE,
- V4SI_type_node,
- endlink))));
+static void
+altivec_init_builtins ()
+{
+ struct builtin_description *d;
+ struct builtin_description_predicates *dp;
+ size_t i;
+ tree pfloat_type_node = build_pointer_type (float_type_node);
+ tree pint_type_node = build_pointer_type (integer_type_node);
+ tree pshort_type_node = build_pointer_type (short_integer_type_node);
+ tree pchar_type_node = build_pointer_type (char_type_node);
- tree v8hi_ftype_v8hi_v8hi
- = build_function_type (V8HI_type_node,
- tree_cons (NULL_TREE, V8HI_type_node,
- tree_cons (NULL_TREE, V8HI_type_node,
- endlink)));
- tree v8hi_ftype_v8hi_v8hi_v8hi
- = build_function_type (V8HI_type_node,
- tree_cons (NULL_TREE, V8HI_type_node,
- tree_cons (NULL_TREE, V8HI_type_node,
- tree_cons (NULL_TREE,
- V8HI_type_node,
- endlink))));
- tree v4si_ftype_v8hi_v8hi_v4si
- = build_function_type (V4SI_type_node,
- tree_cons (NULL_TREE, V8HI_type_node,
- tree_cons (NULL_TREE, V8HI_type_node,
- tree_cons (NULL_TREE,
- V4SI_type_node,
- endlink))));
- tree v4si_ftype_v16qi_v16qi_v4si
- = build_function_type (V4SI_type_node,
- tree_cons (NULL_TREE, V16QI_type_node,
- tree_cons (NULL_TREE, V16QI_type_node,
- tree_cons (NULL_TREE,
- V4SI_type_node,
- endlink))));
-
- tree v16qi_ftype_v16qi_v16qi
- = build_function_type (V16QI_type_node,
- tree_cons (NULL_TREE, V16QI_type_node,
- tree_cons (NULL_TREE, V16QI_type_node,
- endlink)));
-
- tree v4si_ftype_v4sf_v4sf
- = build_function_type (V4SI_type_node,
- tree_cons (NULL_TREE, V4SF_type_node,
- tree_cons (NULL_TREE, V4SF_type_node,
- endlink)));
+ tree pvoid_type_node = build_pointer_type (void_type_node);
- tree v4si_ftype_v4si
- = build_function_type (V4SI_type_node,
- tree_cons (NULL_TREE, V4SI_type_node, endlink));
+ tree pcfloat_type_node = build_pointer_type (build_qualified_type (float_type_node, TYPE_QUAL_CONST));
+ tree pcint_type_node = build_pointer_type (build_qualified_type (integer_type_node, TYPE_QUAL_CONST));
+ tree pcshort_type_node = build_pointer_type (build_qualified_type (short_integer_type_node, TYPE_QUAL_CONST));
+ tree pcchar_type_node = build_pointer_type (build_qualified_type (char_type_node, TYPE_QUAL_CONST));
- tree v8hi_ftype_v8hi
- = build_function_type (V8HI_type_node,
- tree_cons (NULL_TREE, V8HI_type_node, endlink));
+ tree pcvoid_type_node = build_pointer_type (build_qualified_type (void_type_node, TYPE_QUAL_CONST));
+
+ tree int_ftype_int_v4si_v4si
+ = build_function_type_list (integer_type_node,
+ integer_type_node, V4SI_type_node,
+ V4SI_type_node, NULL_TREE);
+ tree v4sf_ftype_pcfloat
+ = build_function_type_list (V4SF_type_node, pcfloat_type_node, NULL_TREE);
+ tree void_ftype_pfloat_v4sf
+ = build_function_type_list (void_type_node,
+ pfloat_type_node, V4SF_type_node, NULL_TREE);
+ tree v4si_ftype_pcint
+ = build_function_type_list (V4SI_type_node, pcint_type_node, NULL_TREE);
+ tree void_ftype_pint_v4si
+ = build_function_type_list (void_type_node,
+ pint_type_node, V4SI_type_node, NULL_TREE);
+ tree v8hi_ftype_pcshort
+ = build_function_type_list (V8HI_type_node, pcshort_type_node, NULL_TREE);
+ tree void_ftype_pshort_v8hi
+ = build_function_type_list (void_type_node,
+ pshort_type_node, V8HI_type_node, NULL_TREE);
+ tree v16qi_ftype_pcchar
+ = build_function_type_list (V16QI_type_node, pcchar_type_node, NULL_TREE);
+ tree void_ftype_pchar_v16qi
+ = build_function_type_list (void_type_node,
+ pchar_type_node, V16QI_type_node, NULL_TREE);
+ tree void_ftype_v4si
+ = build_function_type_list (void_type_node, V4SI_type_node, NULL_TREE);
+ tree v8hi_ftype_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 v16qi_ftype_int_pcvoid
+ = build_function_type_list (V16QI_type_node,
+ integer_type_node, pcvoid_type_node, NULL_TREE);
+ tree v8hi_ftype_int_pcvoid
+ = build_function_type_list (V8HI_type_node,
+ integer_type_node, pcvoid_type_node, NULL_TREE);
+ tree v4si_ftype_int_pcvoid
+ = build_function_type_list (V4SI_type_node,
+ integer_type_node, pcvoid_type_node, NULL_TREE);
+ tree void_ftype_v4si_int_pvoid
+ = build_function_type_list (void_type_node,
+ V4SI_type_node, integer_type_node,
+ pvoid_type_node, NULL_TREE);
+ tree void_ftype_v16qi_int_pvoid
+ = build_function_type_list (void_type_node,
+ V16QI_type_node, integer_type_node,
+ pvoid_type_node, NULL_TREE);
+ tree void_ftype_v8hi_int_pvoid
+ = build_function_type_list (void_type_node,
+ V8HI_type_node, integer_type_node,
+ pvoid_type_node, NULL_TREE);
+ tree int_ftype_int_v8hi_v8hi
+ = build_function_type_list (integer_type_node,
+ integer_type_node, V8HI_type_node,
+ V8HI_type_node, NULL_TREE);
+ tree int_ftype_int_v16qi_v16qi
+ = build_function_type_list (integer_type_node,
+ integer_type_node, V16QI_type_node,
+ V16QI_type_node, NULL_TREE);
+ tree int_ftype_int_v4sf_v4sf
+ = build_function_type_list (integer_type_node,
+ integer_type_node, V4SF_type_node,
+ V4SF_type_node, NULL_TREE);
+ tree v4si_ftype_v4si
+ = build_function_type_list (V4SI_type_node, V4SI_type_node, NULL_TREE);
+ tree v8hi_ftype_v8hi
+ = build_function_type_list (V8HI_type_node, V8HI_type_node, NULL_TREE);
tree v16qi_ftype_v16qi
- = build_function_type (V16QI_type_node,
- tree_cons (NULL_TREE, V16QI_type_node, endlink));
+ = 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
+ = build_function_type_list (void_type_node,
+ pcvoid_type_node, integer_type_node,
+ char_type_node, NULL_TREE);
+
+ def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_4sf", v4sf_ftype_pcfloat,
+ ALTIVEC_BUILTIN_LD_INTERNAL_4sf);
+ def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_4sf", void_ftype_pfloat_v4sf,
+ ALTIVEC_BUILTIN_ST_INTERNAL_4sf);
+ def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_4si", v4si_ftype_pcint,
+ ALTIVEC_BUILTIN_LD_INTERNAL_4si);
+ def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_4si", void_ftype_pint_v4si,
+ ALTIVEC_BUILTIN_ST_INTERNAL_4si);
+ def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_8hi", v8hi_ftype_pcshort,
+ ALTIVEC_BUILTIN_LD_INTERNAL_8hi);
+ def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_8hi", void_ftype_pshort_v8hi,
+ ALTIVEC_BUILTIN_ST_INTERNAL_8hi);
+ def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_16qi", v16qi_ftype_pcchar,
+ ALTIVEC_BUILTIN_LD_INTERNAL_16qi);
+ def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_16qi", void_ftype_pchar_v16qi,
+ ALTIVEC_BUILTIN_ST_INTERNAL_16qi);
+ 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_lvsl", v16qi_ftype_int_pcvoid, ALTIVEC_BUILTIN_LVSL);
+ def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvsr", v16qi_ftype_int_pcvoid, ALTIVEC_BUILTIN_LVSR);
+ def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvebx", v16qi_ftype_int_pcvoid, ALTIVEC_BUILTIN_LVEBX);
+ def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvehx", v8hi_ftype_int_pcvoid, ALTIVEC_BUILTIN_LVEHX);
+ def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvewx", v4si_ftype_int_pcvoid, ALTIVEC_BUILTIN_LVEWX);
+ def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvxl", v4si_ftype_int_pcvoid, ALTIVEC_BUILTIN_LVXL);
+ def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvx", v4si_ftype_int_pcvoid, ALTIVEC_BUILTIN_LVX);
+ def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvx", void_ftype_v4si_int_pvoid, ALTIVEC_BUILTIN_STVX);
+ def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvewx", void_ftype_v4si_int_pvoid, ALTIVEC_BUILTIN_STVEWX);
+ def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvxl", void_ftype_v4si_int_pvoid, ALTIVEC_BUILTIN_STVXL);
+ def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvebx", void_ftype_v16qi_int_pvoid, ALTIVEC_BUILTIN_STVEBX);
+ def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvehx", void_ftype_v8hi_int_pvoid, ALTIVEC_BUILTIN_STVEHX);
- tree v8hi_ftype_v16qi_v16qi
- = build_function_type (V8HI_type_node,
- tree_cons (NULL_TREE, V16QI_type_node,
- tree_cons (NULL_TREE, V16QI_type_node,
- endlink)));
+ /* 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);
- tree v4si_ftype_v8hi_v8hi
- = build_function_type (V4SI_type_node,
- tree_cons (NULL_TREE, V8HI_type_node,
- tree_cons (NULL_TREE, V8HI_type_node,
- endlink)));
+ /* Initialize the predicates. */
+ dp = (struct builtin_description_predicates *) bdesc_altivec_preds;
+ for (i = 0; i < ARRAY_SIZE (bdesc_altivec_preds); i++, dp++)
+ {
+ enum machine_mode mode1;
+ tree type;
- tree v8hi_ftype_v4si_v4si
- = build_function_type (V8HI_type_node,
- tree_cons (NULL_TREE, V4SI_type_node,
- tree_cons (NULL_TREE, V4SI_type_node,
- endlink)));
+ mode1 = insn_data[dp->icode].operand[1].mode;
- tree v16qi_ftype_v8hi_v8hi
- = build_function_type (V16QI_type_node,
- tree_cons (NULL_TREE, V8HI_type_node,
- tree_cons (NULL_TREE, V8HI_type_node,
- endlink)));
+ switch (mode1)
+ {
+ case V4SImode:
+ type = int_ftype_int_v4si_v4si;
+ break;
+ case V8HImode:
+ type = int_ftype_int_v8hi_v8hi;
+ break;
+ case V16QImode:
+ type = int_ftype_int_v16qi_v16qi;
+ break;
+ case V4SFmode:
+ type = int_ftype_int_v4sf_v4sf;
+ break;
+ default:
+ abort ();
+ }
+
+ def_builtin (dp->mask, dp->name, type, dp->code);
+ }
- tree v4si_ftype_v16qi_v4si
- = build_function_type (V4SI_type_node,
- tree_cons (NULL_TREE, V16QI_type_node,
- tree_cons (NULL_TREE, V4SI_type_node,
- endlink)));
+ /* Initialize the abs* operators. */
+ d = (struct builtin_description *) bdesc_abs;
+ for (i = 0; i < ARRAY_SIZE (bdesc_abs); i++, d++)
+ {
+ enum machine_mode mode0;
+ tree type;
- tree v4si_ftype_v16qi_v16qi
- = build_function_type (V4SI_type_node,
- tree_cons (NULL_TREE, V16QI_type_node,
- tree_cons (NULL_TREE, V16QI_type_node,
- endlink)));
+ mode0 = insn_data[d->icode].operand[0].mode;
- tree v4si_ftype_v8hi_v4si
- = build_function_type (V4SI_type_node,
- tree_cons (NULL_TREE, V8HI_type_node,
- tree_cons (NULL_TREE, V4SI_type_node,
- endlink)));
+ switch (mode0)
+ {
+ case V4SImode:
+ type = v4si_ftype_v4si;
+ break;
+ case V8HImode:
+ type = v8hi_ftype_v8hi;
+ break;
+ case V16QImode:
+ type = v16qi_ftype_v16qi;
+ break;
+ case V4SFmode:
+ type = v4sf_ftype_v4sf;
+ break;
+ default:
+ abort ();
+ }
+
+ def_builtin (d->mask, d->name, type, d->code);
+ }
+}
- tree v4si_ftype_v8hi
- = build_function_type (V4SI_type_node,
- tree_cons (NULL_TREE, V8HI_type_node, endlink));
+static void
+rs6000_common_init_builtins ()
+{
+ struct builtin_description *d;
+ size_t i;
- tree int_ftype_v4si_v4si
- = build_function_type (integer_type_node,
- tree_cons (NULL_TREE, V4SI_type_node,
- tree_cons (NULL_TREE, V4SI_type_node,
- endlink)));
+ tree v4sf_ftype_v4sf_v4sf_v16qi
+ = build_function_type_list (V4SF_type_node,
+ V4SF_type_node, V4SF_type_node,
+ V16QI_type_node, NULL_TREE);
+ tree v4si_ftype_v4si_v4si_v16qi
+ = build_function_type_list (V4SI_type_node,
+ V4SI_type_node, V4SI_type_node,
+ V16QI_type_node, NULL_TREE);
+ tree v8hi_ftype_v8hi_v8hi_v16qi
+ = build_function_type_list (V8HI_type_node,
+ V8HI_type_node, V8HI_type_node,
+ V16QI_type_node, NULL_TREE);
+ tree v16qi_ftype_v16qi_v16qi_v16qi
+ = 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 v8hi_ftype_v16qi
+ = build_function_type_list (V8HI_type_node, V16QI_type_node, NULL_TREE);
+ tree v4sf_ftype_v4sf
+ = build_function_type_list (V4SF_type_node, V4SF_type_node, NULL_TREE);
- tree int_ftype_v4sf_v4sf
- = build_function_type (integer_type_node,
- tree_cons (NULL_TREE, V4SF_type_node,
- tree_cons (NULL_TREE, V4SF_type_node,
- endlink)));
+ tree v2si_ftype_v2si_v2si
+ = build_function_type_list (V2SI_type_node,
+ V2SI_type_node, V2SI_type_node, NULL_TREE);
- tree int_ftype_v16qi_v16qi
- = build_function_type (integer_type_node,
- tree_cons (NULL_TREE, V16QI_type_node,
- tree_cons (NULL_TREE, V16QI_type_node,
- endlink)));
+ tree v2sf_ftype_v2sf_v2sf
+ = build_function_type_list (V2SF_type_node,
+ V2SF_type_node, V2SF_type_node, NULL_TREE);
- tree int_ftype_int_v4si_v4si
- = build_function_type
- (integer_type_node,
- tree_cons (NULL_TREE, integer_type_node,
- tree_cons (NULL_TREE, V4SI_type_node,
- tree_cons (NULL_TREE, V4SI_type_node,
- endlink))));
+ tree v2si_ftype_int_int
+ = build_function_type_list (V2SI_type_node,
+ integer_type_node, integer_type_node,
+ NULL_TREE);
- tree int_ftype_int_v4sf_v4sf
- = build_function_type
- (integer_type_node,
- tree_cons (NULL_TREE, integer_type_node,
- tree_cons (NULL_TREE, V4SF_type_node,
- tree_cons (NULL_TREE, V4SF_type_node,
- endlink))));
+ tree v2si_ftype_v2si
+ = build_function_type_list (V2SI_type_node, V2SI_type_node, NULL_TREE);
- tree int_ftype_int_v8hi_v8hi
- = build_function_type
- (integer_type_node,
- tree_cons (NULL_TREE, integer_type_node,
- tree_cons (NULL_TREE, V8HI_type_node,
- tree_cons (NULL_TREE, V8HI_type_node,
- endlink))));
+ tree v2sf_ftype_v2sf
+ = build_function_type_list (V2SF_type_node,
+ V2SF_type_node, NULL_TREE);
+
+ tree v2sf_ftype_v2si
+ = build_function_type_list (V2SF_type_node,
+ V2SI_type_node, NULL_TREE);
- tree int_ftype_int_v16qi_v16qi
- = build_function_type
- (integer_type_node,
- tree_cons (NULL_TREE, integer_type_node,
- tree_cons (NULL_TREE, V16QI_type_node,
- tree_cons (NULL_TREE, V16QI_type_node,
- endlink))));
+ tree v2si_ftype_v2sf
+ = build_function_type_list (V2SI_type_node,
+ V2SF_type_node, NULL_TREE);
- tree v16qi_ftype_int_pvoid
- = build_function_type (V16QI_type_node,
- tree_cons (NULL_TREE, integer_type_node,
- tree_cons (NULL_TREE, pvoid_type_node,
- endlink)));
+ tree v2si_ftype_v2si_char
+ = build_function_type_list (V2SI_type_node,
+ V2SI_type_node, char_type_node, NULL_TREE);
- tree v4si_ftype_int_pvoid
- = build_function_type (V4SI_type_node,
- tree_cons (NULL_TREE, integer_type_node,
- tree_cons (NULL_TREE, pvoid_type_node,
- endlink)));
+ tree v2si_ftype_int_char
+ = build_function_type_list (V2SI_type_node,
+ integer_type_node, char_type_node, NULL_TREE);
- tree v8hi_ftype_int_pvoid
- = build_function_type (V8HI_type_node,
- tree_cons (NULL_TREE, integer_type_node,
- tree_cons (NULL_TREE, pvoid_type_node,
- endlink)));
+ tree v2si_ftype_char
+ = build_function_type_list (V2SI_type_node, char_type_node, NULL_TREE);
- tree int_ftype_v8hi_v8hi
- = build_function_type (integer_type_node,
- tree_cons (NULL_TREE, V8HI_type_node,
- tree_cons (NULL_TREE, V8HI_type_node,
- endlink)));
+ tree int_ftype_int_int
+ = build_function_type_list (integer_type_node,
+ integer_type_node, integer_type_node,
+ NULL_TREE);
- def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_4sf", v4sf_ftype_pfloat, ALTIVEC_BUILTIN_LD_INTERNAL_4sf);
- def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_4sf", void_ftype_pfloat_v4sf, ALTIVEC_BUILTIN_ST_INTERNAL_4sf);
- def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_4si", v4si_ftype_pint, ALTIVEC_BUILTIN_LD_INTERNAL_4si);
- def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_4si", void_ftype_pint_v4si, ALTIVEC_BUILTIN_ST_INTERNAL_4si);
- def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_8hi", v8hi_ftype_pshort, ALTIVEC_BUILTIN_LD_INTERNAL_8hi);
- def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_8hi", void_ftype_pshort_v8hi, ALTIVEC_BUILTIN_ST_INTERNAL_8hi);
- def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_16qi", v16qi_ftype_pchar, ALTIVEC_BUILTIN_LD_INTERNAL_16qi);
- def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_16qi", void_ftype_pchar_v16qi, ALTIVEC_BUILTIN_ST_INTERNAL_16qi);
- 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_lvsl", v16qi_ftype_int_pvoid, ALTIVEC_BUILTIN_LVSL);
- def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvsr", v16qi_ftype_int_pvoid, ALTIVEC_BUILTIN_LVSR);
- def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvebx", v16qi_ftype_int_pvoid, ALTIVEC_BUILTIN_LVEBX);
- def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvehx", v8hi_ftype_int_pvoid, ALTIVEC_BUILTIN_LVEHX);
- def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvewx", v4si_ftype_int_pvoid, ALTIVEC_BUILTIN_LVEWX);
- def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvxl", v4si_ftype_int_pvoid, ALTIVEC_BUILTIN_LVXL);
- def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvx", v4si_ftype_int_pvoid, ALTIVEC_BUILTIN_LVX);
- def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvx", void_ftype_v4si_int_pvoid, ALTIVEC_BUILTIN_STVX);
- def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvebx", void_ftype_v16qi_int_pvoid, ALTIVEC_BUILTIN_STVEBX);
- def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvehx", void_ftype_v8hi_int_pvoid, ALTIVEC_BUILTIN_STVEHX);
- def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvewx", void_ftype_v4si_int_pvoid, ALTIVEC_BUILTIN_STVEWX);
- def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvxl", void_ftype_v4si_int_pvoid, ALTIVEC_BUILTIN_STVXL);
+ 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
+ = build_function_type_list (V4SF_type_node,
+ V4SI_type_node, char_type_node, NULL_TREE);
+ tree v4si_ftype_v4sf_char
+ = build_function_type_list (V4SI_type_node,
+ V4SF_type_node, char_type_node, NULL_TREE);
+ tree v4si_ftype_v4si_char
+ = build_function_type_list (V4SI_type_node,
+ V4SI_type_node, char_type_node, NULL_TREE);
+ tree v8hi_ftype_v8hi_char
+ = build_function_type_list (V8HI_type_node,
+ V8HI_type_node, char_type_node, NULL_TREE);
+ tree v16qi_ftype_v16qi_char
+ = build_function_type_list (V16QI_type_node,
+ V16QI_type_node, char_type_node, NULL_TREE);
+ tree v16qi_ftype_v16qi_v16qi_char
+ = build_function_type_list (V16QI_type_node,
+ V16QI_type_node, V16QI_type_node,
+ char_type_node, NULL_TREE);
+ tree v8hi_ftype_v8hi_v8hi_char
+ = build_function_type_list (V8HI_type_node,
+ V8HI_type_node, V8HI_type_node,
+ char_type_node, NULL_TREE);
+ tree v4si_ftype_v4si_v4si_char
+ = build_function_type_list (V4SI_type_node,
+ V4SI_type_node, V4SI_type_node,
+ char_type_node, NULL_TREE);
+ tree v4sf_ftype_v4sf_v4sf_char
+ = build_function_type_list (V4SF_type_node,
+ V4SF_type_node, V4SF_type_node,
+ char_type_node, NULL_TREE);
+ tree v4sf_ftype_v4sf_v4sf
+ = build_function_type_list (V4SF_type_node,
+ V4SF_type_node, V4SF_type_node, NULL_TREE);
+ tree v4sf_ftype_v4sf_v4sf_v4si
+ = build_function_type_list (V4SF_type_node,
+ V4SF_type_node, V4SF_type_node,
+ V4SI_type_node, NULL_TREE);
+ tree v4sf_ftype_v4sf_v4sf_v4sf
+ = build_function_type_list (V4SF_type_node,
+ V4SF_type_node, V4SF_type_node,
+ V4SF_type_node, NULL_TREE);
+ tree v4si_ftype_v4si_v4si_v4si
+ = build_function_type_list (V4SI_type_node,
+ V4SI_type_node, V4SI_type_node,
+ V4SI_type_node, NULL_TREE);
+ tree v8hi_ftype_v8hi_v8hi
+ = build_function_type_list (V8HI_type_node,
+ V8HI_type_node, V8HI_type_node, NULL_TREE);
+ tree v8hi_ftype_v8hi_v8hi_v8hi
+ = build_function_type_list (V8HI_type_node,
+ V8HI_type_node, V8HI_type_node,
+ V8HI_type_node, NULL_TREE);
+ tree v4si_ftype_v8hi_v8hi_v4si
+ = build_function_type_list (V4SI_type_node,
+ V8HI_type_node, V8HI_type_node,
+ V4SI_type_node, NULL_TREE);
+ tree v4si_ftype_v16qi_v16qi_v4si
+ = build_function_type_list (V4SI_type_node,
+ V16QI_type_node, V16QI_type_node,
+ V4SI_type_node, NULL_TREE);
+ tree v16qi_ftype_v16qi_v16qi
+ = build_function_type_list (V16QI_type_node,
+ V16QI_type_node, V16QI_type_node, NULL_TREE);
+ tree v4si_ftype_v4sf_v4sf
+ = build_function_type_list (V4SI_type_node,
+ V4SF_type_node, V4SF_type_node, NULL_TREE);
+ tree v8hi_ftype_v16qi_v16qi
+ = build_function_type_list (V8HI_type_node,
+ V16QI_type_node, V16QI_type_node, NULL_TREE);
+ tree v4si_ftype_v8hi_v8hi
+ = build_function_type_list (V4SI_type_node,
+ V8HI_type_node, V8HI_type_node, NULL_TREE);
+ tree v8hi_ftype_v4si_v4si
+ = build_function_type_list (V8HI_type_node,
+ V4SI_type_node, V4SI_type_node, NULL_TREE);
+ tree v16qi_ftype_v8hi_v8hi
+ = build_function_type_list (V16QI_type_node,
+ V8HI_type_node, V8HI_type_node, NULL_TREE);
+ tree v4si_ftype_v16qi_v4si
+ = build_function_type_list (V4SI_type_node,
+ V16QI_type_node, V4SI_type_node, NULL_TREE);
+ tree v4si_ftype_v16qi_v16qi
+ = build_function_type_list (V4SI_type_node,
+ V16QI_type_node, V16QI_type_node, NULL_TREE);
+ tree v4si_ftype_v8hi_v4si
+ = build_function_type_list (V4SI_type_node,
+ V8HI_type_node, V4SI_type_node, NULL_TREE);
+ tree v4si_ftype_v8hi
+ = build_function_type_list (V4SI_type_node, V8HI_type_node, NULL_TREE);
+ tree int_ftype_v4si_v4si
+ = build_function_type_list (integer_type_node,
+ V4SI_type_node, V4SI_type_node, NULL_TREE);
+ tree int_ftype_v4sf_v4sf
+ = build_function_type_list (integer_type_node,
+ V4SF_type_node, V4SF_type_node, NULL_TREE);
+ tree int_ftype_v16qi_v16qi
+ = build_function_type_list (integer_type_node,
+ V16QI_type_node, V16QI_type_node, NULL_TREE);
+ tree int_ftype_v8hi_v8hi
+ = build_function_type_list (integer_type_node,
+ V8HI_type_node, V8HI_type_node, NULL_TREE);
/* Add the simple ternary operators. */
d = (struct builtin_description *) bdesc_3arg;
- for (i = 0; i < sizeof (bdesc_3arg) / sizeof *d; i++, d++)
+ for (i = 0; i < ARRAY_SIZE (bdesc_3arg); i++, d++)
{
enum machine_mode mode0, mode1, mode2, mode3;
tree type;
- if (d->name == 0)
+ if (d->name == 0 || d->icode == CODE_FOR_nothing)
continue;
mode0 = insn_data[d->icode].operand[0].mode;
@@ -4694,49 +5944,14 @@ altivec_init_builtins (void)
def_builtin (d->mask, d->name, type, d->code);
}
- /* Add the DST variants. */
- d = (struct builtin_description *) bdesc_dst;
- for (i = 0; i < sizeof (bdesc_dst) / sizeof *d; i++, d++)
- def_builtin (d->mask, d->name, void_ftype_pvoid_int_char, d->code);
-
- /* Initialize the predicates. */
- dp = (struct builtin_description_predicates *) bdesc_altivec_preds;
- for (i = 0; i < sizeof (bdesc_altivec_preds) / sizeof *dp; i++, dp++)
- {
- enum machine_mode mode1;
- tree type;
-
- mode1 = insn_data[dp->icode].operand[1].mode;
-
- switch (mode1)
- {
- case V4SImode:
- type = int_ftype_int_v4si_v4si;
- break;
- case V8HImode:
- type = int_ftype_int_v8hi_v8hi;
- break;
- case V16QImode:
- type = int_ftype_int_v16qi_v16qi;
- break;
- case V4SFmode:
- type = int_ftype_int_v4sf_v4sf;
- break;
- default:
- abort ();
- }
-
- def_builtin (dp->mask, dp->name, type, dp->code);
- }
-
/* Add the simple binary operators. */
d = (struct builtin_description *) bdesc_2arg;
- for (i = 0; i < sizeof (bdesc_2arg) / sizeof *d; i++, d++)
+ for (i = 0; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
{
enum machine_mode mode0, mode1, mode2;
tree type;
- if (d->name == 0)
+ if (d->name == 0 || d->icode == CODE_FOR_nothing)
continue;
mode0 = insn_data[d->icode].operand[0].mode;
@@ -4760,6 +5975,15 @@ altivec_init_builtins (void)
case V8HImode:
type = v8hi_ftype_v8hi_v8hi;
break;
+ case V2SImode:
+ type = v2si_ftype_v2si_v2si;
+ break;
+ case V2SFmode:
+ type = v2sf_ftype_v2sf_v2sf;
+ break;
+ case SImode:
+ type = int_ftype_int_int;
+ break;
default:
abort ();
}
@@ -4819,6 +6043,15 @@ altivec_init_builtins (void)
else if (mode0 == V4SImode && mode1 == V4SFmode && mode2 == QImode)
type = v4si_ftype_v4sf_char;
+ else if (mode0 == V2SImode && mode1 == SImode && mode2 == SImode)
+ type = v2si_ftype_int_int;
+
+ else if (mode0 == V2SImode && mode1 == V2SImode && mode2 == QImode)
+ type = v2si_ftype_v2si_char;
+
+ else if (mode0 == V2SImode && mode1 == SImode && mode2 == QImode)
+ type = v2si_ftype_int_char;
+
/* int, x, x. */
else if (mode0 == SImode)
{
@@ -4847,44 +6080,14 @@ altivec_init_builtins (void)
def_builtin (d->mask, d->name, type, d->code);
}
- /* Initialize the abs* operators. */
- d = (struct builtin_description *) bdesc_abs;
- for (i = 0; i < sizeof (bdesc_abs) / sizeof *d; i++, d++)
- {
- enum machine_mode mode0;
- tree type;
-
- mode0 = insn_data[d->icode].operand[0].mode;
-
- switch (mode0)
- {
- case V4SImode:
- type = v4si_ftype_v4si;
- break;
- case V8HImode:
- type = v8hi_ftype_v8hi;
- break;
- case V16QImode:
- type = v16qi_ftype_v16qi;
- break;
- case V4SFmode:
- type = v4sf_ftype_v4sf;
- break;
- default:
- abort ();
- }
-
- def_builtin (d->mask, d->name, type, d->code);
- }
-
/* Add the simple unary operators. */
d = (struct builtin_description *) bdesc_1arg;
- for (i = 0; i < sizeof (bdesc_1arg) / sizeof *d; i++, d++)
+ for (i = 0; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
{
enum machine_mode mode0, mode1;
tree type;
- if (d->name == 0)
+ if (d->name == 0 || d->icode == CODE_FOR_nothing)
continue;
mode0 = insn_data[d->icode].operand[0].mode;
@@ -4902,6 +6105,16 @@ altivec_init_builtins (void)
type = v8hi_ftype_v16qi;
else if (mode0 == V4SImode && mode1 == V8HImode)
type = v4si_ftype_v8hi;
+ else if (mode0 == V2SImode && mode1 == V2SImode)
+ type = v2si_ftype_v2si;
+ else if (mode0 == V2SFmode && mode1 == V2SFmode)
+ type = v2sf_ftype_v2sf;
+ else if (mode0 == V2SFmode && mode1 == V2SImode)
+ type = v2sf_ftype_v2si;
+ else if (mode0 == V2SImode && mode1 == V2SFmode)
+ type = v2si_ftype_v2sf;
+ else if (mode0 == V2SImode && mode1 == QImode)
+ type = v2si_ftype_char;
else
abort ();
@@ -5550,9 +6763,10 @@ validate_condition_mode (code, mode)
abort ();
/* These should never be generated except for
- flag_unsafe_math_optimizations. */
+ flag_unsafe_math_optimizations and flag_finite_math_only. */
if (mode == CCFPmode
&& ! flag_unsafe_math_optimizations
+ && ! flag_finite_math_only
&& (code == LE || code == GE
|| code == UNEQ || code == LTGT
|| code == UNGT || code == UNLT))
@@ -5603,6 +6817,7 @@ branch_positive_comparison_operator (op, mode)
code = GET_CODE (op);
return (code == EQ || code == LT || code == GT
+ || (TARGET_SPE && TARGET_HARD_FLOAT && !TARGET_FPRS && code == NE)
|| code == LTU || code == GTU
|| code == UNORDERED);
}
@@ -6054,8 +7269,12 @@ ccr_bit (op, scc_p)
switch (code)
{
case NE:
+ if (TARGET_SPE && TARGET_HARD_FLOAT && cc_mode == CCFPmode)
+ return base_bit + 1;
return scc_p ? base_bit + 3 : base_bit + 2;
case EQ:
+ if (TARGET_SPE && TARGET_HARD_FLOAT && cc_mode == CCFPmode)
+ return base_bit + 1;
return base_bit + 2;
case GT: case GTU: case UNLE:
return base_bit + 1;
@@ -6095,29 +7314,93 @@ rs6000_got_register (value)
return pic_offset_table_rtx;
}
-/* Functions to init, mark and free struct machine_function.
- These will be called, via pointer variables,
- from push_function_context and pop_function_context. */
+/* Function to init struct machine_function.
+ This will be called, via a pointer variable,
+ from push_function_context. */
-static void
-rs6000_init_machine_status (p)
- struct function *p;
+static struct machine_function *
+rs6000_init_machine_status ()
{
- p->machine = (machine_function *) xcalloc (1, sizeof (machine_function));
+ return ggc_alloc_cleared (sizeof (machine_function));
}
+
+/* These macros test for integers and extract the low-order bits. */
+#define INT_P(X) \
+((GET_CODE (X) == CONST_INT || GET_CODE (X) == CONST_DOUBLE) \
+ && GET_MODE (X) == VOIDmode)
-static void
-rs6000_free_machine_status (p)
- struct function *p;
+#define INT_LOWPART(X) \
+ (GET_CODE (X) == CONST_INT ? INTVAL (X) : CONST_DOUBLE_LOW (X))
+
+int
+extract_MB (op)
+ rtx op;
{
- if (p->machine == NULL)
- return;
+ int i;
+ unsigned long val = INT_LOWPART (op);
+
+ /* If the high bit is zero, the value is the first 1 bit we find
+ from the left. */
+ if ((val & 0x80000000) == 0)
+ {
+ if ((val & 0xffffffff) == 0)
+ abort ();
- free (p->machine);
- p->machine = NULL;
+ i = 1;
+ while (((val <<= 1) & 0x80000000) == 0)
+ ++i;
+ return i;
+ }
+
+ /* If the high bit is set and the low bit is not, or the mask is all
+ 1's, the value is zero. */
+ if ((val & 1) == 0 || (val & 0xffffffff) == 0xffffffff)
+ return 0;
+
+ /* Otherwise we have a wrap-around mask. Look for the first 0 bit
+ from the right. */
+ i = 31;
+ while (((val >>= 1) & 1) != 0)
+ --i;
+
+ return i;
+}
+
+int
+extract_ME (op)
+ rtx op;
+{
+ int i;
+ unsigned long val = INT_LOWPART (op);
+
+ /* If the low bit is zero, the value is the first 1 bit we find from
+ the right. */
+ if ((val & 1) == 0)
+ {
+ if ((val & 0xffffffff) == 0)
+ abort ();
+
+ i = 30;
+ while (((val >>= 1) & 1) == 0)
+ --i;
+
+ return i;
+ }
+
+ /* If the low bit is set and the high bit is not, or the mask is all
+ 1's, the value is 31. */
+ if ((val & 0x80000000) == 0 || (val & 0xffffffff) == 0xffffffff)
+ return 31;
+
+ /* Otherwise we have a wrap-around mask. Look for the first 0 bit
+ from the left. */
+ i = 0;
+ while (((val <<= 1) & 0x80000000) != 0)
+ ++i;
+
+ return i;
}
-
/* Print an operand. Recognize special options, documented below. */
#if TARGET_ELF
@@ -6136,14 +7419,7 @@ print_operand (file, x, code)
{
int i;
HOST_WIDE_INT val;
-
- /* These macros test for integers and extract the low-order bits. */
-#define INT_P(X) \
-((GET_CODE (X) == CONST_INT || GET_CODE (X) == CONST_DOUBLE) \
- && GET_MODE (X) == VOIDmode)
-
-#define INT_LOWPART(X) \
- (GET_CODE (X) == CONST_INT ? INTVAL (X) : CONST_DOUBLE_LOW (X))
+ unsigned HOST_WIDE_INT uval;
switch (code)
{
@@ -6209,6 +7485,15 @@ print_operand (file, x, code)
fprintf (file, "crnor %d,%d,%d\n\t", base_bit + 3,
base_bit + 2, base_bit + 2);
}
+ else if (TARGET_SPE && TARGET_HARD_FLOAT
+ && GET_CODE (x) == EQ
+ && GET_MODE (XEXP (x, 0)) == CCFPmode)
+ {
+ int base_bit = 4 * (REGNO (XEXP (x, 0)) - CR0_REGNO);
+
+ fprintf (file, "crnor %d,%d,%d\n\t", base_bit + 1,
+ base_bit + 1, base_bit + 1);
+ }
return;
case 'E':
@@ -6239,7 +7524,7 @@ print_operand (file, x, code)
case 'G':
/* X is a constant integer. If it is negative, print "m",
- otherwise print "z". This is to make a aze or ame insn. */
+ otherwise print "z". This is to make an aze or ame insn. */
if (GET_CODE (x) != CONST_INT)
output_operand_lossage ("invalid %%G value");
else if (INTVAL (x) >= 0)
@@ -6319,6 +7604,11 @@ print_operand (file, x, code)
output_operand_lossage ("invalid %%K value");
print_operand_address (file, XEXP (XEXP (x, 0), 0));
fputs ("@l", file);
+ /* For GNU as, there must be a non-alphanumeric character
+ between 'l' and the number. The '-' is added by
+ print_operand() already. */
+ if (INTVAL (XEXP (XEXP (x, 0), 1)) >= 0)
+ fputs ("+", file);
print_operand (file, XEXP (XEXP (x, 0), 1), 0);
}
return;
@@ -6354,34 +7644,7 @@ print_operand (file, x, code)
if (! mask_operand (x, SImode))
output_operand_lossage ("invalid %%m value");
- val = INT_LOWPART (x);
-
- /* If the high bit is set and the low bit is not, the value is zero.
- If the high bit is zero, the value is the first 1 bit we find from
- the left. */
- if ((val & 0x80000000) && ((val & 1) == 0))
- {
- putc ('0', file);
- return;
- }
- else if ((val & 0x80000000) == 0)
- {
- for (i = 1; i < 32; i++)
- if ((val <<= 1) & 0x80000000)
- break;
- fprintf (file, "%d", i);
- return;
- }
-
- /* Otherwise, look for the first 0 bit from the right. The result is its
- number plus 1. We know the low-order bit is one. */
- for (i = 0; i < 32; i++)
- if (((val >>= 1) & 1) == 0)
- break;
-
- /* If we ended in ...01, i would be 0. The correct value is 31, so
- we want 31 - i. */
- fprintf (file, "%d", 31 - i);
+ fprintf (file, "%d", extract_MB (x));
return;
case 'M':
@@ -6389,35 +7652,7 @@ print_operand (file, x, code)
if (! mask_operand (x, SImode))
output_operand_lossage ("invalid %%M value");
- val = INT_LOWPART (x);
-
- /* If the low bit is set and the high bit is not, the value is 31.
- If the low bit is zero, the value is the first 1 bit we find from
- the right. */
- if ((val & 1) && ((val & 0x80000000) == 0))
- {
- fputs ("31", file);
- return;
- }
- else if ((val & 1) == 0)
- {
- for (i = 0; i < 32; i++)
- if ((val >>= 1) & 1)
- break;
-
- /* If we had ....10, i would be 0. The result should be
- 30, so we need 30 - i. */
- fprintf (file, "%d", 30 - i);
- return;
- }
-
- /* Otherwise, look for the first 0 bit from the left. The result is its
- number minus 1. We know the high-order bit is one. */
- for (i = 0; i < 32; i++)
- if (((val <<= 1) & 0x80000000) == 0)
- break;
-
- fprintf (file, "%d", i);
+ fprintf (file, "%d", extract_ME (x));
return;
/* %n outputs the negative of its operand. */
@@ -6513,68 +7748,43 @@ print_operand (file, x, code)
return;
case 'S':
- /* PowerPC64 mask position. All 0's and all 1's are excluded.
+ /* PowerPC64 mask position. All 0's is excluded.
CONST_INT 32-bit mask is considered sign-extended so any
transition must occur within the CONST_INT, not on the boundary. */
if (! mask64_operand (x, DImode))
output_operand_lossage ("invalid %%S value");
- val = INT_LOWPART (x);
+ uval = INT_LOWPART (x);
- if (val & 1) /* Clear Left */
+ if (uval & 1) /* Clear Left */
{
- for (i = 0; i < HOST_BITS_PER_WIDE_INT; i++)
- if (!((val >>= 1) & 1))
- break;
-
-#if HOST_BITS_PER_WIDE_INT == 32
- if (GET_CODE (x) == CONST_DOUBLE && i == 32)
- {
- val = CONST_DOUBLE_HIGH (x);
-
- if (val == 0)
- --i;
- else
- for (i = 32; i < 64; i++)
- if (!((val >>= 1) & 1))
- break;
- }
-#endif
- /* i = index of last set bit from right
- mask begins at 63 - i from left */
- if (i > 63)
- output_operand_lossage ("%%S computed all 1's mask");
-
- fprintf (file, "%d", 63 - i);
- return;
+ uval &= ((unsigned HOST_WIDE_INT) 1 << 63 << 1) - 1;
+ i = 64;
}
- else /* Clear Right */
+ else /* Clear Right */
{
- for (i = 0; i < HOST_BITS_PER_WIDE_INT; i++)
- if ((val >>= 1) & 1)
- break;
+ uval = ~uval;
+ uval &= ((unsigned HOST_WIDE_INT) 1 << 63 << 1) - 1;
+ i = 63;
+ }
+ while (uval != 0)
+ --i, uval >>= 1;
+ if (i < 0)
+ abort ();
+ fprintf (file, "%d", i);
+ return;
-#if HOST_BITS_PER_WIDE_INT == 32
- if (GET_CODE (x) == CONST_DOUBLE && i == 32)
- {
- val = CONST_DOUBLE_HIGH (x);
+ case 't':
+ /* Like 'J' but get to the OVERFLOW/UNORDERED bit. */
+ if (GET_CODE (x) != REG || GET_MODE (x) != CCmode)
+ abort ();
- if (val == (HOST_WIDE_INT) -1)
- --i;
- else
- for (i = 32; i < 64; i++)
- if ((val >>= 1) & 1)
- break;
- }
-#endif
- /* i = index of last clear bit from right
- mask ends at 62 - i from left */
- if (i > 62)
- output_operand_lossage ("%%S computed all 0's mask");
+ /* Bit 3 is OV bit. */
+ i = 4 * (REGNO (x) - CR0_REGNO) + 3;
- fprintf (file, "%d", 62 - i);
- return;
- }
+ /* If we want bit 31, write a shift count of zero, not 32. */
+ fprintf (file, "%d", i == 31 ? 0 : i + 1);
+ return;
case 'T':
/* Print the symbolic name of a branch target register. */
@@ -6768,7 +7978,7 @@ print_operand (file, x, code)
}
return;
- /* Print AltiVec memory operand. */
+ /* Print AltiVec or SPE memory operand. */
case 'y':
{
rtx tmp;
@@ -6778,6 +7988,30 @@ print_operand (file, x, code)
tmp = XEXP (x, 0);
+ if (TARGET_SPE)
+ {
+ /* Handle [reg]. */
+ if (GET_CODE (tmp) == REG)
+ {
+ fprintf (file, "0(%s)", reg_names[REGNO (tmp)]);
+ break;
+ }
+ /* Handle [reg+UIMM]. */
+ else if (GET_CODE (tmp) == PLUS &&
+ GET_CODE (XEXP (tmp, 1)) == CONST_INT)
+ {
+ int x;
+
+ if (GET_CODE (XEXP (tmp, 0)) != REG)
+ abort ();
+
+ x = INTVAL (XEXP (tmp, 1));
+ fprintf (file, "%d(%s)", x, reg_names[REGNO (XEXP (tmp, 0))]);
+ break;
+ }
+
+ /* Fall through. Must be [reg+reg]. */
+ }
if (GET_CODE (tmp) == REG)
fprintf (file, "0,%s", reg_names[REGNO (tmp)]);
else if (GET_CODE (tmp) == PLUS && GET_CODE (XEXP (tmp, 1)) == REG)
@@ -6909,7 +8143,7 @@ print_operand_address (file, x)
abort ();
}
-/* Target hook for assembling integer objects. The powerpc version has
+/* Target hook for assembling integer objects. The PowerPC version has
to handle fixup entries for relocatable code if RELOCATABLE_NEEDS_FIXUP
is defined. It also needs to handle DI-mode objects on 64-bit
targets. */
@@ -6972,6 +8206,37 @@ rs6000_assemble_integer (x, size, aligned_p)
#endif /* RELOCATABLE_NEEDS_FIXUP */
return default_assemble_integer (x, size, aligned_p);
}
+
+#ifdef HAVE_GAS_HIDDEN
+/* Emit an assembler directive to set symbol visibility for DECL to
+ VISIBILITY_TYPE. */
+
+static void
+rs6000_assemble_visibility (decl, vis)
+ tree decl;
+ int vis;
+{
+ /* Functions need to have their entry point symbol visibility set as
+ well as their descriptor symbol visibility. */
+ if (DEFAULT_ABI == ABI_AIX && TREE_CODE (decl) == FUNCTION_DECL)
+ {
+ static const char * const visibility_types[] = {
+ NULL, "internal", "hidden", "protected"
+ };
+
+ const char *name, *type;
+
+ name = ((* targetm.strip_name_encoding)
+ (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl))));
+ type = visibility_types[vis];
+
+ fprintf (asm_out_file, "\t.%s\t%s\n", type, name);
+ fprintf (asm_out_file, "\t.%s\t.%s\n", type, name);
+ }
+ else
+ default_assemble_visibility (decl, vis);
+}
+#endif
enum rtx_code
rs6000_reverse_condition (mode, code)
@@ -7006,15 +8271,134 @@ rs6000_generate_compare (code)
/* First, the compare. */
compare_result = gen_reg_rtx (comp_mode);
- emit_insn (gen_rtx_SET (VOIDmode, compare_result,
- gen_rtx_COMPARE (comp_mode,
- rs6000_compare_op0,
- rs6000_compare_op1)));
+
+ /* SPE FP compare instructions on the GPRs. Yuck! */
+ if ((TARGET_SPE && TARGET_HARD_FLOAT) && rs6000_compare_fp_p)
+ {
+ rtx cmp, or1, or2, or_result, compare_result2;
+
+ switch (code)
+ {
+ case EQ:
+ case UNEQ:
+ case NE:
+ case LTGT:
+ cmp = flag_unsafe_math_optimizations
+ ? gen_tstsfeq_gpr (compare_result, rs6000_compare_op0,
+ rs6000_compare_op1)
+ : gen_cmpsfeq_gpr (compare_result, rs6000_compare_op0,
+ rs6000_compare_op1);
+ break;
+ case GT:
+ case GTU:
+ case UNGT:
+ case UNGE:
+ case GE:
+ case GEU:
+ cmp = flag_unsafe_math_optimizations
+ ? gen_tstsfgt_gpr (compare_result, rs6000_compare_op0,
+ rs6000_compare_op1)
+ : gen_cmpsfgt_gpr (compare_result, rs6000_compare_op0,
+ rs6000_compare_op1);
+ break;
+ case LT:
+ case LTU:
+ case UNLT:
+ case UNLE:
+ case LE:
+ case LEU:
+ cmp = flag_unsafe_math_optimizations
+ ? gen_tstsflt_gpr (compare_result, rs6000_compare_op0,
+ rs6000_compare_op1)
+ : gen_cmpsflt_gpr (compare_result, rs6000_compare_op0,
+ rs6000_compare_op1);
+ break;
+ default:
+ abort ();
+ }
+
+ /* Synthesize LE and GE from LT/GT || EQ. */
+ if (code == LE || code == GE || code == LEU || code == GEU)
+ {
+ /* Synthesize GE/LE frome GT/LT || EQ. */
+
+ emit_insn (cmp);
+
+ switch (code)
+ {
+ case LE: code = LT; break;
+ case GE: code = GT; break;
+ case LEU: code = LT; break;
+ case GEU: code = GT; break;
+ default: abort ();
+ }
+
+ or1 = gen_reg_rtx (SImode);
+ or2 = gen_reg_rtx (SImode);
+ or_result = gen_reg_rtx (CCEQmode);
+ compare_result2 = gen_reg_rtx (CCFPmode);
+
+ /* Do the EQ. */
+ cmp = flag_unsafe_math_optimizations
+ ? gen_tstsfeq_gpr (compare_result2, rs6000_compare_op0,
+ rs6000_compare_op1)
+ : gen_cmpsfeq_gpr (compare_result2, rs6000_compare_op0,
+ rs6000_compare_op1);
+ emit_insn (cmp);
+
+ /* The MC8540 FP compare instructions set the CR bits
+ differently than other PPC compare instructions. For
+ that matter, there is no generic test instruction, but a
+ testgt, testlt, and testeq. For a true condition, bit 2
+ is set (x1xx) in the CR. Following the traditional CR
+ values:
+
+ LT GT EQ OV
+ bit3 bit2 bit1 bit0
+
+ ... bit 2 would be a GT CR alias, so later on we
+ look in the GT bits for the branch instructins.
+ However, we must be careful to emit correct RTL in
+ the meantime, so optimizations don't get confused. */
+
+ or1 = gen_rtx (NE, SImode, compare_result, const0_rtx);
+ or2 = gen_rtx (NE, SImode, compare_result2, const0_rtx);
+
+ /* OR them together. */
+ cmp = gen_rtx_SET (VOIDmode, or_result,
+ gen_rtx_COMPARE (CCEQmode,
+ gen_rtx_IOR (SImode, or1, or2),
+ const_true_rtx));
+ compare_result = or_result;
+ code = EQ;
+ }
+ else
+ {
+ /* We only care about 1 bit (x1xx), so map everything to NE to
+ maintain rtl sanity. We'll get to the right bit (x1xx) at
+ code output time. */
+ if (code == NE || code == LTGT)
+ /* Do the inverse here because we have no cmpne
+ instruction. We use the cmpeq instruction and expect
+ to get a 0 instead. */
+ code = EQ;
+ else
+ code = NE;
+ }
+
+ emit_insn (cmp);
+ }
+ 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;
except for flag_unsafe_math_optimizations we don't bother. */
if (rs6000_compare_fp_p
&& ! flag_unsafe_math_optimizations
+ && ! (TARGET_HARD_FLOAT && TARGET_SPE)
&& (code == LE || code == GE
|| code == UNEQ || code == LTGT
|| code == UNGT || code == UNLT))
@@ -7104,7 +8488,7 @@ rs6000_emit_cbranch (code, loc)
condition code register and its mode specifies what kind of
comparison we made.
- REVERSED is non-zero if we should reverse the sense of the comparison.
+ REVERSED is nonzero if we should reverse the sense of the comparison.
INSN is the insn. */
@@ -7142,6 +8526,19 @@ output_cbranch (op, label, reversed, insn)
code = reverse_condition (code);
}
+ if ((TARGET_SPE && TARGET_HARD_FLOAT) && mode == CCFPmode)
+ {
+ /* The efscmp/tst* instructions twiddle bit 2, which maps nicely
+ to the GT bit. */
+ if (code == EQ)
+ /* Opposite of GT. */
+ code = UNLE;
+ else if (code == NE)
+ code = GT;
+ else
+ abort ();
+ }
+
switch (code)
{
/* Not all of these are actually distinct opcodes, but
@@ -7168,21 +8565,30 @@ output_cbranch (op, label, reversed, insn)
/* Maybe we have a guess as to how likely the branch is.
The old mnemonics don't have a way to specify this information. */
+ pred = "";
note = find_reg_note (insn, REG_BR_PROB, NULL_RTX);
if (note != NULL_RTX)
{
/* PROB is the difference from 50%. */
int prob = INTVAL (XEXP (note, 0)) - REG_BR_PROB_BASE / 2;
-
- /* For branches that are very close to 50%, assume not-taken. */
- if (abs (prob) > REG_BR_PROB_BASE / 20
- && ((prob > 0) ^ need_longbranch))
- pred = "+";
- else
- pred = "-";
+ bool always_hint = rs6000_cpu != PROCESSOR_POWER4;
+
+ /* Only hint for highly probable/improbable branches on newer
+ cpus as static prediction overrides processor dynamic
+ prediction. For older cpus we may as well always hint, but
+ assume not taken for branches that are very close to 50% as a
+ mispredicted taken branch is more expensive than a
+ mispredicted not-taken branch. */
+ if (always_hint
+ || abs (prob) > REG_BR_PROB_BASE / 100 * 48)
+ {
+ if (abs (prob) > REG_BR_PROB_BASE / 20
+ && ((prob > 0) ^ need_longbranch))
+ pred = "+";
+ else
+ pred = "-";
+ }
}
- else
- pred = "";
if (label == NULL)
s += sprintf (s, "{b%sr|b%slr%s} ", ccode, ccode, pred);
@@ -7228,7 +8634,10 @@ rs6000_emit_cmove (dest, op, true_cond, false_cond)
rtx temp;
/* These modes should always match. */
- if (GET_MODE (op1) != compare_mode)
+ if (GET_MODE (op1) != compare_mode
+ /* In the isel case however, we can use a compare immediate, so
+ op1 may be a small constant. */
+ && (!TARGET_ISEL || !short_cint_operand (op1, VOIDmode)))
return 0;
if (GET_MODE (true_cond) != result_mode)
return 0;
@@ -7237,10 +8646,12 @@ rs6000_emit_cmove (dest, op, true_cond, false_cond)
/* First, work out if the hardware can do this at all, or
if it's too slow... */
- /* If the comparison is an integer one, since we only have fsel
- it'll be cheaper to use a branch. */
if (! rs6000_compare_fp_p)
- return 0;
+ {
+ if (TARGET_ISEL)
+ return rs6000_emit_int_cmove (dest, op, true_cond, false_cond);
+ return 0;
+ }
/* Eliminate half of the comparisons by switching operands, this
makes the remaining code simpler. */
@@ -7264,11 +8675,11 @@ rs6000_emit_cmove (dest, op, true_cond, false_cond)
/* We're going to try to implement comparions by performing
a subtract, then comparing against zero. Unfortunately,
Inf - Inf is NaN which is not zero, and so if we don't
- know that the the operand is finite and the comparison
+ know that the operand is finite and the comparison
would treat EQ different to UNORDERED, we can't do it. */
if (! flag_unsafe_math_optimizations
&& code != GT && code != UNGE
- && (GET_CODE (op1) != CONST_DOUBLE || target_isinf (c1))
+ && (GET_CODE (op1) != CONST_DOUBLE || real_isinf (&c1))
/* Constructs of the form (a OP b ? a : b) are safe. */
&& ((! rtx_equal_p (op0, false_cond) && ! rtx_equal_p (op1, false_cond))
|| (! rtx_equal_p (op0, true_cond)
@@ -7372,6 +8783,53 @@ rs6000_emit_cmove (dest, op, true_cond, false_cond)
return 1;
}
+/* Same as above, but for ints (isel). */
+
+static int
+rs6000_emit_int_cmove (dest, op, true_cond, false_cond)
+ rtx dest;
+ rtx op;
+ rtx true_cond;
+ rtx false_cond;
+{
+ rtx condition_rtx, cr;
+
+ /* All isel implementations thus far are 32-bits. */
+ if (GET_MODE (rs6000_compare_op0) != SImode)
+ return 0;
+
+ /* We still have to do the compare, because isel doesn't do a
+ compare, it just looks at the CRx bits set by a previous compare
+ instruction. */
+ condition_rtx = rs6000_generate_compare (GET_CODE (op));
+ cr = XEXP (condition_rtx, 0);
+
+ if (GET_MODE (cr) == CCmode)
+ emit_insn (gen_isel_signed (dest, condition_rtx,
+ true_cond, false_cond, cr));
+ else
+ emit_insn (gen_isel_unsigned (dest, condition_rtx,
+ true_cond, false_cond, cr));
+
+ return 1;
+}
+
+const char *
+output_isel (operands)
+ rtx *operands;
+{
+ enum rtx_code code;
+
+ code = GET_CODE (operands[1]);
+ if (code == GE || code == GEU || code == LE || code == LEU || code == NE)
+ {
+ PUT_CODE (operands[1], reverse_condition (code));
+ return "isel %0,%3,%2,%j1";
+ }
+ else
+ return "isel %0,%2,%3,%j1";
+}
+
void
rs6000_emit_minmax (dest, code, op0, op1)
rtx dest;
@@ -7380,12 +8838,19 @@ rs6000_emit_minmax (dest, code, op0, op1)
rtx op1;
{
enum machine_mode mode = GET_MODE (op0);
+ enum rtx_code c;
rtx target;
+
+ if (code == SMAX || code == SMIN)
+ c = GE;
+ else
+ c = GEU;
+
if (code == SMAX || code == UMAX)
- target = emit_conditional_move (dest, GE, op0, op1, mode,
+ target = emit_conditional_move (dest, c, op0, op1, mode,
op0, op1, mode, 0);
else
- target = emit_conditional_move (dest, GE, op0, op1, mode,
+ target = emit_conditional_move (dest, c, op0, op1, mode,
op1, op0, mode, 0);
if (target == NULL_RTX)
abort ();
@@ -7409,13 +8874,14 @@ 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;
#if TARGET_MACHO
- if (flag_pic && current_function_uses_pic_offset_table &&
- (first_reg > RS6000_PIC_OFFSET_TABLE_REGNUM))
+ if (flag_pic
+ && current_function_uses_pic_offset_table
+ && first_reg > RS6000_PIC_OFFSET_TABLE_REGNUM)
return RS6000_PIC_OFFSET_TABLE_REGNUM;
#endif
@@ -7583,6 +9049,10 @@ is_altivec_return_reg (reg, xyes)
+---------------------------------------+
| Save area for VRSAVE register (Z) | 8+P+A+V+L+X+W+Y
+---------------------------------------+
+ | SPE: area for 64-bit GP registers |
+ +---------------------------------------+
+ | SPE alignment padding |
+ +---------------------------------------+
| saved CR (C) | 8+P+A+V+L+X+W+Y+Z
+---------------------------------------+
| Save area for GP registers (G) | 8+P+A+V+L+X+W+Y+Z+C
@@ -7638,6 +9108,20 @@ rs6000_stack_info ()
else
info_ptr->gp_size = reg_size * (32 - info_ptr->first_gp_reg_save);
+ /* For the SPE, we have an additional upper 32-bits on each GPR.
+ Ideally we should save the entire 64-bits only when the upper
+ half is used in SIMD instructions. Since we only record
+ registers live (not the size they are used in), this proves
+ difficult because we'd have to traverse the instruction chain at
+ the right time, taking reload into account. This is a real pain,
+ so we opt to save the GPRs in 64-bits always. Anyone overly
+ concerned with frame size can fix this. ;-).
+
+ So... since we save all GPRs (except the SP) in 64-bits, the
+ traditional GP save area will be empty. */
+ if (TARGET_SPE_ABI)
+ info_ptr->gp_size = 0;
+
info_ptr->first_fp_reg_save = first_fp_reg_to_save ();
info_ptr->fp_size = 8 * (64 - info_ptr->first_fp_reg_save);
@@ -7686,7 +9170,9 @@ rs6000_stack_info ()
unsigned int i;
for (i = 0; EH_RETURN_DATA_REGNO (i) != INVALID_REGNUM; ++i)
continue;
- ehrd_size = i * UNITS_PER_WORD;
+
+ /* SPE saves EH registers in 64-bits. */
+ ehrd_size = i * (TARGET_SPE_ABI ? UNITS_PER_SPE_WORD : UNITS_PER_WORD);
}
else
ehrd_size = 0;
@@ -7699,7 +9185,12 @@ rs6000_stack_info ()
info_ptr->parm_size = RS6000_ALIGN (current_function_outgoing_args_size,
8);
- if (TARGET_ALTIVEC_ABI)
+ if (TARGET_SPE_ABI)
+ info_ptr->spe_gp_size = 8 * (32 - info_ptr->first_gp_reg_save);
+ else
+ info_ptr->spe_gp_size = 0;
+
+ if (TARGET_ALTIVEC_ABI && TARGET_ALTIVEC_VRSAVE)
{
info_ptr->vrsave_mask = compute_vrsave_mask ();
info_ptr->vrsave_size = info_ptr->vrsave_mask ? 4 : 0;
@@ -7754,7 +9245,26 @@ rs6000_stack_info ()
info_ptr->gp_save_offset = info_ptr->fp_save_offset - info_ptr->gp_size;
info_ptr->cr_save_offset = info_ptr->gp_save_offset - info_ptr->cr_size;
- if (TARGET_ALTIVEC_ABI)
+ if (TARGET_SPE_ABI)
+ {
+ /* Align stack so SPE GPR save area is aligned on a
+ double-word boundary. */
+ if (info_ptr->spe_gp_size != 0)
+ info_ptr->spe_padding_size
+ = 8 - (-info_ptr->cr_save_offset % 8);
+ else
+ info_ptr->spe_padding_size = 0;
+
+ info_ptr->spe_gp_save_offset
+ = info_ptr->cr_save_offset
+ - info_ptr->spe_padding_size
+ - info_ptr->spe_gp_size;
+
+ /* Adjust for SPE case. */
+ info_ptr->toc_save_offset
+ = info_ptr->spe_gp_save_offset - info_ptr->toc_size;
+ }
+ else if (TARGET_ALTIVEC_ABI)
{
info_ptr->vrsave_save_offset
= info_ptr->cr_save_offset - info_ptr->vrsave_size;
@@ -7787,10 +9297,11 @@ rs6000_stack_info ()
+ info_ptr->altivec_size
+ info_ptr->altivec_padding_size
+ info_ptr->vrsave_size
+ + info_ptr->spe_gp_size
+ + info_ptr->spe_padding_size
+ 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);
@@ -7841,6 +9352,9 @@ rs6000_stack_info ()
if (! TARGET_ALTIVEC_ABI || info_ptr->vrsave_mask == 0)
info_ptr->vrsave_save_offset = 0;
+ if (! TARGET_SPE_ABI || info_ptr->spe_gp_size == 0)
+ info_ptr->spe_gp_save_offset = 0;
+
if (! info_ptr->lr_save_p)
info_ptr->lr_save_offset = 0;
@@ -7882,6 +9396,9 @@ debug_stack_info (info)
if (TARGET_ALTIVEC_ABI)
fprintf (stderr, "\tALTIVEC ABI extensions enabled.\n");
+ if (TARGET_SPE_ABI)
+ fprintf (stderr, "\tSPE ABI extensions enabled.\n");
+
if (info->first_gp_reg_save != 32)
fprintf (stderr, "\tfirst_gp_reg_save = %5d\n", info->first_gp_reg_save);
@@ -7920,6 +9437,10 @@ debug_stack_info (info)
fprintf (stderr, "\taltivec_save_offset = %5d\n",
info->altivec_save_offset);
+ if (info->spe_gp_save_offset)
+ fprintf (stderr, "\tspe_gp_save_offset = %5d\n",
+ info->spe_gp_save_offset);
+
if (info->vrsave_save_offset)
fprintf (stderr, "\tvrsave_save_offset = %5d\n",
info->vrsave_save_offset);
@@ -7954,6 +9475,9 @@ debug_stack_info (info)
if (info->gp_size)
fprintf (stderr, "\tgp_size = %5d\n", info->gp_size);
+ if (info->spe_gp_size)
+ fprintf (stderr, "\tspe_gp_size = %5d\n", info->spe_gp_size);
+
if (info->fp_size)
fprintf (stderr, "\tfp_size = %5d\n", info->fp_size);
@@ -7967,6 +9491,10 @@ debug_stack_info (info)
fprintf (stderr, "\taltivec_padding_size= %5d\n",
info->altivec_padding_size);
+ if (info->spe_padding_size)
+ fprintf (stderr, "\tspe_padding_size = %5d\n",
+ info->spe_padding_size);
+
if (info->lr_size)
fprintf (stderr, "\tlr_size = %5d\n", info->lr_size);
@@ -7993,10 +9521,7 @@ rs6000_return_addr (count, frame)
/* Currently we don't optimize very well between prolog and body
code and for PIC code the code can be actually quite bad, so
don't try to be too clever here. */
- if (count != 0
- || flag_pic != 0
- || DEFAULT_ABI == ABI_AIX
- || DEFAULT_ABI == ABI_AIX_NODESC)
+ if (count != 0 || flag_pic != 0)
{
cfun->machine->ra_needs_full_frame = 1;
@@ -8014,25 +9539,92 @@ rs6000_return_addr (count, frame)
return get_hard_reg_initial_val (Pmode, LINK_REGISTER_REGNUM);
}
+/* Say whether a function is a candidate for sibcall handling or not.
+ We do not allow indirect calls to be optimized into sibling calls.
+ Also, we can't do it if there are any vector parameters; there's
+ nowhere to put the VRsave code so it works; note that functions with
+ vector parameters are required to have a prototype, so the argument
+ type info must be available here. (The tail recursion case can work
+ with vector parameters, but there's no way to distinguish here.) */
+int
+function_ok_for_sibcall (fndecl)
+ tree fndecl;
+{
+ tree type;
+ if (fndecl)
+ {
+ if (TARGET_ALTIVEC_VRSAVE)
+ {
+ for (type = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
+ type; type = TREE_CHAIN (type))
+ {
+ if (TREE_CODE (TREE_VALUE (type)) == VECTOR_TYPE)
+ return 0;
+ }
+ }
+ if (DEFAULT_ABI == ABI_DARWIN
+ || (*targetm.binds_local_p) (fndecl))
+ {
+ tree attr_list = TYPE_ATTRIBUTES (TREE_TYPE (fndecl));
+
+ if (!lookup_attribute ("longcall", attr_list)
+ || lookup_attribute ("shortcall", attr_list))
+ return 1;
+ }
+ }
+ return 0;
+}
+
static int
rs6000_ra_ever_killed ()
{
rtx top;
+ rtx reg;
+ rtx insn;
-#ifdef ASM_OUTPUT_MI_THUNK
- if (current_function_is_thunk)
+ /* Irritatingly, there are two kinds of thunks -- those created with
+ TARGET_ASM_OUTPUT_MI_THUNK and those with DECL_THUNK_P that go
+ through the regular part of the compiler. This is a very hacky
+ way to tell them apart. */
+ if (current_function_is_thunk && !no_new_pseudos)
return 0;
-#endif
- if (!has_hard_reg_initial_val (Pmode, LINK_REGISTER_REGNUM)
- || cfun->machine->ra_needs_full_frame)
- return regs_ever_live[LINK_REGISTER_REGNUM];
+ /* regs_ever_live has LR marked as used if any sibcalls are present,
+ but this should not force saving and restoring in the
+ pro/epilogue. Likewise, reg_set_between_p thinks a sibcall
+ clobbers LR, so that is inappropriate. */
+
+ /* Also, the prologue can generate a store into LR that
+ doesn't really count, like this:
+
+ move LR->R0
+ bcl to set PIC register
+ move LR->R31
+ move R0->LR
+
+ When we're called from the epilogue, we need to avoid counting
+ this as a store. */
+
push_topmost_sequence ();
top = get_insns ();
pop_topmost_sequence ();
+ reg = gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM);
- return reg_set_between_p (gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM),
- top, NULL_RTX);
+ for (insn = NEXT_INSN (top); insn != NULL_RTX; insn = NEXT_INSN (insn))
+ {
+ if (INSN_P (insn))
+ {
+ if (FIND_REG_INC_NOTE (insn, reg))
+ return 1;
+ else if (GET_CODE (insn) == CALL_INSN
+ && !SIBLING_CALL_P (insn))
+ return 1;
+ else if (set_of (reg, insn) != NULL_RTX
+ && !prologue_epilogue_contains (insn))
+ return 1;
+ }
+ }
+ return 0;
}
/* Add a REG_MAYBE_DEAD note to the insn. */
@@ -8053,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)
@@ -8061,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)
{
@@ -8109,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)
{
@@ -8126,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 ();
@@ -8273,10 +9874,8 @@ rs6000_emit_eh_toc_restore (stacksize)
bottom_of_stack, stacksize,
NULL_RTX, 1, OPTAB_WIDEN);
- emit_move_insn (tocompare,
- GEN_INT (trunc_int_for_mode (TARGET_32BIT
- ? 0x80410014
- : 0xE8410028, SImode)));
+ emit_move_insn (tocompare, gen_int_mode (TARGET_32BIT ? 0x80410014
+ : 0xE8410028, SImode));
if (insn_after_throw == NULL_RTX)
abort ();
@@ -8460,8 +10059,19 @@ rs6000_frame_related (insn, reg, val, reg2, rreg)
{
rtx real, temp;
+ /* copy_rtx will not make unique copies of registers, so we need to
+ ensure we don't have unwanted sharing here. */
+ if (reg == reg2)
+ reg = gen_raw_REG (GET_MODE (reg), REGNO (reg));
+
+ if (reg == rreg)
+ reg = gen_raw_REG (GET_MODE (reg), REGNO (reg));
+
real = copy_rtx (PATTERN (insn));
+ if (reg2 != NULL_RTX)
+ real = replace_rtx (real, reg2, rreg);
+
real = replace_rtx (real, reg,
gen_rtx_PLUS (Pmode, gen_rtx_REG (Pmode,
STACK_POINTER_REGNUM),
@@ -8514,9 +10124,6 @@ rs6000_frame_related (insn, reg, val, reg2, rreg)
else
abort ();
- if (reg2 != NULL_RTX)
- real = replace_rtx (real, reg2, rreg);
-
RTX_FRAME_RELATED_P (insn) = 1;
REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
real,
@@ -8585,6 +10192,78 @@ generate_set_vrsave (reg, info, epiloguep)
return insn;
}
+/* Save a register into the frame, and emit RTX_FRAME_RELATED_P notes.
+ Save REGNO into [FRAME_REG + OFFSET] in mode MODE. */
+
+static void
+emit_frame_save (frame_reg, frame_ptr, mode, regno, offset, total_size)
+ rtx frame_reg;
+ rtx frame_ptr;
+ enum machine_mode mode;
+ unsigned int regno;
+ int offset;
+ int total_size;
+{
+ rtx reg, offset_rtx, insn, mem, addr, int_rtx;
+ rtx replacea, replaceb;
+
+ int_rtx = GEN_INT (offset);
+
+ /* Some cases that need register indexed addressing. */
+ if ((TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
+ || (TARGET_SPE_ABI
+ && SPE_VECTOR_MODE (mode)
+ && !SPE_CONST_OFFSET_OK (offset)))
+ {
+ /* Whomever calls us must make sure r11 is available in the
+ flow path of instructions in the prologue. */
+ offset_rtx = gen_rtx_REG (Pmode, 11);
+ emit_move_insn (offset_rtx, int_rtx);
+
+ replacea = offset_rtx;
+ replaceb = int_rtx;
+ }
+ else
+ {
+ offset_rtx = int_rtx;
+ replacea = NULL_RTX;
+ replaceb = NULL_RTX;
+ }
+
+ reg = gen_rtx_REG (mode, regno);
+ addr = gen_rtx_PLUS (Pmode, frame_reg, offset_rtx);
+ mem = gen_rtx_MEM (mode, addr);
+ set_mem_alias_set (mem, rs6000_sr_alias_set);
+
+ insn = emit_move_insn (mem, reg);
+
+ rs6000_frame_related (insn, frame_ptr, total_size, replacea, replaceb);
+}
+
+/* Emit an offset memory reference suitable for a frame store, while
+ converting to a valid addressing mode. */
+
+static rtx
+gen_frame_mem_offset (mode, reg, offset)
+ enum machine_mode mode;
+ rtx reg;
+ int offset;
+{
+ rtx int_rtx, offset_rtx;
+
+ int_rtx = GEN_INT (offset);
+
+ if (TARGET_SPE_ABI && SPE_VECTOR_MODE (mode))
+ {
+ offset_rtx = gen_rtx_REG (Pmode, FIXED_SCRATCH);
+ emit_move_insn (offset_rtx, int_rtx);
+ }
+ else
+ offset_rtx = int_rtx;
+
+ return gen_rtx_MEM (mode, gen_rtx_PLUS (Pmode, reg, offset_rtx));
+}
+
/* Emit function prologue as insns. */
void
@@ -8602,7 +10281,14 @@ rs6000_emit_prologue ()
int using_store_multiple;
HOST_WIDE_INT sp_offset = 0;
+ if (TARGET_SPE_ABI)
+ {
+ reg_mode = V2SImode;
+ reg_size = 8;
+ }
+
using_store_multiple = (TARGET_MULTIPLE && ! TARGET_POWERPC64
+ && !TARGET_SPE_ABI
&& info->first_gp_reg_save < 31);
saving_FPRs_inline = (info->first_fp_reg_save == 64
|| FP_SAVE_INLINE (info->first_fp_reg_save));
@@ -8712,20 +10398,10 @@ rs6000_emit_prologue ()
for (i = 0; i < 64 - info->first_fp_reg_save; i++)
if ((regs_ever_live[info->first_fp_reg_save+i]
&& ! call_used_regs[info->first_fp_reg_save+i]))
- {
- rtx addr, reg, mem;
- reg = gen_rtx_REG (DFmode, info->first_fp_reg_save + i);
- addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
- GEN_INT (info->fp_save_offset
- + sp_offset
- + 8 * i));
- mem = gen_rtx_MEM (DFmode, addr);
- set_mem_alias_set (mem, rs6000_sr_alias_set);
-
- insn = emit_move_insn (mem, reg);
- rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
- NULL_RTX, NULL_RTX);
- }
+ emit_frame_save (frame_reg_rtx, frame_ptr_rtx, DFmode,
+ info->first_fp_reg_save + i,
+ info->fp_save_offset + sp_offset + 8 * i,
+ info->total_size);
}
else if (info->first_fp_reg_save != 64)
{
@@ -8765,10 +10441,9 @@ rs6000_emit_prologue ()
the store-multiple instructions. */
if (using_store_multiple)
{
- rtvec p, dwarfp;
+ rtvec p;
int i;
p = rtvec_alloc (32 - info->first_gp_reg_save);
- dwarfp = rtvec_alloc (32 - info->first_gp_reg_save);
for (i = 0; i < 32 - info->first_gp_reg_save; i++)
{
rtx addr, reg, mem;
@@ -8793,21 +10468,50 @@ 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;
reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
- addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
- GEN_INT (info->gp_save_offset
- + sp_offset
- + reg_size * i));
- mem = gen_rtx_MEM (reg_mode, addr);
- set_mem_alias_set (mem, rs6000_sr_alias_set);
- insn = emit_move_insn (mem, reg);
- rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
- NULL_RTX, NULL_RTX);
+ if (TARGET_SPE_ABI)
+ {
+ int offset = info->spe_gp_save_offset + sp_offset + 8 * i;
+ rtx b;
+
+ if (!SPE_CONST_OFFSET_OK (offset))
+ {
+ b = gen_rtx_REG (Pmode, FIXED_SCRATCH);
+ emit_move_insn (b, GEN_INT (offset));
+ }
+ else
+ b = GEN_INT (offset);
+
+ addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, b);
+ mem = gen_rtx_MEM (V2SImode, addr);
+ set_mem_alias_set (mem, rs6000_sr_alias_set);
+ insn = emit_move_insn (mem, reg);
+
+ if (GET_CODE (b) == CONST_INT)
+ rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
+ NULL_RTX, NULL_RTX);
+ else
+ rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
+ b, GEN_INT (offset));
+ }
+ else
+ {
+ addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
+ GEN_INT (info->gp_save_offset
+ + sp_offset
+ + reg_size * i));
+ mem = gen_rtx_MEM (reg_mode, addr);
+ set_mem_alias_set (mem, rs6000_sr_alias_set);
+
+ insn = emit_move_insn (mem, reg);
+ rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
+ NULL_RTX, NULL_RTX);
+ }
}
}
@@ -8819,22 +10523,14 @@ rs6000_emit_prologue ()
for (i = 0; ; ++i)
{
- rtx addr, reg, mem;
-
regno = EH_RETURN_DATA_REGNO (i);
if (regno == INVALID_REGNUM)
break;
- reg = gen_rtx_REG (reg_mode, regno);
- addr = plus_constant (frame_reg_rtx,
- info->ehrd_offset + sp_offset
- + reg_size * (int) i);
- mem = gen_rtx_MEM (reg_mode, addr);
- set_mem_alias_set (mem, rs6000_sr_alias_set);
-
- insn = emit_move_insn (mem, reg);
- rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
- NULL_RTX, NULL_RTX);
+ emit_frame_save (frame_reg_rtx, frame_ptr_rtx, reg_mode, regno,
+ info->ehrd_offset + sp_offset
+ + reg_size * (int) i,
+ info->total_size);
}
}
@@ -8889,7 +10585,7 @@ rs6000_emit_prologue ()
/* Set frame pointer, if needed. */
if (frame_pointer_needed)
{
- insn = emit_move_insn (gen_rtx_REG (reg_mode, FRAME_POINTER_REGNUM),
+ insn = emit_move_insn (gen_rtx_REG (Pmode, FRAME_POINTER_REGNUM),
sp_reg_rtx);
RTX_FRAME_RELATED_P (insn) = 1;
}
@@ -8917,17 +10613,21 @@ rs6000_emit_prologue ()
gen_rtx_REG (Pmode, 11));
}
+#if TARGET_MACHO
if (DEFAULT_ABI == ABI_DARWIN
&& flag_pic && current_function_uses_pic_offset_table)
{
rtx dest = gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM);
+ char *picbase = machopic_function_base_name ();
+ rtx src = gen_rtx_SYMBOL_REF (Pmode, ggc_alloc_string (picbase, -1));
- rs6000_maybe_dead (emit_insn (gen_load_macho_picbase (dest)));
+ rs6000_maybe_dead (emit_insn (gen_load_macho_picbase (dest, src)));
rs6000_maybe_dead (
emit_move_insn (gen_rtx_REG (Pmode, RS6000_PIC_OFFSET_TABLE_REGNUM),
gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM)));
}
+#endif
}
/* Write function prologue. */
@@ -9016,8 +10716,15 @@ rs6000_emit_epilogue (sibcall)
int reg_size = TARGET_POWERPC64 ? 8 : 4;
int i;
+ if (TARGET_SPE_ABI)
+ {
+ reg_mode = V2SImode;
+ reg_size = 8;
+ }
+
info = rs6000_stack_info ();
using_load_multiple = (TARGET_MULTIPLE && ! TARGET_POWERPC64
+ && !TARGET_SPE_ABI
&& info->first_gp_reg_save < 31);
restoring_FPRs_inline = (sibcall
|| current_function_calls_eh_return
@@ -9102,9 +10809,8 @@ rs6000_emit_epilogue (sibcall)
/* Get the old lr if we saved it. */
if (info->lr_save_p)
{
- rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
- GEN_INT (info->lr_save_offset + sp_offset));
- rtx mem = gen_rtx_MEM (Pmode, addr);
+ rtx mem = gen_frame_mem_offset (Pmode, frame_reg_rtx,
+ info->lr_save_offset + sp_offset);
set_mem_alias_set (mem, rs6000_sr_alias_set);
@@ -9135,16 +10841,15 @@ rs6000_emit_epilogue (sibcall)
for (i = 0; ; ++i)
{
- rtx addr, mem;
+ rtx mem;
regno = EH_RETURN_DATA_REGNO (i);
if (regno == INVALID_REGNUM)
break;
- addr = plus_constant (frame_reg_rtx,
- info->ehrd_offset + sp_offset
- + reg_size * (int) i);
- mem = gen_rtx_MEM (reg_mode, addr);
+ mem = gen_frame_mem_offset (reg_mode, frame_reg_rtx,
+ info->ehrd_offset + sp_offset
+ + reg_size * (int) i);
set_mem_alias_set (mem, rs6000_sr_alias_set);
emit_move_insn (gen_rtx_REG (reg_mode, regno), mem);
@@ -9179,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,
@@ -9188,11 +10893,28 @@ rs6000_emit_epilogue (sibcall)
+ reg_size * i));
rtx mem = gen_rtx_MEM (reg_mode, addr);
+ /* Restore 64-bit quantities for SPE. */
+ if (TARGET_SPE_ABI)
+ {
+ int offset = info->spe_gp_save_offset + sp_offset + 8 * i;
+ rtx b;
+
+ if (!SPE_CONST_OFFSET_OK (offset))
+ {
+ b = gen_rtx_REG (Pmode, FIXED_SCRATCH);
+ emit_move_insn (b, GEN_INT (offset));
+ }
+ else
+ b = GEN_INT (offset);
+
+ addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, b);
+ mem = gen_rtx_MEM (V2SImode, addr);
+ }
+
set_mem_alias_set (mem, rs6000_sr_alias_set);
emit_move_insn (gen_rtx_REG (reg_mode,
- info->first_gp_reg_save + i),
- mem);
+ info->first_gp_reg_save + i), mem);
}
/* Restore fpr's if we need to do it without calling a function. */
@@ -9350,7 +11072,6 @@ rs6000_output_function_epilogue (file, size)
HOST_WIDE_INT size ATTRIBUTE_UNUSED;
{
rs6000_stack_t *info = rs6000_stack_info ();
- int optional_tbtab = (optimize_size || TARGET_ELF) ? 0 : 1;
if (! HAVE_epilogue)
{
@@ -9403,22 +11124,33 @@ rs6000_output_function_epilogue (file, size)
System V.4 Powerpc's (and the embedded ABI derived from it) use a
different traceback table. */
- if (DEFAULT_ABI == ABI_AIX && ! flag_inhibit_size_directive)
+ if (DEFAULT_ABI == ABI_AIX && ! flag_inhibit_size_directive
+ && rs6000_traceback != traceback_none)
{
- const char *fname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
+ const char *fname = NULL;
const char *language_string = lang_hooks.name;
int fixed_parms = 0, float_parms = 0, parm_info = 0;
int i;
+ int optional_tbtab;
- while (*fname == '.') /* V.4 encodes . in the name */
- fname++;
+ if (rs6000_traceback == traceback_full)
+ optional_tbtab = 1;
+ else if (rs6000_traceback == traceback_part)
+ optional_tbtab = 0;
+ else
+ optional_tbtab = !optimize_size && !TARGET_ELF;
- /* Need label immediately before tbtab, so we can compute its offset
- from the function start. */
- if (*fname == '*')
- ++fname;
- ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "LT");
- ASM_OUTPUT_LABEL (file, fname);
+ if (optional_tbtab)
+ {
+ fname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
+ while (*fname == '.') /* V.4 encodes . in the name */
+ fname++;
+
+ /* Need label immediately before tbtab, so we can compute
+ its offset from the function start. */
+ ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "LT");
+ ASM_OUTPUT_LABEL (file, fname);
+ }
/* The .tbtab pseudo-op can only be used for the first eight
expressions, since it can't handle the possibly variable
@@ -9513,7 +11245,7 @@ rs6000_output_function_epilogue (file, size)
if (mode == SFmode)
bits = 0x2;
- else if (mode == DFmode)
+ else if (mode == DFmode || mode == TFmode)
bits = 0x3;
else
abort ();
@@ -9590,6 +11322,8 @@ rs6000_output_function_epilogue (file, size)
/* Omit this list of longs, because there are no CTL anchors. */
/* Length of function name. */
+ if (*fname == '*')
+ ++fname;
fprintf (file, "\t.short %d\n", (int) strlen (fname));
/* Function name. */
@@ -9602,7 +11336,6 @@ rs6000_output_function_epilogue (file, size)
fputs ("\t.align 2\n", file);
}
- return;
}
/* A C compound statement that outputs the assembler code for a thunk
@@ -9637,11 +11370,12 @@ rs6000_output_function_epilogue (file, size)
calls FUNCTION instead of jumping to it. The generic approach does
not support varargs. */
-void
-output_mi_thunk (file, thunk_fndecl, delta, function)
+static void
+rs6000_output_mi_thunk (file, thunk_fndecl, delta, vcall_offset, function)
FILE *file;
tree thunk_fndecl ATTRIBUTE_UNUSED;
- int delta;
+ HOST_WIDE_INT delta;
+ HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED;
tree function;
{
const char *this_reg =
@@ -9659,9 +11393,9 @@ output_mi_thunk (file, thunk_fndecl, delta, function)
if (delta >= -32768 && delta <= 32767)
{
if (! TARGET_NEW_MNEMONICS)
- fprintf (file, "\tcal %s,%d(%s)\n", this_reg, delta, this_reg);
+ fprintf (file, "\tcal %s,%d(%s)\n", this_reg, (int) delta, this_reg);
else
- fprintf (file, "\taddi %s,%s,%d\n", this_reg, this_reg, delta);
+ fprintf (file, "\taddi %s,%s,%d\n", this_reg, this_reg, (int) delta);
}
/* 64-bit constants. If "int" is 32 bits, we'll never hit this abort. */
@@ -9671,7 +11405,7 @@ output_mi_thunk (file, thunk_fndecl, delta, function)
/* Large constants that can be done by one addis instruction. */
else if ((delta & 0xffff) == 0)
asm_fprintf (file, "\t{cau|addis} %s,%s,%d\n", this_reg, this_reg,
- delta >> 16);
+ (int) (delta >> 16));
/* 32-bit constants that can be done by an add and addis instruction. */
else
@@ -9702,6 +11436,7 @@ output_mi_thunk (file, thunk_fndecl, delta, function)
case ABI_V4:
case ABI_AIX_NODESC:
+ case ABI_DARWIN:
prefix = "";
break;
}
@@ -9712,8 +11447,10 @@ output_mi_thunk (file, thunk_fndecl, delta, function)
fname = XSTR (XEXP (DECL_RTL (function), 0), 0);
if (current_file_function_operand (XEXP (DECL_RTL (function), 0), VOIDmode)
- && ! lookup_attribute ("longcall",
- TYPE_ATTRIBUTES (TREE_TYPE (function))))
+ && (! lookup_attribute ("longcall",
+ TYPE_ATTRIBUTES (TREE_TYPE (function)))
+ || lookup_attribute ("shortcall",
+ TYPE_ATTRIBUTES (TREE_TYPE (function)))))
{
fprintf (file, "\tb %s", prefix);
assemble_name (file, fname);
@@ -9745,10 +11482,7 @@ output_mi_thunk (file, thunk_fndecl, delta, function)
}
assemble_name (file, fname);
putc ('\n', file);
- if (TARGET_ELF)
- function_section (current_function_decl);
- else
- text_section ();
+ function_section (current_function_decl);
if (TARGET_MINIMAL_TOC)
asm_fprintf (file, (TARGET_32BIT)
? "\t{l|lwz} %s,%s(%s)\n" : "\tld %s,%s(%s)\n", r12,
@@ -9795,7 +11529,6 @@ output_mi_thunk (file, thunk_fndecl, delta, function)
}
}
}
-
/* A quick summary of the various types of 'constant-pool tables'
under PowerPC:
@@ -9843,20 +11576,34 @@ static unsigned
rs6000_hash_constant (k)
rtx k;
{
- unsigned result = (GET_CODE (k) << 3) ^ GET_MODE (k);
- const char *format = GET_RTX_FORMAT (GET_CODE (k));
- int flen = strlen (format);
- int fidx;
+ enum rtx_code code = GET_CODE (k);
+ enum machine_mode mode = GET_MODE (k);
+ unsigned result = (code << 3) ^ mode;
+ const char *format;
+ int flen, fidx;
- if (GET_CODE (k) == LABEL_REF)
- return result * 1231 + X0INT (XEXP (k, 0), 3);
+ format = GET_RTX_FORMAT (code);
+ flen = strlen (format);
+ fidx = 0;
- if (GET_CODE (k) == CONST_DOUBLE)
- fidx = 1;
- else if (GET_CODE (k) == CODE_LABEL)
- fidx = 3;
- else
- fidx = 0;
+ switch (code)
+ {
+ case LABEL_REF:
+ return result * 1231 + (unsigned) INSN_UID (XEXP (k, 0));
+
+ case CONST_DOUBLE:
+ if (mode != VOIDmode)
+ return real_hash (CONST_DOUBLE_REAL_VALUE (k)) * result;
+ flen = 2;
+ break;
+
+ case CODE_LABEL:
+ fidx = 3;
+ break;
+
+ default:
+ break;
+ }
for (; fidx < flen; fidx++)
switch (format[fidx])
@@ -9893,6 +11640,7 @@ rs6000_hash_constant (k)
default:
abort ();
}
+
return result;
}
@@ -9919,29 +11667,7 @@ toc_hash_eq (h1, h2)
!= ((const struct toc_hash_struct *) h2)->key_mode)
return 0;
- /* Gotcha: One of these const_doubles will be in memory.
- The other may be on the constant-pool chain.
- So rtx_equal_p will think they are different... */
- if (r1 == r2)
- return 1;
- if (GET_CODE (r1) != GET_CODE (r2)
- || GET_MODE (r1) != GET_MODE (r2))
- return 0;
- if (GET_CODE (r1) == CONST_DOUBLE)
- {
- int format_len = strlen (GET_RTX_FORMAT (CONST_DOUBLE));
- int i;
- for (i = 1; i < format_len; i++)
- if (XWINT (r1, i) != XWINT (r2, i))
- return 0;
-
- return 1;
- }
- else if (GET_CODE (r1) == LABEL_REF)
- return (CODE_LABEL_NUMBER (XEXP (r1, 0))
- == CODE_LABEL_NUMBER (XEXP (r2, 0)));
- else
- return rtx_equal_p (r1, r2);
+ return rtx_equal_p (r1, r2);
}
/* Mark the hash table-entry HASH_ENTRY. */
@@ -10071,7 +11797,42 @@ output_toc (file, x, labelno, mode)
/* Handle FP constants specially. Note that if we have a minimal
TOC, things we put here aren't actually in the TOC, so we can allow
FP constants. */
- if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == DFmode)
+ if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == TFmode)
+ {
+ REAL_VALUE_TYPE rv;
+ long k[4];
+
+ REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
+ REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, k);
+
+ if (TARGET_64BIT)
+ {
+ if (TARGET_MINIMAL_TOC)
+ fputs (DOUBLE_INT_ASM_OP, file);
+ else
+ fprintf (file, "\t.tc FT_%lx_%lx_%lx_%lx[TC],",
+ k[0] & 0xffffffff, k[1] & 0xffffffff,
+ k[2] & 0xffffffff, k[3] & 0xffffffff);
+ fprintf (file, "0x%lx%08lx,0x%lx%08lx\n",
+ k[0] & 0xffffffff, k[1] & 0xffffffff,
+ k[2] & 0xffffffff, k[3] & 0xffffffff);
+ return;
+ }
+ else
+ {
+ if (TARGET_MINIMAL_TOC)
+ fputs ("\t.long ", file);
+ else
+ fprintf (file, "\t.tc FT_%lx_%lx_%lx_%lx[TC],",
+ k[0] & 0xffffffff, k[1] & 0xffffffff,
+ k[2] & 0xffffffff, k[3] & 0xffffffff);
+ fprintf (file, "0x%lx,0x%lx,0x%lx,0x%lx\n",
+ k[0] & 0xffffffff, k[1] & 0xffffffff,
+ k[2] & 0xffffffff, k[3] & 0xffffffff);
+ return;
+ }
+ }
+ else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == DFmode)
{
REAL_VALUE_TYPE rv;
long k[2];
@@ -10232,7 +11993,7 @@ output_toc (file, x, labelno, mode)
else
abort ();
- STRIP_NAME_ENCODING (real_name, name);
+ real_name = (*targetm.strip_name_encoding) (name);
if (TARGET_MINIMAL_TOC)
fputs (TARGET_32BIT ? "\t.long " : DOUBLE_INT_ASM_OP, file);
else
@@ -10368,7 +12129,7 @@ rs6000_gen_section_name (buf, filename, section_desc)
}
len = strlen (after_last_slash) + strlen (section_desc) + 2;
- *buf = (char *) permalloc (len);
+ *buf = (char *) xmalloc (len);
p = *buf;
*p++ = '_';
@@ -10407,7 +12168,7 @@ output_profile_hook (labelno)
rtx fun;
ASM_GENERATE_INTERNAL_LABEL (buf, "LP", labelno);
- STRIP_NAME_ENCODING (label_name, ggc_strdup (buf));
+ label_name = (*targetm.strip_name_encoding) (ggc_strdup (buf));
fun = gen_rtx_SYMBOL_REF (Pmode, label_name);
emit_library_call (init_one_libfunc (RS6000_MCOUNT), 0, VOIDmode, 1,
@@ -10546,18 +12307,24 @@ rs6000_adjust_cost (insn, link, dep_insn, cost)
switch (get_attr_type (insn))
{
case TYPE_JMPREG:
- /* Tell the first scheduling pass about the latency between
+ /* Tell the first scheduling pass about the latency between
a mtctr and bctr (and mtlr and br/blr). The first
scheduling pass will not know about this latency since
the mtctr instruction, which has the latency associated
to it, will be generated by reload. */
- return TARGET_POWER ? 5 : 4;
+ return TARGET_POWER ? 5 : 4;
case TYPE_BRANCH:
/* Leave some extra cycles between a compare and its
dependent branch, to inhibit expensive mispredicts. */
- if ((rs6000_cpu_attr == CPU_PPC750
- || rs6000_cpu_attr == CPU_PPC7400
- || rs6000_cpu_attr == CPU_PPC7450)
+ if ((rs6000_cpu_attr == CPU_PPC603
+ || rs6000_cpu_attr == CPU_PPC604
+ || rs6000_cpu_attr == CPU_PPC604E
+ || rs6000_cpu_attr == CPU_PPC620
+ || rs6000_cpu_attr == CPU_PPC630
+ || rs6000_cpu_attr == CPU_PPC750
+ || rs6000_cpu_attr == CPU_PPC7400
+ || rs6000_cpu_attr == CPU_PPC7450
+ || rs6000_cpu_attr == CPU_POWER4)
&& recog_memoized (dep_insn)
&& (INSN_CODE (dep_insn) >= 0)
&& (get_attr_type (dep_insn) == TYPE_COMPARE
@@ -10638,6 +12405,7 @@ rs6000_issue_rate ()
case CPU_PPC604E:
case CPU_PPC620:
case CPU_PPC630:
+ case CPU_POWER4:
return 4;
default:
return 1;
@@ -10730,12 +12498,13 @@ rs6000_initialize_trampoline (addr, fnaddr, cxt)
const struct attribute_spec rs6000_attribute_table[] =
{
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
- { "longcall", 0, 0, false, true, true, rs6000_handle_longcall_attribute },
- { NULL, 0, 0, false, false, false, NULL }
+ { "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 a "longcall" attribute; arguments as in struct
- attribute_spec.handler. */
+/* Handle a "longcall" or "shortcall" attribute; arguments as in
+ struct attribute_spec.handler. */
static tree
rs6000_handle_longcall_attribute (node, name, args, flags, no_add_attrs)
@@ -10757,6 +12526,20 @@ rs6000_handle_longcall_attribute (node, name, args, flags, no_add_attrs)
return NULL_TREE;
}
+/* Set longcall attributes on all functions declared when
+ rs6000_default_long_calls is true. */
+static void
+rs6000_set_default_type_attributes (type)
+ tree type;
+{
+ if (rs6000_default_long_calls
+ && (TREE_CODE (type) == FUNCTION_TYPE
+ || TREE_CODE (type) == METHOD_TYPE))
+ TYPE_ATTRIBUTES (type) = tree_cons (get_identifier ("longcall"),
+ NULL_TREE,
+ TYPE_ATTRIBUTES (type));
+}
+
/* Return a reference suitable for calling a function with the
longcall attribute. */
@@ -10785,6 +12568,8 @@ rs6000_longcall_ref (call_ref)
}
+#ifdef USING_ELFOS_H
+
/* A C statement or statements to switch to the appropriate section
for output of RTX in mode MODE. You can assume that RTX is some
kind of constant in RTL. The argument MODE is redundant except in
@@ -10794,22 +12579,16 @@ rs6000_longcall_ref (call_ref)
Do not define this macro if you put all constants in the read-only
data section. */
-#ifdef USING_ELFOS_H
-
-void
-rs6000_select_rtx_section (mode, x)
+static void
+rs6000_elf_select_rtx_section (mode, x, align)
enum machine_mode mode;
rtx x;
+ unsigned HOST_WIDE_INT align;
{
if (ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (x, mode))
toc_section ();
- else if (flag_pic
- && (GET_CODE (x) == SYMBOL_REF
- || GET_CODE (x) == LABEL_REF
- || GET_CODE (x) == CONST))
- data_section ();
else
- const_section ();
+ default_elf_select_rtx_section (mode, x, align);
}
/* A C statement or statements to switch to the appropriate
@@ -10817,46 +12596,14 @@ rs6000_select_rtx_section (mode, x)
or a constant of some sort. RELOC indicates whether forming
the initial value of DECL requires link-time relocations. */
-void
-rs6000_select_section (decl, reloc)
+static void
+rs6000_elf_select_section (decl, reloc, align)
tree decl;
int reloc;
+ unsigned HOST_WIDE_INT align;
{
- int size = int_size_in_bytes (TREE_TYPE (decl));
- int needs_sdata;
- int readonly;
- static void (* const sec_funcs[4]) PARAMS ((void)) = {
- &const_section,
- &sdata2_section,
- &data_section,
- &sdata_section
- };
-
- needs_sdata = (size > 0
- && size <= g_switch_value
- && rs6000_sdata != SDATA_NONE
- && (rs6000_sdata != SDATA_DATA || TREE_PUBLIC (decl)));
-
- if (TREE_CODE (decl) == STRING_CST)
- readonly = ! flag_writable_strings;
- else if (TREE_CODE (decl) == VAR_DECL)
- readonly = (! ((flag_pic || DEFAULT_ABI == ABI_AIX) && reloc)
- && TREE_READONLY (decl)
- && ! TREE_SIDE_EFFECTS (decl)
- && DECL_INITIAL (decl)
- && DECL_INITIAL (decl) != error_mark_node
- && TREE_CONSTANT (DECL_INITIAL (decl)));
- else if (TREE_CODE (decl) == CONSTRUCTOR)
- readonly = (! ((flag_pic || DEFAULT_ABI == ABI_AIX) && reloc)
- && ! TREE_SIDE_EFFECTS (decl)
- && TREE_CONSTANT (decl));
- else
- readonly = ! ((flag_pic || DEFAULT_ABI == ABI_AIX) && reloc);
-
- if (needs_sdata && rs6000_sdata != SDATA_EABI)
- readonly = 0;
-
- (*sec_funcs[(readonly ? 0 : 2) + (needs_sdata ? 1 : 0)])();
+ default_elf_select_section_1 (decl, reloc, align,
+ flag_pic || DEFAULT_ABI == ABI_AIX);
}
/* A C statement to build up a unique section name, expressed as a
@@ -10865,120 +12612,18 @@ rs6000_select_section (decl, reloc)
link-time relocations. If you do not define this macro, GCC will use
the symbol name prefixed by `.' as the section name. Note - this
macro can now be called for uninitialized data items as well as
- initialised data and functions. */
+ initialized data and functions. */
-void
-rs6000_unique_section (decl, reloc)
+static void
+rs6000_elf_unique_section (decl, reloc)
tree decl;
int reloc;
{
- int len;
- int sec;
- const char *name;
- char *string;
- const char *prefix;
-
- static const char *const prefixes[7][2] =
- {
- { ".rodata.", ".gnu.linkonce.r." },
- { ".sdata2.", ".gnu.linkonce.s2." },
- { ".data.", ".gnu.linkonce.d." },
- { ".sdata.", ".gnu.linkonce.s." },
- { ".bss.", ".gnu.linkonce.b." },
- { ".sbss.", ".gnu.linkonce.sb." },
- { ".text.", ".gnu.linkonce.t." }
- };
-
- if (TREE_CODE (decl) == FUNCTION_DECL)
- sec = 6;
- else
- {
- int readonly;
- int needs_sdata;
- int size;
-
- if (TREE_CODE (decl) == STRING_CST)
- readonly = ! flag_writable_strings;
- else if (TREE_CODE (decl) == VAR_DECL)
- readonly = (! ((flag_pic || DEFAULT_ABI == ABI_AIX) && reloc)
- && TREE_READONLY (decl)
- && ! TREE_SIDE_EFFECTS (decl)
- && TREE_CONSTANT (DECL_INITIAL (decl)));
- else
- readonly = ! ((flag_pic || DEFAULT_ABI == ABI_AIX) && reloc);
-
- size = int_size_in_bytes (TREE_TYPE (decl));
- needs_sdata = (size > 0
- && size <= g_switch_value
- && rs6000_sdata != SDATA_NONE
- && (rs6000_sdata != SDATA_DATA || TREE_PUBLIC (decl)));
-
- if (DECL_INITIAL (decl) == 0
- || DECL_INITIAL (decl) == error_mark_node)
- sec = 4;
- else if (! readonly)
- sec = 2;
- else
- sec = 0;
-
- if (needs_sdata)
- {
- /* .sdata2 is only for EABI. */
- if (sec == 0 && rs6000_sdata != SDATA_EABI)
- sec = 2;
- sec += 1;
- }
- }
-
- STRIP_NAME_ENCODING (name, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
- prefix = prefixes[sec][DECL_ONE_ONLY (decl)];
- len = strlen (name) + strlen (prefix);
- string = alloca (len + 1);
-
- sprintf (string, "%s%s", prefix, name);
-
- DECL_SECTION_NAME (decl) = build_string (len, string);
-}
-
-
-static bool
-rs6000_binds_local_p (exp)
- tree exp;
-{
- bool local_p;
- tree attr;
-
- /* A non-decl is an entry in the constant pool. */
- if (!DECL_P (exp))
- local_p = true;
- /* Static variables are always local. */
- else if (! TREE_PUBLIC (exp))
- local_p = true;
- /* Otherwise, variables defined outside this object may not be local. */
- else if (DECL_EXTERNAL (exp))
- local_p = false;
- /* Linkonce and weak data are never local. */
- else if (DECL_ONE_ONLY (exp) || DECL_WEAK (exp))
- local_p = false;
- /* If PIC, then assume that any global name can be overridden by
- * symbols resolved from other modules. */
- else if (flag_pic || rs6000_flag_pic)
- local_p = false;
- /* Uninitialized COMMON variable may be unified with symbols
- * resolved from other modules. */
- else if (DECL_COMMON (exp)
- && (DECL_INITIAL (exp) == NULL
- || DECL_INITIAL (exp) == error_mark_node))
- local_p = false;
- /* Otherwise we're left with initialized (or non-common) global data
- * which is of necessity defined locally. */
- else
- local_p = true;
-
- return local_p;
+ default_unique_section_1 (decl, reloc,
+ flag_pic || DEFAULT_ABI == ABI_AIX);
}
-
+
/* If we are referencing a function that is static or is known to be
in this file, make the SYMBOL_REF special. We can use this to indicate
that we can branch to this function without emitting a no-op after the
@@ -10987,14 +12632,18 @@ rs6000_binds_local_p (exp)
the function descriptor name. This saves a lot of overriding code
to read the prefixes. */
-void
-rs6000_encode_section_info (decl)
+static void
+rs6000_elf_encode_section_info (decl, first)
tree decl;
+ int first;
{
+ if (!first)
+ return;
+
if (TREE_CODE (decl) == FUNCTION_DECL)
{
rtx sym_ref = XEXP (DECL_RTL (decl), 0);
- if (rs6000_binds_local_p (decl))
+ if ((*targetm.binds_local_p) (decl))
SYMBOL_REF_FLAG (sym_ref) = 1;
if (DEFAULT_ABI == ABI_AIX)
@@ -11019,7 +12668,7 @@ rs6000_encode_section_info (decl)
const char *name = (char *)0;
int len = 0;
- if (rs6000_binds_local_p (decl))
+ if ((*targetm.binds_local_p) (decl))
SYMBOL_REF_FLAG (sym_ref) = 1;
if (section_name)
@@ -11048,7 +12697,6 @@ rs6000_encode_section_info (decl)
|| (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);
@@ -11059,6 +12707,43 @@ rs6000_encode_section_info (decl)
}
}
+static const char *
+rs6000_elf_strip_name_encoding (str)
+ const char *str;
+{
+ while (*str == '*' || *str == '@')
+ str++;
+ return str;
+}
+
+static bool
+rs6000_elf_in_small_data_p (decl)
+ tree decl;
+{
+ if (rs6000_sdata == SDATA_NONE)
+ return false;
+
+ if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl))
+ {
+ const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
+ if (strcmp (section, ".sdata") == 0
+ || strcmp (section, ".sdata2") == 0
+ || strcmp (section, ".sbss") == 0)
+ return true;
+ }
+ else
+ {
+ HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (decl));
+
+ if (size > 0
+ && size <= g_switch_value
+ && (rs6000_sdata != SDATA_DATA || TREE_PUBLIC (decl)))
+ return true;
+ }
+
+ return false;
+}
+
#endif /* USING_ELFOS_H */
@@ -11106,16 +12791,9 @@ rs6000_fatal_bad_address (op)
static void
rs6000_add_gc_roots ()
{
- ggc_add_rtx_root (&rs6000_compare_op0, 1);
- ggc_add_rtx_root (&rs6000_compare_op1, 1);
-
toc_hash_table = htab_create (1021, toc_hash_function, toc_hash_eq, NULL);
ggc_add_root (&toc_hash_table, 1, sizeof (toc_hash_table),
toc_hash_mark_table);
-
-#if TARGET_MACHO
- machopic_add_gc_roots ();
-#endif
}
#if TARGET_MACHO
@@ -11177,8 +12855,7 @@ output_compiler_stub ()
{
char tmp_buf[256];
char label_buf[256];
- char *label;
- tree tmp_stub, stub;
+ tree stub;
if (!flag_pic)
for (stub = stub_list; stub; stub = TREE_CHAIN (stub))
@@ -11264,7 +12941,7 @@ output_call (insn, call_dest, operand_number)
if (no_previous_def (funname))
{
- int line_number;
+ int line_number = 0;
rtx label_rtx = gen_label_rtx ();
char *label_buf, temp_buf[256];
ASM_GENERATE_INTERNAL_LABEL (temp_buf, "L",
@@ -11324,7 +13001,7 @@ machopic_output_stub (file, symb, stub)
static int label = 0;
/* Lose our funky encoding stuff so it doesn't contaminate the stub. */
- STRIP_NAME_ENCODING (symb, symb);
+ symb = (*targetm.strip_name_encoding) (symb);
label += 1;
@@ -11444,7 +13121,9 @@ rs6000_elf_section_type_flags (decl, name, reloc)
const char *name;
int reloc;
{
- unsigned int flags = default_section_type_flags (decl, name, reloc);
+ unsigned int flags
+ = default_section_type_flags_1 (decl, name, reloc,
+ flag_pic || DEFAULT_ABI == ABI_AIX);
if (TARGET_RELOCATABLE)
flags |= SECTION_WRITE;
@@ -11522,12 +13201,215 @@ rs6000_elf_asm_out_destructor (symbol, priority)
}
#endif
-#ifdef OBJECT_FORMAT_COFF
+#if TARGET_XCOFF
static void
-xcoff_asm_named_section (name, flags)
+rs6000_xcoff_asm_globalize_label (stream, name)
+ FILE *stream;
const char *name;
- unsigned int flags ATTRIBUTE_UNUSED;
{
- fprintf (asm_out_file, "\t.csect %s\n", name);
+ fputs (GLOBAL_ASM_OP, stream);
+ RS6000_OUTPUT_BASENAME (stream, name);
+ putc ('\n', stream);
}
-#endif
+
+static void
+rs6000_xcoff_asm_named_section (name, flags)
+ const char *name;
+ unsigned int flags;
+{
+ int smclass;
+ static const char * const suffix[3] = { "PR", "RO", "RW" };
+
+ if (flags & SECTION_CODE)
+ smclass = 0;
+ else if (flags & SECTION_WRITE)
+ smclass = 2;
+ else
+ smclass = 1;
+
+ fprintf (asm_out_file, "\t.csect %s%s[%s],%u\n",
+ (flags & SECTION_CODE) ? "." : "",
+ name, suffix[smclass], flags & SECTION_ENTSIZE);
+}
+
+static void
+rs6000_xcoff_select_section (decl, reloc, align)
+ tree decl;
+ int reloc;
+ unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED;
+{
+ if (decl_readonly_section_1 (decl, reloc, 1))
+ {
+ if (TREE_PUBLIC (decl))
+ read_only_data_section ();
+ else
+ read_only_private_data_section ();
+ }
+ else
+ {
+ if (TREE_PUBLIC (decl))
+ data_section ();
+ else
+ private_data_section ();
+ }
+}
+
+static void
+rs6000_xcoff_unique_section (decl, reloc)
+ tree decl;
+ int reloc ATTRIBUTE_UNUSED;
+{
+ const char *name;
+
+ /* Use select_section for private and uninitialized data. */
+ if (!TREE_PUBLIC (decl)
+ || DECL_COMMON (decl)
+ || DECL_INITIAL (decl) == NULL_TREE
+ || DECL_INITIAL (decl) == error_mark_node
+ || (flag_zero_initialized_in_bss
+ && initializer_zerop (DECL_INITIAL (decl))))
+ return;
+
+ name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+ name = (*targetm.strip_name_encoding) (name);
+ DECL_SECTION_NAME (decl) = build_string (strlen (name), name);
+}
+
+/* Select section for constant in constant pool.
+
+ On RS/6000, all constants are in the private read-only data area.
+ However, if this is being placed in the TOC it must be output as a
+ toc entry. */
+
+static void
+rs6000_xcoff_select_rtx_section (mode, x, align)
+ enum machine_mode mode;
+ rtx x;
+ unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED;
+{
+ if (ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (x, mode))
+ toc_section ();
+ else
+ read_only_private_data_section ();
+}
+
+/* Remove any trailing [DS] or the like from the symbol name. */
+
+static const char *
+rs6000_xcoff_strip_name_encoding (name)
+ const char *name;
+{
+ size_t len;
+ if (*name == '*')
+ name++;
+ len = strlen (name);
+ if (name[len - 1] == ']')
+ return ggc_alloc_string (name, len - 4);
+ else
+ return name;
+}
+
+/* Section attributes. AIX is always PIC. */
+
+static unsigned int
+rs6000_xcoff_section_type_flags (decl, name, reloc)
+ tree decl;
+ const char *name;
+ int reloc;
+{
+ unsigned int align;
+ unsigned int flags = default_section_type_flags_1 (decl, name, reloc, 1);
+
+ /* Align to at least UNIT size. */
+ if (flags & SECTION_CODE)
+ align = MIN_UNITS_PER_WORD;
+ else
+ /* Increase alignment of large objects if not already stricter. */
+ align = MAX ((DECL_ALIGN (decl) / BITS_PER_UNIT),
+ int_size_in_bytes (TREE_TYPE (decl)) > MIN_UNITS_PER_WORD
+ ? UNITS_PER_FP_WORD : MIN_UNITS_PER_WORD);
+
+ return flags | (exact_log2 (align) & SECTION_ENTSIZE);
+}
+
+#endif /* TARGET_XCOFF */
+
+/* Note that this is also used for PPC64 Linux. */
+
+static void
+rs6000_xcoff_encode_section_info (decl, first)
+ tree decl;
+ int first ATTRIBUTE_UNUSED;
+{
+ if (TREE_CODE (decl) == FUNCTION_DECL
+ && (*targetm.binds_local_p) (decl))
+ SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0)) = 1;
+}
+
+/* Cross-module name binding. For AIX and PPC64 Linux, which always are
+ PIC, use private copy of flag_pic. */
+
+static bool
+rs6000_binds_local_p (decl)
+ tree decl;
+{
+ return default_binds_local_p_1 (decl, flag_pic || rs6000_flag_pic);
+}
+
+/* A C expression returning the cost of moving data from a register of class
+ CLASS1 to one of CLASS2. */
+
+int
+rs6000_register_move_cost (mode, from, to)
+ enum machine_mode mode;
+ enum reg_class from, to;
+{
+ /* Moves from/to GENERAL_REGS. */
+ if (reg_classes_intersect_p (to, GENERAL_REGS)
+ || reg_classes_intersect_p (from, GENERAL_REGS))
+ {
+ if (! reg_classes_intersect_p (to, GENERAL_REGS))
+ from = to;
+
+ if (from == FLOAT_REGS || from == ALTIVEC_REGS)
+ return (rs6000_memory_move_cost (mode, from, 0)
+ + rs6000_memory_move_cost (mode, GENERAL_REGS, 0));
+
+/* It's more expensive to move CR_REGS than CR0_REGS because of the shift...*/
+ else if (from == CR_REGS)
+ return 4;
+
+ else
+/* A move will cost one instruction per GPR moved. */
+ return 2 * HARD_REGNO_NREGS (0, mode);
+ }
+
+/* Moving between two similar registers is just one instruction. */
+ else if (reg_classes_intersect_p (to, from))
+ return mode == TFmode ? 4 : 2;
+
+/* Everything else has to go through GENERAL_REGS. */
+ else
+ return (rs6000_register_move_cost (mode, GENERAL_REGS, to)
+ + rs6000_register_move_cost (mode, from, GENERAL_REGS));
+}
+
+/* A C expressions returning the cost of moving data of MODE from a register to
+ or from memory. */
+
+int
+rs6000_memory_move_cost (mode, class, in)
+ enum machine_mode mode;
+ enum reg_class class;
+ int in ATTRIBUTE_UNUSED;
+{
+ if (reg_classes_intersect_p (class, GENERAL_REGS))
+ return 4 * HARD_REGNO_NREGS (0, mode);
+ else if (reg_classes_intersect_p (class, FLOAT_REGS))
+ return 4 * HARD_REGNO_NREGS (32, mode);
+ else if (reg_classes_intersect_p (class, ALTIVEC_REGS))
+ return 4 * HARD_REGNO_NREGS (FIRST_ALTIVEC_REGNO, mode);
+ else
+ return 4 + rs6000_register_move_cost (mode, class, GENERAL_REGS);
+}
+
OpenPOWER on IntegriCloud