/* 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 non-zero once AIX common-mode calls have been defined. */
static int common_mode_defined;
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];
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 rtx expand_block_move_mem PARAMS ((enum machine_mode, rtx, rtx));
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 *));
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 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_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));
{"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},
}
}
+ if (rs6000_cpu == PROCESSOR_PPC8540)
+ rs6000_isel = 1;
+
/* If we are optimizing big endian systems for space, use the store
multiple instructions. */
if (BYTES_BIG_ENDIAN && optimize_size)
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)
/* Handle -mvrsave= option. */
rs6000_parse_vrsave_option ();
+ /* Handle -misel= option. */
+ rs6000_parse_isel_option ();
+
#ifdef SUBTARGET_OVERRIDE_OPTIONS
SUBTARGET_OVERRIDE_OPTIONS;
#endif
init_machine_status = rs6000_init_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 ()
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);
}
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. */
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
+ abort ();
+#endif
}
/* Return 1 if the operand is either a non-special register or a constant
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. */
&& 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)
&& (TARGET_POWERPC64 || mode != DImode)
&& mode != TImode)
{
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)));
&& 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)
{
&& 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));
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;
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)
&& (TARGET_POWERPC64 || mode != DImode)
&& LEGITIMATE_INDEXED_ADDRESS_P (x, reg_ok_strict))
return 1;
if (! no_new_pseudos && 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;
case V8HImode:
case V4SFmode:
case V4SImode:
+ case V4HImode:
+ case V2SFmode:
+ case V2SImode:
if (CONSTANT_P (operands[1])
&& !easy_vector_constant (operands[1]))
operands[1] = force_const_mem (mode, operands[1]);
{
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
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)
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. */
cum->words += align + RS6000_ARG_SIZE (mode, type);
- if (GET_MODE_CLASS (mode) == MODE_FLOAT && TARGET_HARD_FLOAT)
+ if (GET_MODE_CLASS (mode) == MODE_FLOAT
+ && TARGET_HARD_FLOAT && TARGET_FPRS)
cum->fregno++;
if (TARGET_DEBUG_ARG)
if (mode == VOIDmode)
{
if (abi == ABI_V4
- && TARGET_HARD_FLOAT
&& cum->nargs_prototype < 0
&& type && (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);
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)
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 = GET_MODE_INNER (mode);
+
+ 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;
}
/* 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;
/* Implement va_start. */
void
-rs6000_va_start (stdarg_p, valist, nextarg)
- int stdarg_p;
+rs6000_va_start (valist, nextarg)
tree valist;
rtx 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;
}
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;
/* 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[] =
/* 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 },
{ 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_evmwlsmf, "__builtin_spe_evmwlsmf", SPE_BUILTIN_EVMWLSMF },
+ { 0, CODE_FOR_spe_evmwlsmfa, "__builtin_spe_evmwlsmfa", SPE_BUILTIN_EVMWLSMFA },
+ { 0, CODE_FOR_spe_evmwlsmfaaw, "__builtin_spe_evmwlsmfaaw", SPE_BUILTIN_EVMWLSMFAAW },
+ { 0, CODE_FOR_spe_evmwlsmfanw, "__builtin_spe_evmwlsmfanw", SPE_BUILTIN_EVMWLSMFANW },
+ { 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_evmwlssf, "__builtin_spe_evmwlssf", SPE_BUILTIN_EVMWLSSF },
+ { 0, CODE_FOR_spe_evmwlssfa, "__builtin_spe_evmwlssfa", SPE_BUILTIN_EVMWLSSFA },
+ { 0, CODE_FOR_spe_evmwlssfaaw, "__builtin_spe_evmwlssfaaw", SPE_BUILTIN_EVMWLSSFAAW },
+ { 0, CODE_FOR_spe_evmwlssfanw, "__builtin_spe_evmwlssfanw", SPE_BUILTIN_EVMWLSSFANW },
+ { 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. */
{ 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[] =
/* 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 },
{ 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
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 const0_rtx;
- switch (icode)
+ 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. */
- case CODE_FOR_altivec_vspltisb:
- case CODE_FOR_altivec_vspltish:
- case CODE_FOR_altivec_vspltisw:
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;
}
- break;
- default:
- break;
}
if (target == 0
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 const0_rtx;
- switch (icode)
+ 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. */
- case CODE_FOR_altivec_vcfux:
- case CODE_FOR_altivec_vcfsx:
- case CODE_FOR_altivec_vctsxs:
- case CODE_FOR_altivec_vctuxs:
- case CODE_FOR_altivec_vspltb:
- case CODE_FOR_altivec_vsplth:
- case CODE_FOR_altivec_vspltw:
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;
}
if (target == 0
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 const0_rtx;
- switch (icode)
+ 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. */
- case CODE_FOR_altivec_vsldoi_4sf:
- case CODE_FOR_altivec_vsldoi_4si:
- case CODE_FOR_altivec_vsldoi_8hi:
- case CODE_FOR_altivec_vsldoi_16qi:
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;
}
- break;
- default:
- break;
}
if (target == 0
enum machine_mode mode0, mode1, mode2;
rtx pat, op0, op1, op2;
struct builtin_description *d;
- int i;
+ size_t i;
*expandedp = false;
return NULL_RTX;
}
-/* 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).
- SUBTARGET may be used as the target for computing one of EXP's operands.
- IGNORE is nonzero if the value is to be ignored. */
+/* 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
-rs6000_expand_builtin (exp, target, subtarget, mode, ignore)
+spe_expand_builtin (exp, target, expandedp)
tree exp;
rtx target;
- rtx subtarget ATTRIBUTE_UNUSED;
- enum machine_mode mode ATTRIBUTE_UNUSED;
- int ignore ATTRIBUTE_UNUSED;
+ 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;
- rtx ret;
- bool success;
-
- if (TARGET_ALTIVEC)
- {
- ret = altivec_expand_builtin (exp, target, &success);
- if (success)
- return ret;
+ *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;
}
- /* Handle simple unary operations. */
- d = (struct builtin_description *) bdesc_1arg;
- for (i = 0; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
+ d = (struct builtin_description *) bdesc_2arg_spe;
+ for (i = 0; i < ARRAY_SIZE (bdesc_2arg_spe); ++i, ++d)
if (d->code == fcode)
- return rs6000_expand_unop_builtin (d->icode, arglist, target);
+ return rs6000_expand_binop_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++)
+ d = (struct builtin_description *) bdesc_spe_predicates;
+ for (i = 0; i < ARRAY_SIZE (bdesc_spe_predicates); ++i, ++d)
if (d->code == fcode)
- return rs6000_expand_binop_builtin (d->icode, arglist, target);
+ return spe_expand_predicate_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++)
+ d = (struct builtin_description *) bdesc_spe_evsel;
+ for (i = 0; i < ARRAY_SIZE (bdesc_spe_evsel); ++i, ++d)
if (d->code == fcode)
- return rs6000_expand_ternop_builtin (d->icode, arglist, target);
+ return spe_expand_evsel_builtin (d->icode, arglist, target);
- abort ();
- return NULL_RTX;
-}
+ 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;
-static void
-rs6000_init_builtins ()
-{
- if (TARGET_ALTIVEC)
- altivec_init_builtins ();
-}
+ 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;
-static void
-altivec_init_builtins (void)
-{
- struct builtin_description *d;
- struct builtin_description_predicates *dp;
+ 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).
+ SUBTARGET may be used as the target for computing one of EXP's operands.
+ IGNORE is nonzero if the value is to be ignored. */
+
+static rtx
+rs6000_expand_builtin (exp, target, subtarget, mode, ignore)
+ tree exp;
+ rtx target;
+ rtx subtarget ATTRIBUTE_UNUSED;
+ 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)
+ {
+ ret = altivec_expand_builtin (exp, target, &success);
- tree endlink = void_list_node;
+ if (success)
+ return ret;
+ }
+ if (TARGET_SPE)
+ {
+ ret = spe_expand_builtin (exp, target, &success);
- 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 (success)
+ return ret;
+ }
- 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))));
+ 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);
- /* V4SI foo (char). */
- tree v4si_ftype_char
- = build_function_type (V4SI_type_node,
- tree_cons (NULL_TREE, char_type_node, endlink));
+ /* 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);
- /* V8HI foo (char). */
- tree v8hi_ftype_char
- = build_function_type (V8HI_type_node,
- tree_cons (NULL_TREE, char_type_node, endlink));
+ /* 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);
+ }
- /* 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));
+ abort ();
+ return NULL_RTX;
+}
- /* 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));
+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 ();
+}
- /* V8HI foo (V16QI). */
- tree v8hi_ftype_v16qi
- = build_function_type (V8HI_type_node,
- tree_cons (NULL_TREE, V16QI_type_node, endlink));
+/* 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
+enable_mask_for_builtins (desc, size, start, end)
+ struct builtin_description *desc;
+ int size;
+ enum rs6000_builtins start, end;
+{
+ int i;
- /* void foo (void *, int, char/literal). */
- tree void_ftype_pvoid_int_char
- = build_function_type (void_type_node,
- tree_cons (NULL_TREE, pvoid_type_node,
- tree_cons (NULL_TREE, integer_type_node,
- tree_cons (NULL_TREE,
- char_type_node,
- endlink))));
+ for (i = 0; i < size; ++i)
+ if (desc[i].code == start)
+ break;
- /* void foo (int *, V4SI). */
- tree void_ftype_pint_v4si
- = 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)));
+ if (i == size)
+ return;
- /* void foo (V4SI). */
- tree void_ftype_v4si
+ for (; i < size; ++i)
+ {
+ /* Flip all the bits on. */
+ desc[i].mask = target_flags;
+ if (desc[i].code == end)
+ break;
+ }
+}
+
+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;
+
+ 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))));
+
+ 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))));
+
+ tree void_ftype_v2si_puint_int
= build_function_type (void_type_node,
- tree_cons (NULL_TREE, V4SI_type_node,
- endlink));
+ tree_cons (NULL_TREE, V2SI_type_node,
+ tree_cons (NULL_TREE, puint_type_node,
+ tree_cons (NULL_TREE,
+ integer_type_node,
+ endlink))));
- /* void foo (vint, int, void *). */
- tree void_ftype_v4si_int_pvoid
+ tree void_ftype_v2si_puint_char
= 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));
+
+ tree int_ftype_void
+ = build_function_type (integer_type_node,
+ tree_cons (NULL_TREE, void_type_node, endlink));
+
+ 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)));
+
+ 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 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)));
+
+ /* 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;
+
+ 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 ();
+ }
+
+ def_builtin (d->mask, d->name, type, d->code);
+ }
+
+ /* Evsel predicates. */
+ d = (struct builtin_description *) bdesc_spe_evsel;
+ for (i = 0; i < ARRAY_SIZE (bdesc_spe_evsel); ++i, d++)
+ {
+ tree type;
+
+ 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 ();
+ }
+
+ def_builtin (d->mask, d->name, type, d->code);
+ }
+}
- /* void foo (void). */
+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 pvoid_type_node = build_pointer_type (void_type_node);
+
+ 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_pfloat
+ = build_function_type_list (V4SF_type_node, pfloat_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_pint
+ = build_function_type_list (V4SI_type_node, pint_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_pshort
+ = build_function_type_list (V8HI_type_node, pshort_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_pchar
+ = build_function_type_list (V16QI_type_node, pchar_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_pvoid
+ = build_function_type_list (V16QI_type_node,
+ integer_type_node, pvoid_type_node, NULL_TREE);
+ tree v8hi_ftype_int_pvoid
+ = build_function_type_list (V8HI_type_node,
+ integer_type_node, pvoid_type_node, NULL_TREE);
+ tree v4si_ftype_int_pvoid
+ = build_function_type_list (V4SI_type_node,
+ integer_type_node, pvoid_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_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_pvoid_int_char
+ = build_function_type_list (void_type_node,
+ pvoid_type_node, integer_type_node,
+ char_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_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);
+
+ /* 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_pvoid_int_char, d->code);
+
+ /* 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;
+
+ 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);
+ }
+
+ /* 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;
+
+ 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);
+ }
+}
+
+static void
+rs6000_common_init_builtins ()
+{
+ struct builtin_description *d;
+ size_t i;
+
+ 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 v2si_ftype_v2si_v2si
+ = build_function_type_list (V2SI_type_node,
+ V2SI_type_node, V2SI_type_node, NULL_TREE);
+
+ tree v2sf_ftype_v2sf_v2sf
+ = build_function_type_list (V2SF_type_node,
+ V2SF_type_node, V2SF_type_node, NULL_TREE);
+
+ tree v2si_ftype_int_int
+ = build_function_type_list (V2SI_type_node,
+ integer_type_node, integer_type_node,
+ NULL_TREE);
+
+ tree v2si_ftype_v2si
+ = build_function_type_list (V2SI_type_node, V2SI_type_node, NULL_TREE);
+
+ 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 v2si_ftype_v2sf
+ = build_function_type_list (V2SI_type_node,
+ V2SF_type_node, NULL_TREE);
- /* vshort foo (void). */
- tree v8hi_ftype_void
- = build_function_type (V8HI_type_node, void_list_node);
+ tree v2si_ftype_v2si_char
+ = build_function_type_list (V2SI_type_node,
+ V2SI_type_node, char_type_node, NULL_TREE);
- 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,
- endlink)));
+ tree v2si_ftype_int_char
+ = build_function_type_list (V2SI_type_node,
+ integer_type_node, char_type_node, NULL_TREE);
- /* These are for the unsigned 5 bit literals. */
+ tree v2si_ftype_char
+ = build_function_type_list (V2SI_type_node, char_type_node, NULL_TREE);
+ tree int_ftype_int_int
+ = build_function_type_list (integer_type_node,
+ integer_type_node, integer_type_node,
+ NULL_TREE);
+
+ 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 (V4SF_type_node,
- tree_cons (NULL_TREE, V4SI_type_node,
- tree_cons (NULL_TREE, char_type_node,
- endlink)));
+ = build_function_type_list (V4SF_type_node,
+ V4SI_type_node, char_type_node, NULL_TREE);
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)));
+ = build_function_type_list (V4SI_type_node,
+ V4SF_type_node, char_type_node, NULL_TREE);
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)));
+ = build_function_type_list (V4SI_type_node,
+ V4SI_type_node, char_type_node, NULL_TREE);
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,
- endlink)));
+ = build_function_type_list (V8HI_type_node,
+ V8HI_type_node, char_type_node, NULL_TREE);
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,
- endlink)));
-
- /* These are for the unsigned 4 bit literals. */
-
+ = build_function_type_list (V16QI_type_node,
+ V16QI_type_node, char_type_node, NULL_TREE);
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))));
-
+ = 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 (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))));
-
+ = 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 (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))));
-
+ = 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 (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))));
-
- /* End of 4 bit literals. */
-
+ = 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 (V4SF_type_node,
- tree_cons (NULL_TREE, V4SF_type_node,
- tree_cons (NULL_TREE, V4SF_type_node,
- endlink)));
+ = build_function_type_list (V4SF_type_node,
+ V4SF_type_node, V4SF_type_node, NULL_TREE);
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))));
+ = 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 (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))));
+ = 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 (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))));
-
+ = 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 (V8HI_type_node,
- tree_cons (NULL_TREE, V8HI_type_node,
- tree_cons (NULL_TREE, V8HI_type_node,
- endlink)));
+ = build_function_type_list (V8HI_type_node,
+ V8HI_type_node, V8HI_type_node, NULL_TREE);
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))));
+ = 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 (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))));
+ = 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 (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))));
-
+ = 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 (V16QI_type_node,
- tree_cons (NULL_TREE, V16QI_type_node,
- tree_cons (NULL_TREE, V16QI_type_node,
- endlink)));
-
+ = build_function_type_list (V16QI_type_node,
+ V16QI_type_node, V16QI_type_node, NULL_TREE);
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 v4si_ftype_v4si
- = build_function_type (V4SI_type_node,
- tree_cons (NULL_TREE, V4SI_type_node, endlink));
-
- tree v8hi_ftype_v8hi
- = build_function_type (V8HI_type_node,
- tree_cons (NULL_TREE, V8HI_type_node, endlink));
-
- tree v16qi_ftype_v16qi
- = build_function_type (V16QI_type_node,
- tree_cons (NULL_TREE, V16QI_type_node, endlink));
-
+ = build_function_type_list (V4SI_type_node,
+ V4SF_type_node, V4SF_type_node, NULL_TREE);
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)));
-
+ = build_function_type_list (V8HI_type_node,
+ V16QI_type_node, V16QI_type_node, NULL_TREE);
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)));
-
+ = build_function_type_list (V4SI_type_node,
+ V8HI_type_node, V8HI_type_node, NULL_TREE);
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)));
-
+ = build_function_type_list (V8HI_type_node,
+ V4SI_type_node, V4SI_type_node, NULL_TREE);
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)));
-
+ = build_function_type_list (V16QI_type_node,
+ V8HI_type_node, V8HI_type_node, NULL_TREE);
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)));
-
+ = build_function_type_list (V4SI_type_node,
+ V16QI_type_node, V4SI_type_node, NULL_TREE);
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)));
-
+ = build_function_type_list (V4SI_type_node,
+ V16QI_type_node, V16QI_type_node, NULL_TREE);
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)));
-
+ = build_function_type_list (V4SI_type_node,
+ V8HI_type_node, V4SI_type_node, NULL_TREE);
tree v4si_ftype_v8hi
- = build_function_type (V4SI_type_node,
- tree_cons (NULL_TREE, V8HI_type_node, endlink));
-
+ = build_function_type_list (V4SI_type_node, V8HI_type_node, NULL_TREE);
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)));
-
+ = build_function_type_list (integer_type_node,
+ V4SI_type_node, V4SI_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)));
-
+ = build_function_type_list (integer_type_node,
+ V4SF_type_node, V4SF_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 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 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 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 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 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 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 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)));
-
+ = build_function_type_list (integer_type_node,
+ V16QI_type_node, V16QI_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)));
-
- 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);
+ = 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;
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;
def_builtin (d->mask, d->name, type, d->code);
}
- /* 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_pvoid_int_char, d->code);
-
- /* 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;
-
- 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 < 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;
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 ();
}
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)
{
def_builtin (d->mask, d->name, type, d->code);
}
- /* 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;
-
- 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 < 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;
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 ();
}
}
-\f
/* Generate a memory reference for expand_block_move, copying volatile,
and other bits from an original memory reference. */
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))
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);
}
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;
return ggc_alloc_cleared (sizeof (machine_function));
}
\f
+/* 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))
+
+int
+extract_MB (op)
+ rtx op;
+{
+ 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 ();
+
+ 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
int 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))
+ HOST_WIDE_INT val;
+ unsigned HOST_WIDE_INT uval;
switch (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':
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;
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':
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. */
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. */
}
return;
- /* Print AltiVec memory operand. */
+ /* Print AltiVec or SPE memory operand. */
case 'y':
{
rtx tmp;
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)
/* 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))
if (really_reversed)
code = rs6000_reverse_condition (mode, 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
/* 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);
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;
/* 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. */
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;
|| (DEFAULT_ABI == ABI_DARWIN && flag_pic)))))
break;
- if (current_function_profile)
- {
- /* AIX must save/restore every register that contains a parameter
- before/after the .__mcount call plus an additional register
- for the static chain, if needed; use registers from 30 down to 22
- to do this. */
- if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_DARWIN)
- {
- int last_parm_reg, profile_first_reg;
-
- /* Figure out last used parameter register. The proper thing
- to do is to walk incoming args of the function. A function
- might have live parameter registers even if it has no
- incoming args. */
- for (last_parm_reg = 10;
- last_parm_reg > 2 && ! regs_ever_live [last_parm_reg];
- last_parm_reg--)
- ;
-
- /* Calculate first reg for saving parameter registers
- and static chain.
- Skip reg 31 which may contain the frame pointer. */
- profile_first_reg = (33 - last_parm_reg
- - (current_function_needs_context ? 1 : 0));
-#if TARGET_MACHO
- /* Need to skip another reg to account for R31 being PICBASE
- (when flag_pic is set) or R30 being used as the frame
- pointer (when flag_pic is not set). */
- --profile_first_reg;
-#endif
- /* Do not save frame pointer if no parameters needs to be saved. */
- if (profile_first_reg == 31)
- profile_first_reg = 32;
-
- if (first_reg > profile_first_reg)
- first_reg = profile_first_reg;
- }
-
- /* SVR4 may need one register to preserve the static chain. */
- else if (current_function_needs_context)
- {
- /* Skip reg 31 which may contain the frame pointer. */
- if (first_reg > 30)
- first_reg = 30;
- }
- }
-
#if TARGET_MACHO
if (flag_pic && current_function_uses_pic_offset_table &&
(first_reg > RS6000_PIC_OFFSET_TABLE_REGNUM))
+---------------------------------------+
| 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
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);
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;
info_ptr->parm_size = RS6000_ALIGN (current_function_outgoing_args_size,
8);
+ 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->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;
+ 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
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;
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);
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);
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);
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);
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),
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,
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
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));
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)
{
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;
{
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);
+ }
}
}
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);
}
}
/* 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;
}
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
/* 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);
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);
+ 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. */
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)
{
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 *language_string = lang_hooks.name;
int fixed_parms = 0, float_parms = 0, parm_info = 0;
int i;
+ int optional_tbtab;
+
+ if (rs6000_traceback == traceback_full)
+ optional_tbtab = 1;
+ else if (rs6000_traceback == traceback_part)
+ optional_tbtab = 0;
+ else
+ optional_tbtab = !optimize_size && !TARGET_ELF;
while (*fname == '.') /* V.4 encodes . in the name */
fname++;
fputs ("\t.align 2\n", file);
}
- return;
}
\f
/* A C compound statement that outputs the assembler code for a thunk
int fidx;
if (GET_CODE (k) == LABEL_REF)
- return result * 1231 + X0INT (XEXP (k, 0), 3);
+ return result * 1231 + (unsigned) INSN_UID (XEXP (k, 0));
if (GET_CODE (k) == CODE_LABEL)
fidx = 3;
abort ();/* It would be easy to make this work, but it doesn't now. */
if (POINTER_SIZE > GET_MODE_BITSIZE (mode))
- lshift_double (low, high, POINTER_SIZE - GET_MODE_BITSIZE (mode),
- POINTER_SIZE, &low, &high, 0);
+ {
+#if HOST_BITS_PER_WIDE_INT == 32
+ lshift_double (low, high, POINTER_SIZE - GET_MODE_BITSIZE (mode),
+ POINTER_SIZE, &low, &high, 0);
+#else
+ low |= high << 32;
+ low <<= POINTER_SIZE - GET_MODE_BITSIZE (mode);
+ high = (HOST_WIDE_INT) low >> 32;
+ low &= 0xffffffff;
+#endif
+ }
if (TARGET_64BIT)
{
}
len = strlen (after_last_slash) + strlen (section_desc) + 2;
- *buf = (char *) permalloc (len);
+ *buf = (char *) xmalloc (len);
p = *buf;
*p++ = '_';
void
output_profile_hook (labelno)
- int labelno;
+ int labelno ATTRIBUTE_UNUSED;
{
if (DEFAULT_ABI == ABI_AIX)
{
+#ifdef NO_PROFILE_COUNTERS
+ emit_library_call (init_one_libfunc (RS6000_MCOUNT), 0, VOIDmode, 0);
+#else
char buf[30];
const char *label_name;
rtx fun;
emit_library_call (init_one_libfunc (RS6000_MCOUNT), 0, VOIDmode, 1,
fun, Pmode);
+#endif
}
else if (DEFAULT_ABI == ABI_DARWIN)
{
int labelno;
{
char buf[100];
+ int save_lr = 8;
ASM_GENERATE_INTERNAL_LABEL (buf, "LP", labelno);
switch (DEFAULT_ABI)
abort ();
case ABI_V4:
+ save_lr = 4;
+ /* Fall through. */
+
case ABI_AIX_NODESC:
+ if (!TARGET_32BIT)
+ {
+ warning ("no profiling of 64-bit code for this ABI");
+ return;
+ }
fprintf (file, "\tmflr %s\n", reg_names[0]);
if (flag_pic == 1)
{
fputs ("\tbl _GLOBAL_OFFSET_TABLE_@local-4\n", file);
- asm_fprintf (file, "\t{st|stw} %s,4(%s)\n",
- reg_names[0], reg_names[1]);
+ asm_fprintf (file, "\t{st|stw} %s,%d(%s)\n",
+ reg_names[0], save_lr, reg_names[1]);
asm_fprintf (file, "\tmflr %s\n", reg_names[12]);
asm_fprintf (file, "\t{l|lwz} %s,", reg_names[0]);
assemble_name (file, buf);
}
else if (flag_pic > 1)
{
- asm_fprintf (file, "\t{st|stw} %s,4(%s)\n",
- reg_names[0], reg_names[1]);
+ asm_fprintf (file, "\t{st|stw} %s,%d(%s)\n",
+ reg_names[0], save_lr, reg_names[1]);
/* Now, we need to get the address of the label. */
fputs ("\tbl 1f\n\t.long ", file);
assemble_name (file, buf);
asm_fprintf (file, "\t{liu|lis} %s,", reg_names[12]);
assemble_name (file, buf);
fputs ("@ha\n", file);
- asm_fprintf (file, "\t{st|stw} %s,4(%s)\n",
- reg_names[0], reg_names[1]);
+ asm_fprintf (file, "\t{st|stw} %s,%d(%s)\n",
+ reg_names[0], save_lr, reg_names[1]);
asm_fprintf (file, "\t{cal|la} %s,", reg_names[0]);
assemble_name (file, buf);
asm_fprintf (file, "@l(%s)\n", reg_names[12]);
}
- if (current_function_needs_context)
- asm_fprintf (file, "\tmr %s,%s\n",
- reg_names[30], reg_names[STATIC_CHAIN_REGNUM]);
- fprintf (file, "\tbl %s\n", RS6000_MCOUNT);
- if (current_function_needs_context)
- asm_fprintf (file, "\tmr %s,%s\n",
- reg_names[STATIC_CHAIN_REGNUM], reg_names[30]);
+ if (current_function_needs_context && DEFAULT_ABI == ABI_AIX_NODESC)
+ {
+ asm_fprintf (file, "\t{st|stw} %s,%d(%s)\n",
+ reg_names[STATIC_CHAIN_REGNUM],
+ 12, reg_names[1]);
+ fprintf (file, "\tbl %s\n", RS6000_MCOUNT);
+ asm_fprintf (file, "\t{l|lwz} %s,%d(%s)\n",
+ reg_names[STATIC_CHAIN_REGNUM],
+ 12, reg_names[1]);
+ }
+ else
+ /* ABI_V4 saves the static chain reg with ASM_OUTPUT_REG_PUSH. */
+ fprintf (file, "\tbl %s\n", RS6000_MCOUNT);
break;
case ABI_AIX:
case ABI_DARWIN:
/* Don't do anything, done in output_profile_hook (). */
break;
-
}
}
{
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))
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",