spu.c (spu_builtin_range): Move from spu-c.c
2006-11-30 Andrew Pinski <andrew_pinski@playstation.sony.com> * config/spu/spu.c (spu_builtin_range): Move from spu-c.c (TARGET_RESOLVE_OVERLOADED_BUILTIN): Delete. (spu_cpu_cpp_builtins): Remove. (spu_override_options): Don't set warn_main. (spu_force_reg): Move from spu-c.c. (spu_check_builtin_parm): Likewise. (expand_builtin_args): Likewise. (spu_expand_builtin_1): Likewise. (spu_expand_builtin): Likewise. * config/spu/spu.h (REGISTER_TARGET_PRAGMAS): Define, set warn_main and targetm.resolve_overloaded_builtin. * config/spu/spu-c.c (spu_builtin_range): Remove. (spu_check_builtin_parm): Remove. (expand_builtin_args): Remove. (spu_expand_builtin_1): Remove. (spu_expand_builtin): Remove. (spu_cpu_cpp_builtins): Moved from spu.c (spu_force_reg): Remove. From-SVN: r119397
This commit is contained in:
parent
8521c41417
commit
b66b813d47
4 changed files with 319 additions and 302 deletions
|
@ -1,3 +1,24 @@
|
||||||
|
2006-11-30 Andrew Pinski <andrew_pinski@playstation.sony.com>
|
||||||
|
|
||||||
|
* config/spu/spu.c (spu_builtin_range): Move from spu-c.c
|
||||||
|
(TARGET_RESOLVE_OVERLOADED_BUILTIN): Delete.
|
||||||
|
(spu_cpu_cpp_builtins): Remove.
|
||||||
|
(spu_override_options): Don't set warn_main.
|
||||||
|
(spu_force_reg): Move from spu-c.c.
|
||||||
|
(spu_check_builtin_parm): Likewise.
|
||||||
|
(expand_builtin_args): Likewise.
|
||||||
|
(spu_expand_builtin_1): Likewise.
|
||||||
|
(spu_expand_builtin): Likewise.
|
||||||
|
* config/spu/spu.h (REGISTER_TARGET_PRAGMAS): Define, set
|
||||||
|
warn_main and targetm.resolve_overloaded_builtin.
|
||||||
|
* config/spu/spu-c.c (spu_builtin_range): Remove.
|
||||||
|
(spu_check_builtin_parm): Remove.
|
||||||
|
(expand_builtin_args): Remove.
|
||||||
|
(spu_expand_builtin_1): Remove.
|
||||||
|
(spu_expand_builtin): Remove.
|
||||||
|
(spu_cpu_cpp_builtins): Moved from spu.c
|
||||||
|
(spu_force_reg): Remove.
|
||||||
|
|
||||||
2006-12-01 Joseph Myers <joseph@codesourcery.com>
|
2006-12-01 Joseph Myers <joseph@codesourcery.com>
|
||||||
David Edelsohn <edelsohn@gnu.org>
|
David Edelsohn <edelsohn@gnu.org>
|
||||||
|
|
||||||
|
|
|
@ -34,35 +34,6 @@
|
||||||
#include "recog.h"
|
#include "recog.h"
|
||||||
#include "optabs.h"
|
#include "optabs.h"
|
||||||
#include "spu-builtins.h"
|
#include "spu-builtins.h"
|
||||||
|
|
||||||
static rtx spu_expand_builtin_1 (struct spu_builtin_description *d,
|
|
||||||
tree arglist, rtx target);
|
|
||||||
static void spu_check_builtin_parm (struct spu_builtin_description *, rtx,
|
|
||||||
int);
|
|
||||||
static void expand_builtin_args (struct spu_builtin_description *, tree, rtx,
|
|
||||||
rtx[]);
|
|
||||||
static rtx spu_force_reg (enum machine_mode mode, rtx op);
|
|
||||||
|
|
||||||
/* Builtin types, data and prototypes. */
|
|
||||||
struct spu_builtin_range
|
|
||||||
{
|
|
||||||
int low, high;
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct spu_builtin_range spu_builtin_range[] = {
|
|
||||||
{-0x40ll, 0x7fll}, /* SPU_BTI_7 */
|
|
||||||
{-0x40ll, 0x3fll}, /* SPU_BTI_S7 */
|
|
||||||
{0ll, 0x7fll}, /* SPU_BTI_U7 */
|
|
||||||
{-0x200ll, 0x1ffll}, /* SPU_BTI_S10 */
|
|
||||||
{-0x2000ll, 0x1fffll}, /* SPU_BTI_S10_4 */
|
|
||||||
{0ll, 0x3fffll}, /* SPU_BTI_U14 */
|
|
||||||
{-0x8000ll, 0xffffll}, /* SPU_BTI_16 */
|
|
||||||
{-0x8000ll, 0x7fffll}, /* SPU_BTI_S16 */
|
|
||||||
{-0x20000ll, 0x1ffffll}, /* SPU_BTI_S16_2 */
|
|
||||||
{0ll, 0xffffll}, /* SPU_BTI_U16 */
|
|
||||||
{0ll, 0x3ffffll}, /* SPU_BTI_U16_2 */
|
|
||||||
{0ll, 0x3ffffll}, /* SPU_BTI_U18 */
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/* Helper for spu_resolve_overloaded_builtin. */
|
/* Helper for spu_resolve_overloaded_builtin. */
|
||||||
|
@ -181,263 +152,13 @@ spu_resolve_overloaded_builtin (tree fndecl, tree fnargs)
|
||||||
return spu_build_overload_builtin (match, fnargs);
|
return spu_build_overload_builtin (match, fnargs);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
spu_check_builtin_parm (struct spu_builtin_description *d, rtx op, int p)
|
void
|
||||||
|
spu_cpu_cpp_builtins (struct cpp_reader *pfile)
|
||||||
{
|
{
|
||||||
HOST_WIDE_INT v = 0;
|
builtin_define_std ("__SPU__");
|
||||||
int lsbits;
|
cpp_assert (pfile, "cpu=spu");
|
||||||
/* Check the range of immediate operands. */
|
cpp_assert (pfile, "machine=spu");
|
||||||
if (p >= SPU_BTI_7 && p <= SPU_BTI_U18)
|
builtin_define_std ("__vector=__attribute__((__spu_vector__))");
|
||||||
{
|
|
||||||
int range = p - SPU_BTI_7;
|
|
||||||
if (!CONSTANT_P (op)
|
|
||||||
|| (GET_CODE (op) == CONST_INT
|
|
||||||
&& (INTVAL (op) < spu_builtin_range[range].low
|
|
||||||
|| INTVAL (op) > spu_builtin_range[range].high)))
|
|
||||||
error ("%s expects an integer literal in the range [%d, %d].",
|
|
||||||
d->name,
|
|
||||||
spu_builtin_range[range].low, spu_builtin_range[range].high);
|
|
||||||
|
|
||||||
if (GET_CODE (op) == CONST
|
|
||||||
&& (GET_CODE (XEXP (op, 0)) == PLUS
|
|
||||||
|| GET_CODE (XEXP (op, 0)) == MINUS))
|
|
||||||
{
|
|
||||||
v = INTVAL (XEXP (XEXP (op, 0), 1));
|
|
||||||
op = XEXP (XEXP (op, 0), 0);
|
|
||||||
}
|
|
||||||
else if (GET_CODE (op) == CONST_INT)
|
|
||||||
v = INTVAL (op);
|
|
||||||
|
|
||||||
switch (p)
|
|
||||||
{
|
|
||||||
case SPU_BTI_S10_4:
|
|
||||||
lsbits = 4;
|
|
||||||
break;
|
|
||||||
case SPU_BTI_U16_2:
|
|
||||||
/* This is only used in lqa, and stqa. Even though the insns
|
|
||||||
encode 16 bits of the address (all but the 2 least
|
|
||||||
significant), only 14 bits are used because it is masked to
|
|
||||||
be 16 byte aligned. */
|
|
||||||
lsbits = 4;
|
|
||||||
break;
|
|
||||||
case SPU_BTI_S16_2:
|
|
||||||
/* This is used for lqr and stqr. */
|
|
||||||
lsbits = 2;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
lsbits = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GET_CODE (op) == LABEL_REF
|
|
||||||
|| (GET_CODE (op) == SYMBOL_REF
|
|
||||||
&& SYMBOL_REF_FUNCTION_P (op))
|
|
||||||
|| (INTVAL (op) & ((1 << lsbits) - 1)) != 0)
|
|
||||||
warning (0, "%d least significant bits of %s are ignored.", lsbits,
|
|
||||||
d->name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
expand_builtin_args (struct spu_builtin_description *d, tree arglist,
|
|
||||||
rtx target, rtx ops[])
|
|
||||||
{
|
|
||||||
enum insn_code icode = d->icode;
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
/* Expand the arguments into rtl. */
|
|
||||||
|
|
||||||
if (d->parm[0] != SPU_BTI_VOID)
|
|
||||||
ops[i++] = target;
|
|
||||||
|
|
||||||
for (; i < insn_data[icode].n_operands; i++)
|
|
||||||
{
|
|
||||||
tree arg = TREE_VALUE (arglist);
|
|
||||||
if (arg == 0)
|
|
||||||
abort ();
|
|
||||||
ops[i] = expand_expr (arg, NULL_RTX, VOIDmode, 0);
|
|
||||||
arglist = TREE_CHAIN (arglist);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static rtx
|
|
||||||
spu_expand_builtin_1 (struct spu_builtin_description *d,
|
|
||||||
tree arglist, rtx target)
|
|
||||||
{
|
|
||||||
rtx pat;
|
|
||||||
rtx ops[8];
|
|
||||||
enum insn_code icode = d->icode;
|
|
||||||
enum machine_mode mode, tmode;
|
|
||||||
int i, p;
|
|
||||||
tree return_type;
|
|
||||||
|
|
||||||
/* Set up ops[] with values from arglist. */
|
|
||||||
expand_builtin_args (d, arglist, target, ops);
|
|
||||||
|
|
||||||
/* Handle the target operand which must be operand 0. */
|
|
||||||
i = 0;
|
|
||||||
if (d->parm[0] != SPU_BTI_VOID)
|
|
||||||
{
|
|
||||||
|
|
||||||
/* We prefer the mode specified for the match_operand otherwise
|
|
||||||
use the mode from the builtin function prototype. */
|
|
||||||
tmode = insn_data[d->icode].operand[0].mode;
|
|
||||||
if (tmode == VOIDmode)
|
|
||||||
tmode = TYPE_MODE (spu_builtin_types[d->parm[0]]);
|
|
||||||
|
|
||||||
/* Try to use target because not using it can lead to extra copies
|
|
||||||
and when we are using all of the registers extra copies leads
|
|
||||||
to extra spills. */
|
|
||||||
if (target && GET_CODE (target) == REG && GET_MODE (target) == tmode)
|
|
||||||
ops[0] = target;
|
|
||||||
else
|
|
||||||
target = ops[0] = gen_reg_rtx (tmode);
|
|
||||||
|
|
||||||
if (!(*insn_data[icode].operand[0].predicate) (ops[0], tmode))
|
|
||||||
abort ();
|
|
||||||
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Ignore align_hint, but still expand it's args in case they have
|
|
||||||
side effects. */
|
|
||||||
if (icode == CODE_FOR_spu_align_hint)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Handle the rest of the operands. */
|
|
||||||
for (p = 1; i < insn_data[icode].n_operands; i++, p++)
|
|
||||||
{
|
|
||||||
if (insn_data[d->icode].operand[i].mode != VOIDmode)
|
|
||||||
mode = insn_data[d->icode].operand[i].mode;
|
|
||||||
else
|
|
||||||
mode = TYPE_MODE (spu_builtin_types[d->parm[i]]);
|
|
||||||
|
|
||||||
/* mode can be VOIDmode here for labels */
|
|
||||||
|
|
||||||
/* For specific intrinsics with an immediate operand, e.g.,
|
|
||||||
si_ai(), we sometimes need to convert the scalar argument to a
|
|
||||||
vector argument by splatting the scalar. */
|
|
||||||
if (VECTOR_MODE_P (mode)
|
|
||||||
&& (GET_CODE (ops[i]) == CONST_INT
|
|
||||||
|| GET_MODE_CLASS (GET_MODE (ops[i])) == MODE_INT
|
|
||||||
|| GET_MODE_CLASS (GET_MODE (ops[i])) == MODE_FLOAT))
|
|
||||||
{
|
|
||||||
if (GET_CODE (ops[i]) == CONST_INT)
|
|
||||||
ops[i] = spu_const (mode, INTVAL (ops[i]));
|
|
||||||
else
|
|
||||||
{
|
|
||||||
rtx reg = gen_reg_rtx (mode);
|
|
||||||
enum machine_mode imode = GET_MODE_INNER (mode);
|
|
||||||
if (!spu_nonmem_operand (ops[i], GET_MODE (ops[i])))
|
|
||||||
ops[i] = force_reg (GET_MODE (ops[i]), ops[i]);
|
|
||||||
if (imode != GET_MODE (ops[i]))
|
|
||||||
ops[i] = convert_to_mode (imode, ops[i],
|
|
||||||
TYPE_UNSIGNED (spu_builtin_types
|
|
||||||
[d->parm[i]]));
|
|
||||||
emit_insn (gen_spu_splats (reg, ops[i]));
|
|
||||||
ops[i] = reg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(*insn_data[icode].operand[i].predicate) (ops[i], mode))
|
|
||||||
ops[i] = spu_force_reg (mode, ops[i]);
|
|
||||||
|
|
||||||
spu_check_builtin_parm (d, ops[i], d->parm[p]);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (insn_data[icode].n_operands)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
pat = GEN_FCN (icode) (0);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
pat = GEN_FCN (icode) (ops[0]);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
pat = GEN_FCN (icode) (ops[0], ops[1]);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
pat = GEN_FCN (icode) (ops[0], ops[1], ops[2]);
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
pat = GEN_FCN (icode) (ops[0], ops[1], ops[2], ops[3]);
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
pat = GEN_FCN (icode) (ops[0], ops[1], ops[2], ops[3], ops[4]);
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
pat = GEN_FCN (icode) (ops[0], ops[1], ops[2], ops[3], ops[4], ops[5]);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
abort ();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!pat)
|
|
||||||
abort ();
|
|
||||||
|
|
||||||
if (d->type == B_CALL || d->type == B_BISLED)
|
|
||||||
emit_call_insn (pat);
|
|
||||||
else if (d->type == B_JUMP)
|
|
||||||
{
|
|
||||||
emit_jump_insn (pat);
|
|
||||||
emit_barrier ();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
emit_insn (pat);
|
|
||||||
|
|
||||||
return_type = spu_builtin_types[d->parm[0]];
|
|
||||||
if (d->parm[0] != SPU_BTI_VOID
|
|
||||||
&& GET_MODE (target) != TYPE_MODE (return_type))
|
|
||||||
{
|
|
||||||
/* target is the return value. It should always be the mode of
|
|
||||||
the builtin function prototype. */
|
|
||||||
target = spu_force_reg (TYPE_MODE (return_type), target);
|
|
||||||
}
|
|
||||||
|
|
||||||
return target;
|
|
||||||
}
|
|
||||||
|
|
||||||
rtx
|
|
||||||
spu_expand_builtin (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);
|
|
||||||
unsigned int fcode = DECL_FUNCTION_CODE (fndecl) - END_BUILTINS;
|
|
||||||
tree arglist = TREE_OPERAND (exp, 1);
|
|
||||||
struct spu_builtin_description *d;
|
|
||||||
|
|
||||||
if (fcode < NUM_SPU_BUILTINS)
|
|
||||||
{
|
|
||||||
d = &spu_builtins[fcode];
|
|
||||||
|
|
||||||
return spu_expand_builtin_1 (d, arglist, target);
|
|
||||||
}
|
|
||||||
abort ();
|
|
||||||
}
|
|
||||||
|
|
||||||
static rtx
|
|
||||||
spu_force_reg (enum machine_mode mode, rtx op)
|
|
||||||
{
|
|
||||||
rtx x, r;
|
|
||||||
if (GET_MODE (op) == VOIDmode || GET_MODE (op) == BLKmode)
|
|
||||||
{
|
|
||||||
if ((SCALAR_INT_MODE_P (mode) && GET_CODE (op) == CONST_INT)
|
|
||||||
|| GET_MODE (op) == BLKmode)
|
|
||||||
return force_reg (mode, convert_to_mode (mode, op, 0));
|
|
||||||
abort ();
|
|
||||||
}
|
|
||||||
|
|
||||||
r = force_reg (GET_MODE (op), op);
|
|
||||||
if (GET_MODE_SIZE (GET_MODE (op)) == GET_MODE_SIZE (mode))
|
|
||||||
{
|
|
||||||
x = simplify_gen_subreg (mode, r, GET_MODE (op), 0);
|
|
||||||
if (x)
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
x = gen_reg_rtx (mode);
|
|
||||||
emit_insn (gen_spu_convert (x, r));
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
|
@ -54,6 +54,28 @@
|
||||||
#include "tree-gimple.h"
|
#include "tree-gimple.h"
|
||||||
#include "tm-constrs.h"
|
#include "tm-constrs.h"
|
||||||
#include "spu-builtins.h"
|
#include "spu-builtins.h"
|
||||||
|
|
||||||
|
/* Builtin types, data and prototypes. */
|
||||||
|
struct spu_builtin_range
|
||||||
|
{
|
||||||
|
int low, high;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct spu_builtin_range spu_builtin_range[] = {
|
||||||
|
{-0x40ll, 0x7fll}, /* SPU_BTI_7 */
|
||||||
|
{-0x40ll, 0x3fll}, /* SPU_BTI_S7 */
|
||||||
|
{0ll, 0x7fll}, /* SPU_BTI_U7 */
|
||||||
|
{-0x200ll, 0x1ffll}, /* SPU_BTI_S10 */
|
||||||
|
{-0x2000ll, 0x1fffll}, /* SPU_BTI_S10_4 */
|
||||||
|
{0ll, 0x3fffll}, /* SPU_BTI_U14 */
|
||||||
|
{-0x8000ll, 0xffffll}, /* SPU_BTI_16 */
|
||||||
|
{-0x8000ll, 0x7fffll}, /* SPU_BTI_S16 */
|
||||||
|
{-0x20000ll, 0x1ffffll}, /* SPU_BTI_S16_2 */
|
||||||
|
{0ll, 0xffffll}, /* SPU_BTI_U16 */
|
||||||
|
{0ll, 0x3ffffll}, /* SPU_BTI_U16_2 */
|
||||||
|
{0ll, 0x3ffffll}, /* SPU_BTI_U18 */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Target specific attribute specifications. */
|
/* Target specific attribute specifications. */
|
||||||
char regs_ever_allocated[FIRST_PSEUDO_REGISTER];
|
char regs_ever_allocated[FIRST_PSEUDO_REGISTER];
|
||||||
|
@ -133,9 +155,6 @@ tree spu_builtin_types[SPU_BTI_MAX];
|
||||||
#undef TARGET_INIT_BUILTINS
|
#undef TARGET_INIT_BUILTINS
|
||||||
#define TARGET_INIT_BUILTINS spu_init_builtins
|
#define TARGET_INIT_BUILTINS spu_init_builtins
|
||||||
|
|
||||||
#undef TARGET_RESOLVE_OVERLOADED_BUILTIN
|
|
||||||
#define TARGET_RESOLVE_OVERLOADED_BUILTIN spu_resolve_overloaded_builtin
|
|
||||||
|
|
||||||
#undef TARGET_EXPAND_BUILTIN
|
#undef TARGET_EXPAND_BUILTIN
|
||||||
#define TARGET_EXPAND_BUILTIN spu_expand_builtin
|
#define TARGET_EXPAND_BUILTIN spu_expand_builtin
|
||||||
|
|
||||||
|
@ -213,16 +232,6 @@ const struct attribute_spec spu_attribute_table[];
|
||||||
|
|
||||||
struct gcc_target targetm = TARGET_INITIALIZER;
|
struct gcc_target targetm = TARGET_INITIALIZER;
|
||||||
|
|
||||||
void
|
|
||||||
spu_cpu_cpp_builtins (struct cpp_reader *pfile)
|
|
||||||
{
|
|
||||||
extern void builtin_define_std (const char *);
|
|
||||||
builtin_define_std ("__SPU__");
|
|
||||||
cpp_assert (pfile, "cpu=spu");
|
|
||||||
cpp_assert (pfile, "machine=spu");
|
|
||||||
builtin_define_std ("__vector=__attribute__((__spu_vector__))");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Sometimes certain combinations of command options do not make sense
|
/* Sometimes certain combinations of command options do not make sense
|
||||||
on a particular target machine. You can define a macro
|
on a particular target machine. You can define a macro
|
||||||
OVERRIDE_OPTIONS to take account of this. This macro, if defined, is
|
OVERRIDE_OPTIONS to take account of this. This macro, if defined, is
|
||||||
|
@ -231,9 +240,6 @@ void
|
||||||
spu_override_options (void)
|
spu_override_options (void)
|
||||||
{
|
{
|
||||||
|
|
||||||
/* Don't give warnings about the main() function. */
|
|
||||||
warn_main = 0;
|
|
||||||
|
|
||||||
/* Override some of the default param values. With so many registers
|
/* Override some of the default param values. With so many registers
|
||||||
larger values are better for these params. */
|
larger values are better for these params. */
|
||||||
if (MAX_UNROLLED_INSNS == 100)
|
if (MAX_UNROLLED_INSNS == 100)
|
||||||
|
@ -4467,3 +4473,266 @@ spu_expand_vector_init (rtx target, rtx vals)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static rtx
|
||||||
|
spu_force_reg (enum machine_mode mode, rtx op)
|
||||||
|
{
|
||||||
|
rtx x, r;
|
||||||
|
if (GET_MODE (op) == VOIDmode || GET_MODE (op) == BLKmode)
|
||||||
|
{
|
||||||
|
if ((SCALAR_INT_MODE_P (mode) && GET_CODE (op) == CONST_INT)
|
||||||
|
|| GET_MODE (op) == BLKmode)
|
||||||
|
return force_reg (mode, convert_to_mode (mode, op, 0));
|
||||||
|
abort ();
|
||||||
|
}
|
||||||
|
|
||||||
|
r = force_reg (GET_MODE (op), op);
|
||||||
|
if (GET_MODE_SIZE (GET_MODE (op)) == GET_MODE_SIZE (mode))
|
||||||
|
{
|
||||||
|
x = simplify_gen_subreg (mode, r, GET_MODE (op), 0);
|
||||||
|
if (x)
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
x = gen_reg_rtx (mode);
|
||||||
|
emit_insn (gen_spu_convert (x, r));
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
spu_check_builtin_parm (struct spu_builtin_description *d, rtx op, int p)
|
||||||
|
{
|
||||||
|
HOST_WIDE_INT v = 0;
|
||||||
|
int lsbits;
|
||||||
|
/* Check the range of immediate operands. */
|
||||||
|
if (p >= SPU_BTI_7 && p <= SPU_BTI_U18)
|
||||||
|
{
|
||||||
|
int range = p - SPU_BTI_7;
|
||||||
|
if (!CONSTANT_P (op)
|
||||||
|
|| (GET_CODE (op) == CONST_INT
|
||||||
|
&& (INTVAL (op) < spu_builtin_range[range].low
|
||||||
|
|| INTVAL (op) > spu_builtin_range[range].high)))
|
||||||
|
error ("%s expects an integer literal in the range [%d, %d].",
|
||||||
|
d->name,
|
||||||
|
spu_builtin_range[range].low, spu_builtin_range[range].high);
|
||||||
|
|
||||||
|
if (GET_CODE (op) == CONST
|
||||||
|
&& (GET_CODE (XEXP (op, 0)) == PLUS
|
||||||
|
|| GET_CODE (XEXP (op, 0)) == MINUS))
|
||||||
|
{
|
||||||
|
v = INTVAL (XEXP (XEXP (op, 0), 1));
|
||||||
|
op = XEXP (XEXP (op, 0), 0);
|
||||||
|
}
|
||||||
|
else if (GET_CODE (op) == CONST_INT)
|
||||||
|
v = INTVAL (op);
|
||||||
|
|
||||||
|
switch (p)
|
||||||
|
{
|
||||||
|
case SPU_BTI_S10_4:
|
||||||
|
lsbits = 4;
|
||||||
|
break;
|
||||||
|
case SPU_BTI_U16_2:
|
||||||
|
/* This is only used in lqa, and stqa. Even though the insns
|
||||||
|
encode 16 bits of the address (all but the 2 least
|
||||||
|
significant), only 14 bits are used because it is masked to
|
||||||
|
be 16 byte aligned. */
|
||||||
|
lsbits = 4;
|
||||||
|
break;
|
||||||
|
case SPU_BTI_S16_2:
|
||||||
|
/* This is used for lqr and stqr. */
|
||||||
|
lsbits = 2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
lsbits = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GET_CODE (op) == LABEL_REF
|
||||||
|
|| (GET_CODE (op) == SYMBOL_REF
|
||||||
|
&& SYMBOL_REF_FUNCTION_P (op))
|
||||||
|
|| (INTVAL (op) & ((1 << lsbits) - 1)) != 0)
|
||||||
|
warning (0, "%d least significant bits of %s are ignored.", lsbits,
|
||||||
|
d->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
expand_builtin_args (struct spu_builtin_description *d, tree arglist,
|
||||||
|
rtx target, rtx ops[])
|
||||||
|
{
|
||||||
|
enum insn_code icode = d->icode;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
/* Expand the arguments into rtl. */
|
||||||
|
|
||||||
|
if (d->parm[0] != SPU_BTI_VOID)
|
||||||
|
ops[i++] = target;
|
||||||
|
|
||||||
|
for (; i < insn_data[icode].n_operands; i++)
|
||||||
|
{
|
||||||
|
tree arg = TREE_VALUE (arglist);
|
||||||
|
if (arg == 0)
|
||||||
|
abort ();
|
||||||
|
ops[i] = expand_expr (arg, NULL_RTX, VOIDmode, 0);
|
||||||
|
arglist = TREE_CHAIN (arglist);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static rtx
|
||||||
|
spu_expand_builtin_1 (struct spu_builtin_description *d,
|
||||||
|
tree arglist, rtx target)
|
||||||
|
{
|
||||||
|
rtx pat;
|
||||||
|
rtx ops[8];
|
||||||
|
enum insn_code icode = d->icode;
|
||||||
|
enum machine_mode mode, tmode;
|
||||||
|
int i, p;
|
||||||
|
tree return_type;
|
||||||
|
|
||||||
|
/* Set up ops[] with values from arglist. */
|
||||||
|
expand_builtin_args (d, arglist, target, ops);
|
||||||
|
|
||||||
|
/* Handle the target operand which must be operand 0. */
|
||||||
|
i = 0;
|
||||||
|
if (d->parm[0] != SPU_BTI_VOID)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* We prefer the mode specified for the match_operand otherwise
|
||||||
|
use the mode from the builtin function prototype. */
|
||||||
|
tmode = insn_data[d->icode].operand[0].mode;
|
||||||
|
if (tmode == VOIDmode)
|
||||||
|
tmode = TYPE_MODE (spu_builtin_types[d->parm[0]]);
|
||||||
|
|
||||||
|
/* Try to use target because not using it can lead to extra copies
|
||||||
|
and when we are using all of the registers extra copies leads
|
||||||
|
to extra spills. */
|
||||||
|
if (target && GET_CODE (target) == REG && GET_MODE (target) == tmode)
|
||||||
|
ops[0] = target;
|
||||||
|
else
|
||||||
|
target = ops[0] = gen_reg_rtx (tmode);
|
||||||
|
|
||||||
|
if (!(*insn_data[icode].operand[0].predicate) (ops[0], tmode))
|
||||||
|
abort ();
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ignore align_hint, but still expand it's args in case they have
|
||||||
|
side effects. */
|
||||||
|
if (icode == CODE_FOR_spu_align_hint)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Handle the rest of the operands. */
|
||||||
|
for (p = 1; i < insn_data[icode].n_operands; i++, p++)
|
||||||
|
{
|
||||||
|
if (insn_data[d->icode].operand[i].mode != VOIDmode)
|
||||||
|
mode = insn_data[d->icode].operand[i].mode;
|
||||||
|
else
|
||||||
|
mode = TYPE_MODE (spu_builtin_types[d->parm[i]]);
|
||||||
|
|
||||||
|
/* mode can be VOIDmode here for labels */
|
||||||
|
|
||||||
|
/* For specific intrinsics with an immediate operand, e.g.,
|
||||||
|
si_ai(), we sometimes need to convert the scalar argument to a
|
||||||
|
vector argument by splatting the scalar. */
|
||||||
|
if (VECTOR_MODE_P (mode)
|
||||||
|
&& (GET_CODE (ops[i]) == CONST_INT
|
||||||
|
|| GET_MODE_CLASS (GET_MODE (ops[i])) == MODE_INT
|
||||||
|
|| GET_MODE_CLASS (GET_MODE (ops[i])) == MODE_FLOAT))
|
||||||
|
{
|
||||||
|
if (GET_CODE (ops[i]) == CONST_INT)
|
||||||
|
ops[i] = spu_const (mode, INTVAL (ops[i]));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rtx reg = gen_reg_rtx (mode);
|
||||||
|
enum machine_mode imode = GET_MODE_INNER (mode);
|
||||||
|
if (!spu_nonmem_operand (ops[i], GET_MODE (ops[i])))
|
||||||
|
ops[i] = force_reg (GET_MODE (ops[i]), ops[i]);
|
||||||
|
if (imode != GET_MODE (ops[i]))
|
||||||
|
ops[i] = convert_to_mode (imode, ops[i],
|
||||||
|
TYPE_UNSIGNED (spu_builtin_types
|
||||||
|
[d->parm[i]]));
|
||||||
|
emit_insn (gen_spu_splats (reg, ops[i]));
|
||||||
|
ops[i] = reg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(*insn_data[icode].operand[i].predicate) (ops[i], mode))
|
||||||
|
ops[i] = spu_force_reg (mode, ops[i]);
|
||||||
|
|
||||||
|
spu_check_builtin_parm (d, ops[i], d->parm[p]);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (insn_data[icode].n_operands)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
pat = GEN_FCN (icode) (0);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
pat = GEN_FCN (icode) (ops[0]);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
pat = GEN_FCN (icode) (ops[0], ops[1]);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
pat = GEN_FCN (icode) (ops[0], ops[1], ops[2]);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
pat = GEN_FCN (icode) (ops[0], ops[1], ops[2], ops[3]);
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
pat = GEN_FCN (icode) (ops[0], ops[1], ops[2], ops[3], ops[4]);
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
pat = GEN_FCN (icode) (ops[0], ops[1], ops[2], ops[3], ops[4], ops[5]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
abort ();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pat)
|
||||||
|
abort ();
|
||||||
|
|
||||||
|
if (d->type == B_CALL || d->type == B_BISLED)
|
||||||
|
emit_call_insn (pat);
|
||||||
|
else if (d->type == B_JUMP)
|
||||||
|
{
|
||||||
|
emit_jump_insn (pat);
|
||||||
|
emit_barrier ();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
emit_insn (pat);
|
||||||
|
|
||||||
|
return_type = spu_builtin_types[d->parm[0]];
|
||||||
|
if (d->parm[0] != SPU_BTI_VOID
|
||||||
|
&& GET_MODE (target) != TYPE_MODE (return_type))
|
||||||
|
{
|
||||||
|
/* target is the return value. It should always be the mode of
|
||||||
|
the builtin function prototype. */
|
||||||
|
target = spu_force_reg (TYPE_MODE (return_type), target);
|
||||||
|
}
|
||||||
|
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
rtx
|
||||||
|
spu_expand_builtin (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);
|
||||||
|
unsigned int fcode = DECL_FUNCTION_CODE (fndecl) - END_BUILTINS;
|
||||||
|
tree arglist = TREE_OPERAND (exp, 1);
|
||||||
|
struct spu_builtin_description *d;
|
||||||
|
|
||||||
|
if (fcode < NUM_SPU_BUILTINS)
|
||||||
|
{
|
||||||
|
d = &spu_builtins[fcode];
|
||||||
|
|
||||||
|
return spu_expand_builtin_1 (d, arglist, target);
|
||||||
|
}
|
||||||
|
abort ();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -238,6 +238,12 @@ enum reg_class {
|
||||||
((GET_MODE_SIZE (FROM) > 4 || GET_MODE_SIZE (TO) > 4) \
|
((GET_MODE_SIZE (FROM) > 4 || GET_MODE_SIZE (TO) > 4) \
|
||||||
&& GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO))
|
&& GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO))
|
||||||
|
|
||||||
|
#define REGISTER_TARGET_PRAGMAS() do { \
|
||||||
|
targetm.resolve_overloaded_builtin = spu_resolve_overloaded_builtin; \
|
||||||
|
/* Don't give warnings about the main() function. */ \
|
||||||
|
warn_main = 0; \
|
||||||
|
}while (0);
|
||||||
|
|
||||||
|
|
||||||
/* Frame Layout */
|
/* Frame Layout */
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue