spu-protos.h (spu_split_immediate): Renamed from spu_split_address.

* config/spu/spu-protos.h (spu_split_immediate): Renamed from
        spu_split_address.
        (cpat_const_p, gen_cpat_const): Add.
        * config/spu/spu.c (immediate_class): New enum.
        (cpat_info, classify_immediate): New.
        (print_operand): Use S, D, T instead of F, G, H.  Use
        classify_immediate.  Handle cpat cases.
        (spu_split_immediate):  Renamed from spu_split_address.  Split all
        immediates that can be split.
        (immediate_load_p): Use classify_immediate.
        (spu_legitimate_constant_p): Accept everything except some cases of
        CONST_VECTOR.
        (spu_expand_move): Use spu_split_immedate.
        (fsmbi_const_p): Use classify_immediate.
        (cpat_const_p): New.
        (gen_cpat_const: New.
        * config/spu/constraints.md (j,k,l): New constraints for cpat
        instructions.
        * config/spu/spu.md (unnamed splitter): Change address splitter to
        handle all immediates.
        (_mov<mode>, _movdi, _movti): Handle i, j, k constraints for cpat
        instructions.
        (cpat, _cpat, splitter): Generate a TImode constant for cpat patterns
        when possible.

From-SVN: r119682
This commit is contained in:
Trevor Smigiel 2006-12-09 01:22:39 +00:00 committed by Trevor Smigiel
parent 55eb837db1
commit a1c6e4b803
5 changed files with 481 additions and 235 deletions

View File

@ -1,3 +1,30 @@
2006-12-08 Trevor Smigiel <trevor_smigiel@playstation.sony.com>
* config/spu/spu-protos.h (spu_split_immediate): Renamed from
spu_split_address.
(cpat_const_p, gen_cpat_const): Add.
* config/spu/spu.c (immediate_class): New enum.
(cpat_info, classify_immediate): New.
(print_operand): Use S, D, T instead of F, G, H. Use
classify_immediate. Handle cpat cases.
(spu_split_immediate): Renamed from spu_split_address. Split all
immediates that can be split.
(immediate_load_p): Use classify_immediate.
(spu_legitimate_constant_p): Accept everything except some cases of
CONST_VECTOR.
(spu_expand_move): Use spu_split_immedate.
(fsmbi_const_p): Use classify_immediate.
(cpat_const_p): New.
(gen_cpat_const: New.
* config/spu/constraints.md (j,k,l): New constraints for cpat
instructions.
* config/spu/spu.md (unnamed splitter): Change address splitter to
handle all immediates.
(_mov<mode>, _movdi, _movti): Handle i, j, k constraints for cpat
instructions.
(cpat, _cpat, splitter): Generate a TImode constant for cpat patterns
when possible.
2006-12-08 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
PR target/30039

View File

@ -18,7 +18,7 @@
;; GCC standard constraints: g, i, m, n, o, p, r, s, E-H, I-P, V, X
;; unused for SPU: E-H, L, Q, d, e, h, j-l, q, t-z
;; unused for SPU: E-H, L, Q, d, e, h, q, t-z
;; For most immediate constraints we have 3 variations to deal with the
;; fact const_int has no mode. One variation treats const_int as 32 bit,
@ -84,6 +84,22 @@
"An immediate which can be loaded with fsmbi."
(and (match_code "const_int,const_double,const_vector")
(match_test "fsmbi_const_p (op)")))
(define_constraint "j"
"An immediate which can be loaded with one of the cbd/chd/cwd/cdd instructions. const_int is treated as a 32 bit value."
(and (match_code "const_int,const_double,const_vector")
(match_test "cpat_const_p (op, SImode)")))
(define_constraint "k"
"An immediate which can be loaded with one of the cbd/chd/cwd/cdd instructions. const_int is treated as a 64 bit value."
(and (match_code "const_int,const_double,const_vector")
(match_test "cpat_const_p (op, DImode)")))
(define_constraint "l"
"An immediate which can be loaded with one of the cbd/chd/cwd/cdd instructions."
(and (match_code "const_double,const_vector")
(match_test "cpat_const_p (op, TImode)")))
;; Integer constraints

View File

@ -34,7 +34,7 @@ extern HOST_WIDE_INT const_double_to_hwint (rtx x);
extern rtx hwint_to_const_double (enum machine_mode mode, HOST_WIDE_INT v);
extern void print_operand_address (FILE * file, register rtx addr);
extern void print_operand (FILE * file, rtx x, int code);
extern void spu_split_address (rtx * ops);
extern int spu_split_immediate (rtx * ops);
extern int spu_saved_regs_size (void);
extern int direct_return (void);
extern void spu_expand_prologue (void);
@ -69,6 +69,8 @@ extern void spu_split_load (rtx * ops);
extern void spu_split_store (rtx * ops);
extern int spu_valid_move (rtx * ops);
extern int fsmbi_const_p (rtx x);
extern int cpat_const_p (rtx x, enum machine_mode mode);
extern rtx gen_cpat_const (rtx * ops);
extern void constant_to_array (enum machine_mode mode, rtx x,
unsigned char *arr);
extern rtx array_to_constant (enum machine_mode mode, unsigned char *arr);

View File

@ -143,9 +143,22 @@ enum spu_immediate {
SPU_ORBI,
SPU_IOHL
};
enum immediate_class
{
IC_POOL, /* constant pool */
IC_IL1, /* one il* instruction */
IC_IL2, /* both ilhu and iohl instructions */
IC_IL1s, /* one il* instruction */
IC_IL2s, /* both ilhu and iohl instructions */
IC_FSMBI, /* the fsmbi instruction */
IC_CPAT, /* one of the c*d instructions */
};
static enum spu_immediate which_immediate_load (HOST_WIDE_INT val);
static enum spu_immediate which_logical_immediate (HOST_WIDE_INT val);
static int cpat_info(unsigned char *arr, int size, int *prun, int *pstart);
static enum immediate_class classify_immediate (rtx op,
enum machine_mode mode);
/* Built in types. */
tree spu_builtin_types[SPU_BTI_MAX];
@ -972,24 +985,22 @@ print_operand (FILE * file, rtx x, int code)
HOST_WIDE_INT val;
unsigned char arr[16];
int xcode = GET_CODE (x);
int i, info;
if (GET_MODE (x) == VOIDmode)
switch (code)
{
case 'H': /* 128 bits, signed */
case 'L': /* 128 bits, signed */
case 'm': /* 128 bits, signed */
case 'T': /* 128 bits, signed */
case 't': /* 128 bits, signed */
mode = TImode;
break;
case 'G': /* 64 bits, signed */
case 'K': /* 64 bits, signed */
case 'k': /* 64 bits, signed */
case 'D': /* 64 bits, signed */
case 'd': /* 64 bits, signed */
mode = DImode;
break;
case 'F': /* 32 bits, signed */
case 'J': /* 32 bits, signed */
case 'j': /* 32 bits, signed */
case 's': /* 32 bits, signed */
@ -1062,34 +1073,62 @@ print_operand (FILE * file, rtx x, int code)
case 't': /* 128 bits, signed */
case 'd': /* 64 bits, signed */
case 's': /* 32 bits, signed */
if (xcode == CONST_INT
|| xcode == CONST_DOUBLE || xcode == CONST_VECTOR)
if (CONSTANT_P (x))
{
gcc_assert (immediate_load_p (x, mode));
constant_to_array (mode, x, arr);
val = (arr[0] << 24) | (arr[1] << 16) | (arr[2] << 8) | arr[3];
val = trunc_int_for_mode (val, SImode);
switch (which_immediate_load (val))
{
case SPU_IL:
break;
case SPU_ILA:
fprintf (file, "a");
break;
case SPU_ILH:
fprintf (file, "h");
break;
case SPU_ILHU:
fprintf (file, "hu");
break;
default:
gcc_unreachable();
}
enum immediate_class c = classify_immediate (x, mode);
switch (c)
{
case IC_IL1:
constant_to_array (mode, x, arr);
val = (arr[0] << 24) | (arr[1] << 16) | (arr[2] << 8) | arr[3];
val = trunc_int_for_mode (val, SImode);
switch (which_immediate_load (val))
{
case SPU_IL:
break;
case SPU_ILA:
fprintf (file, "a");
break;
case SPU_ILH:
fprintf (file, "h");
break;
case SPU_ILHU:
fprintf (file, "hu");
break;
default:
gcc_unreachable ();
}
break;
case IC_CPAT:
constant_to_array (mode, x, arr);
cpat_info (arr, GET_MODE_SIZE (mode), &info, 0);
if (info == 1)
fprintf (file, "b");
else if (info == 2)
fprintf (file, "h");
else if (info == 4)
fprintf (file, "w");
else if (info == 8)
fprintf (file, "d");
break;
case IC_IL1s:
if (xcode == CONST_VECTOR)
{
x = CONST_VECTOR_ELT (x, 0);
xcode = GET_CODE (x);
}
if (xcode == SYMBOL_REF || xcode == LABEL_REF || xcode == CONST)
fprintf (file, "a");
else if (xcode == HIGH)
fprintf (file, "hu");
break;
case IC_FSMBI:
case IC_IL2:
case IC_IL2s:
case IC_POOL:
abort ();
}
}
else if (xcode == SYMBOL_REF || xcode == LABEL_REF || xcode == CONST)
fprintf (file, "a");
else if (xcode == HIGH)
fprintf (file, "hu");
else
gcc_unreachable ();
return;
@ -1097,59 +1136,68 @@ print_operand (FILE * file, rtx x, int code)
case 'T': /* 128 bits, signed */
case 'D': /* 64 bits, signed */
case 'S': /* 32 bits, signed */
if (xcode == CONST_INT
|| xcode == CONST_DOUBLE || xcode == CONST_VECTOR)
if (CONSTANT_P (x))
{
gcc_assert (immediate_load_p (x, mode));
constant_to_array (mode, x, arr);
val = (arr[0] << 24) | (arr[1] << 16) | (arr[2] << 8) | arr[3];
val = trunc_int_for_mode (val, SImode);
switch (which_immediate_load (val))
enum immediate_class c = classify_immediate (x, mode);
switch (c)
{
case SPU_IL:
case SPU_ILA:
case IC_IL1:
constant_to_array (mode, x, arr);
val = (arr[0] << 24) | (arr[1] << 16) | (arr[2] << 8) | arr[3];
val = trunc_int_for_mode (val, SImode);
switch (which_immediate_load (val))
{
case SPU_IL:
case SPU_ILA:
break;
case SPU_ILH:
case SPU_ILHU:
val = trunc_int_for_mode (((arr[0] << 8) | arr[1]), HImode);
break;
default:
gcc_unreachable ();
}
fprintf (file, HOST_WIDE_INT_PRINT_DEC, val);
break;
case SPU_ILH:
case SPU_ILHU:
val = trunc_int_for_mode (((arr[0] << 8) | arr[1]), HImode);
case IC_FSMBI:
constant_to_array (mode, x, arr);
val = 0;
for (i = 0; i < 16; i++)
{
val <<= 1;
val |= arr[i] & 1;
}
print_operand (file, GEN_INT (val), 0);
break;
default:
gcc_unreachable();
case IC_CPAT:
constant_to_array (mode, x, arr);
cpat_info (arr, GET_MODE_SIZE (mode), 0, &info);
fprintf (file, HOST_WIDE_INT_PRINT_DEC, (HOST_WIDE_INT)info);
break;
case IC_IL1s:
if (xcode == CONST_VECTOR)
{
x = CONST_VECTOR_ELT (x, 0);
xcode = GET_CODE (x);
}
if (xcode == HIGH)
{
output_addr_const (file, XEXP (x, 0));
fprintf (file, "@h");
}
else
output_addr_const (file, x);
break;
case IC_IL2:
case IC_IL2s:
case IC_POOL:
abort ();
}
fprintf (file, HOST_WIDE_INT_PRINT_DEC, val);
}
else if (xcode == CONST || xcode == SYMBOL_REF || xcode == LABEL_REF)
output_addr_const (file, x);
else if (xcode == HIGH)
{
output_addr_const (file, XEXP (x, 0));
fprintf (file, "@h");
}
else
gcc_unreachable ();
return;
case 'F':
case 'G':
case 'H':
if (xcode == CONST_INT
|| xcode == CONST_DOUBLE || xcode == CONST_VECTOR)
{ /* immediate operand for fsmbi */
int i;
HOST_WIDE_INT val = 0;
unsigned char arr[16];
constant_to_array (mode, x, arr);
for (i = 0; i < 16; i++)
{
val <<= 1;
val |= arr[i] & 1;
}
print_operand (file, GEN_INT (val), 0);
}
else
gcc_unreachable();
return;
case 'C':
if (xcode == CONST_INT)
{
@ -1246,7 +1294,7 @@ print_operand (FILE * file, rtx x, int code)
else if (xcode == MEM)
output_address (XEXP (x, 0));
else if (xcode == CONST_VECTOR)
output_addr_const (file, CONST_VECTOR_ELT (x, 0));
print_operand (file, CONST_VECTOR_ELT (x, 0), 0);
else
output_addr_const (file, x);
return;
@ -1276,23 +1324,76 @@ get_pic_reg (void)
/* Split constant addresses to handle cases that are too large. Also, add in
the pic register when in PIC mode. */
void
spu_split_address (rtx * ops)
int
spu_split_immediate (rtx * ops)
{
if (TARGET_LARGE_MEM
|| (GET_CODE (ops[1]) == CONST && !legitimate_const (ops[1], 0)))
enum machine_mode mode = GET_MODE (ops[0]);
enum immediate_class c = classify_immediate (ops[1], mode);
switch (c)
{
emit_insn (gen_high (ops[0], ops[1]));
emit_insn (gen_low (ops[0], ops[0], ops[1]));
}
else if (flag_pic)
emit_insn (gen_pic (ops[0], ops[1]));
if (flag_pic)
{
rtx pic_reg = get_pic_reg ();
emit_insn (gen_addsi3 (ops[0], ops[0], pic_reg));
current_function_uses_pic_offset_table = 1;
case IC_IL2:
{
unsigned char arrhi[16];
unsigned char arrlo[16];
rtx to, hi, lo;
int i;
constant_to_array (mode, ops[1], arrhi);
to = no_new_pseudos ? ops[0] : gen_reg_rtx (mode);
for (i = 0; i < 16; i += 4)
{
arrlo[i + 2] = arrhi[i + 2];
arrlo[i + 3] = arrhi[i + 3];
arrlo[i + 0] = arrlo[i + 1] = 0;
arrhi[i + 2] = arrhi[i + 3] = 0;
}
hi = array_to_constant (mode, arrhi);
lo = array_to_constant (mode, arrlo);
emit_move_insn (to, hi);
emit_insn (gen_rtx_SET
(VOIDmode, ops[0], gen_rtx_IOR (mode, to, lo)));
return 1;
}
case IC_POOL:
if (reload_in_progress || reload_completed)
{
rtx mem = force_const_mem (mode, ops[1]);
if (TARGET_LARGE_MEM)
{
rtx addr = gen_rtx_REG (Pmode, REGNO (ops[0]));
emit_move_insn (addr, XEXP (mem, 0));
mem = replace_equiv_address (mem, addr);
}
emit_move_insn (ops[0], mem);
return 1;
}
break;
case IC_IL1s:
case IC_IL2s:
if (reload_completed && GET_CODE (ops[1]) != HIGH)
{
if (c == IC_IL2s)
{
emit_insn (gen_high (ops[0], ops[1]));
emit_insn (gen_low (ops[0], ops[0], ops[1]));
}
else if (flag_pic)
emit_insn (gen_pic (ops[0], ops[1]));
if (flag_pic)
{
rtx pic_reg = get_pic_reg ();
emit_insn (gen_addsi3 (ops[0], ops[0], pic_reg));
current_function_uses_pic_offset_table = 1;
}
return flag_pic || c == IC_IL2s;
}
break;
case IC_IL1:
case IC_FSMBI:
case IC_CPAT:
break;
}
return 0;
}
/* SAVING is TRUE when we are generating the actual load and store
@ -2202,38 +2303,154 @@ which_immediate_load (HOST_WIDE_INT val)
return SPU_NONE;
}
/* Return true when OP can be loaded by one of the il instructions, or
when flow2 is not completed and OP can be loaded using ilhu and iohl. */
int
immediate_load_p (rtx op, enum machine_mode mode)
{
if (CONSTANT_P (op))
{
enum immediate_class c = classify_immediate (op, mode);
return c == IC_IL1 || (!flow2_completed && c == IC_IL2);
}
return 0;
}
/* Return true if the first SIZE bytes of arr is a constant that can be
generated with cbd, chd, cwd or cdd. When non-NULL, PRUN and PSTART
represent the size and offset of the instruction to use. */
static int
cpat_info(unsigned char *arr, int size, int *prun, int *pstart)
{
int cpat, run, i, start;
cpat = 1;
run = 0;
start = -1;
for (i = 0; i < size && cpat; i++)
if (arr[i] != i+16)
{
if (!run)
{
start = i;
if (arr[i] == 3)
run = 1;
else if (arr[i] == 2 && arr[i+1] == 3)
run = 2;
else if (arr[i] == 0)
{
while (arr[i+run] == run && i+run < 16)
run++;
if (run != 4 && run != 8)
cpat = 0;
}
else
cpat = 0;
if ((i & (run-1)) != 0)
cpat = 0;
i += run;
}
else
cpat = 0;
}
if (cpat)
{
if (run == 0)
run = 1;
if (prun)
*prun = run;
if (pstart)
*pstart = start == -1 ? 16-run : start;
return 1;
}
return 0;
}
/* OP is a CONSTANT_P. Determine what instructions can be used to load
it into a regiser. MODE is only valid when OP is a CONST_INT. */
static enum immediate_class
classify_immediate (rtx op, enum machine_mode mode)
{
HOST_WIDE_INT val;
unsigned char arr[16];
int i, j;
int i, j, repeated, fsmbi;
gcc_assert (CONSTANT_P (op));
if (GET_MODE (op) != VOIDmode)
mode = GET_MODE (op);
gcc_assert (GET_CODE (op) == CONST_INT || GET_CODE (op) == CONST_DOUBLE
|| GET_CODE (op) == CONST_VECTOR);
/* V4SI with all identical symbols is valid. */
/* A V4SI const_vector with all identical symbols is ok. */
if (mode == V4SImode
&& GET_CODE (CONST_VECTOR_ELT (op, 0)) == SYMBOL_REF)
return !TARGET_LARGE_MEM && !flag_pic
&& CONST_VECTOR_ELT (op, 0) == CONST_VECTOR_ELT (op, 1)
&& CONST_VECTOR_ELT (op, 1) == CONST_VECTOR_ELT (op, 2)
&& CONST_VECTOR_ELT (op, 2) == CONST_VECTOR_ELT (op, 3);
&& GET_CODE (op) == CONST_VECTOR
&& GET_CODE (CONST_VECTOR_ELT (op, 0)) != CONST_INT
&& GET_CODE (CONST_VECTOR_ELT (op, 0)) != CONST_DOUBLE
&& CONST_VECTOR_ELT (op, 0) == CONST_VECTOR_ELT (op, 1)
&& CONST_VECTOR_ELT (op, 1) == CONST_VECTOR_ELT (op, 2)
&& CONST_VECTOR_ELT (op, 2) == CONST_VECTOR_ELT (op, 3))
op = CONST_VECTOR_ELT (op, 0);
constant_to_array (mode, op, arr);
switch (GET_CODE (op))
{
case SYMBOL_REF:
case LABEL_REF:
return TARGET_LARGE_MEM ? IC_IL2s : IC_IL1s;
/* Check that bytes are repeated. */
for (i = 4; i < 16; i += 4)
for (j = 0; j < 4; j++)
if (arr[j] != arr[i + j])
return 0;
case CONST:
return TARGET_LARGE_MEM
|| !legitimate_const (op, 0) ? IC_IL2s : IC_IL1s;
val = (arr[0] << 24) | (arr[1] << 16) | (arr[2] << 8) | arr[3];
val = trunc_int_for_mode (val, SImode);
case HIGH:
return IC_IL1s;
return which_immediate_load (val) != SPU_NONE;
case CONST_VECTOR:
for (i = 0; i < GET_MODE_NUNITS (mode); i++)
if (GET_CODE (CONST_VECTOR_ELT (op, i)) != CONST_INT
&& GET_CODE (CONST_VECTOR_ELT (op, i)) != CONST_DOUBLE)
return IC_POOL;
/* Fall through. */
case CONST_INT:
case CONST_DOUBLE:
constant_to_array (mode, op, arr);
/* Check that each 4-byte slot is identical. */
repeated = 1;
for (i = 4; i < 16; i += 4)
for (j = 0; j < 4; j++)
if (arr[j] != arr[i + j])
repeated = 0;
if (repeated)
{
val = (arr[0] << 24) | (arr[1] << 16) | (arr[2] << 8) | arr[3];
val = trunc_int_for_mode (val, SImode);
if (which_immediate_load (val) != SPU_NONE)
return IC_IL1;
}
/* Any mode of 2 bytes or smaller can be loaded with an il
instruction. */
gcc_assert (GET_MODE_SIZE (mode) > 2);
fsmbi = 1;
for (i = 0; i < 16 && fsmbi; i++)
if (arr[i] != 0 && arr[i] != 0xff)
fsmbi = 0;
if (fsmbi)
return IC_FSMBI;
if (cpat_info (arr, GET_MODE_SIZE (mode), 0, 0))
return IC_CPAT;
if (repeated)
return IC_IL2;
return IC_POOL;
default:
break;
}
gcc_unreachable ();
}
static enum spu_immediate
@ -2361,31 +2578,7 @@ arith_immediate_p (rtx op, enum machine_mode mode,
int
spu_legitimate_constant_p (rtx x)
{
unsigned char arr[16];
int i, j;
if (GET_CODE (x) == HIGH
|| GET_CODE (x) == CONST
|| GET_CODE (x) == SYMBOL_REF
|| GET_CODE (x) == LABEL_REF)
return 1;
if (fsmbi_const_p (x))
return 1;
if (GET_CODE (x) == CONST_INT)
return (INTVAL (x) >= -0x80000000ll && INTVAL (x) <= 0x7fffffffll)
|| ((INTVAL (x) >> 32) & 0xffffffffll) == (INTVAL (x) & 0xffffffffll);
if (GET_MODE (x) == SFmode)
return 1;
if (GET_MODE (x) == DFmode)
{
HOST_WIDE_INT val = const_double_to_hwint (x);
return ((val >> 32) & 0xffffffffll) == (val & 0xffffffffll);
}
int i;
/* V4SI with all identical symbols is valid. */
if (GET_MODE (x) == V4SImode
&& (GET_CODE (CONST_VECTOR_ELT (x, 0)) == SYMBOL_REF
@ -2401,15 +2594,6 @@ spu_legitimate_constant_p (rtx x)
if (GET_CODE (CONST_VECTOR_ELT (x, i)) != CONST_INT
&& GET_CODE (CONST_VECTOR_ELT (x, i)) != CONST_DOUBLE)
return 0;
constant_to_array (SImode, x, arr);
/* Check that bytes are repeated. */
for (i = 4; i < 16; i += 4)
for (j = 0; j < 4; j++)
if (arr[j] != arr[i + j])
return 0;
return 1;
}
@ -3069,56 +3253,8 @@ spu_expand_mov (rtx * ops, enum machine_mode mode)
}
if (reload_in_progress || reload_completed)
{
enum machine_mode mode = GET_MODE (ops[0]);
if (GET_CODE (ops[1]) == CONST_INT
&& (mode == DImode || mode == TImode)
&& ((INTVAL (ops[1]) >> 32) & 0xffffffffll) !=
(INTVAL (ops[1]) & 0xffffffffll))
{
rtx mem = force_const_mem (mode, ops[1]);
if (TARGET_LARGE_MEM)
{
rtx addr = gen_rtx_REG (Pmode, REGNO (ops[0]));
emit_move_insn (addr, XEXP (mem, 0));
mem = replace_equiv_address (mem, addr);
}
emit_move_insn (ops[0], mem);
return 1;
}
else if ((GET_CODE (ops[1]) == CONST_INT
|| GET_CODE (ops[1]) == CONST_DOUBLE
|| GET_CODE (ops[1]) == CONST_VECTOR)
&& !immediate_load_p (ops[1], mode)
&& !fsmbi_const_p (ops[1]))
{
unsigned char arrlo[16];
unsigned char arrhi[16];
rtx to = ops[0], hi, lo;
int i;
constant_to_array (mode, ops[1], arrhi);
for (i = 0; i < 16; i += 4)
{
arrlo[i + 2] = arrhi[i + 2];
arrlo[i + 3] = arrhi[i + 3];
arrlo[i + 0] = arrlo[i + 1] = 0;
arrhi[i + 2] = arrhi[i + 3] = 0;
}
if (mode == SFmode)
{
to = spu_gen_subreg (SImode, ops[0]);
mode = SImode;
}
else if (mode == V4SFmode)
{
to = spu_gen_subreg (V4SImode, ops[0]);
mode = V4SImode;
}
hi = array_to_constant (mode, arrhi);
lo = array_to_constant (mode, arrlo);
emit_move_insn (to, hi);
emit_insn (gen_rtx_SET (VOIDmode, to, gen_rtx_IOR (mode, to, lo)));
return 1;
}
if (CONSTANT_P (ops[1]))
return spu_split_immediate (ops);
return 0;
}
else
@ -3474,19 +3610,59 @@ spu_valid_move (rtx * ops)
int
fsmbi_const_p (rtx x)
{
enum machine_mode mode;
unsigned char arr[16];
int i;
if (CONSTANT_P (x))
{
/* We can always choose DImode for CONST_INT because the high bits
of an SImode will always be all 1s, i.e., valid for fsmbi. */
enum immediate_class c = classify_immediate (x, DImode);
return c == IC_FSMBI;
}
return 0;
}
/* We can always choose DImode for CONST_INT because the high bits of
an SImode will always be all 1s, i.e., valid for fsmbi. */
mode = GET_CODE (x) == CONST_INT ? DImode : GET_MODE (x);
constant_to_array (mode, x, arr);
/* Return TRUE if x is a CONST_INT, CONST_DOUBLE or CONST_VECTOR that
can be generated using the cbd, chd, cwd or cdd instruction. */
int
cpat_const_p (rtx x, enum machine_mode mode)
{
if (CONSTANT_P (x))
{
enum immediate_class c = classify_immediate (x, mode);
return c == IC_CPAT;
}
return 0;
}
rtx
gen_cpat_const (rtx * ops)
{
unsigned char dst[16];
int i, offset, shift, isize;
if (GET_CODE (ops[3]) != CONST_INT
|| GET_CODE (ops[2]) != CONST_INT
|| (GET_CODE (ops[1]) != CONST_INT
&& GET_CODE (ops[1]) != REG))
return 0;
if (GET_CODE (ops[1]) == REG
&& (!REG_POINTER (ops[1])
|| REGNO_POINTER_ALIGN (ORIGINAL_REGNO (ops[1])) < 128))
return 0;
for (i = 0; i < 16; i++)
if (arr[i] != 0 && arr[i] != 0xff)
return 0;
return 1;
dst[i] = i + 16;
isize = INTVAL (ops[3]);
if (isize == 1)
shift = 3;
else if (isize == 2)
shift = 2;
else
shift = 0;
offset = (INTVAL (ops[2]) +
(GET_CODE (ops[1]) ==
CONST_INT ? INTVAL (ops[1]) : 0)) & 15;
for (i = 0; i < isize; i++)
dst[offset + i] = i + shift;
return array_to_constant (TImode, dst);
}
/* Convert a CONST_INT, CONST_DOUBLE, or CONST_VECTOR into a 16 byte

View File

@ -238,26 +238,19 @@
})
(define_split
[(set (match_operand:SI 0 "spu_reg_operand" "=r")
(match_operand:SI 1 "immediate_operand" "s"))]
[(set (match_operand 0 "spu_reg_operand")
(match_operand 1 "immediate_operand"))]
"(flag_pic || TARGET_LARGE_MEM
|| (GET_CODE (operands[1]) == CONST
&& !legitimate_const (operands[1], 0)))
&& (reload_in_progress || reload_completed)
&& (GET_CODE (operands[1]) == CONST
|| GET_CODE (operands[1]) == SYMBOL_REF
|| GET_CODE (operands[1]) == LABEL_REF)"
[(parallel
[(set (match_dup:SI 0)
(match_dup:SI 1))
(use (const_int 0))])
(set (match_dup:SI 0)
(plus:SI (match_dup:SI 0)
(match_dup:SI 2)))]
""
[(set (match_dup 0)
(high (match_dup 1)))
(set (match_dup 0)
(lo_sum (match_dup 0)
(match_dup 1)))]
{
spu_split_address(operands);
DONE;
if (spu_split_immediate (operands))
DONE;
FAIL;
})
(define_insn "pic"
@ -285,16 +278,17 @@
;; move internal
(define_insn "_mov<mode>"
[(set (match_operand:MOV 0 "spu_nonimm_operand" "=r,r,r,r,m")
(match_operand:MOV 1 "spu_mov_operand" "r,A,f,m,r"))]
[(set (match_operand:MOV 0 "spu_nonimm_operand" "=r,r,r,r,r,m")
(match_operand:MOV 1 "spu_mov_operand" "r,A,f,j,m,r"))]
"spu_valid_move (operands)"
"@
ori\t%0,%1,0
il%s1\t%0,%S1
fsmbi\t%0,%F1
fsmbi\t%0,%S1
c%s1d\t%0,%S1($sp)
lq%p1\t%0,%1
stq%p0\t%1,%0"
[(set_attr "type" "fx2,fx2,shuf,load,store")])
[(set_attr "type" "fx2,fx2,shuf,shuf,load,store")])
(define_insn "high"
[(set (match_operand:SI 0 "spu_reg_operand" "=r")
@ -310,28 +304,30 @@
"iohl\t%0,%2@l")
(define_insn "_movdi"
[(set (match_operand:DI 0 "spu_nonimm_operand" "=r,r,r,r,m")
(match_operand:DI 1 "spu_mov_operand" "r,a,f,m,r"))]
[(set (match_operand:DI 0 "spu_nonimm_operand" "=r,r,r,r,r,m")
(match_operand:DI 1 "spu_mov_operand" "r,a,f,k,m,r"))]
"spu_valid_move (operands)"
"@
ori\t%0,%1,0
il%d1\t%0,%D1
fsmbi\t%0,%G1
fsmbi\t%0,%D1
c%d1d\t%0,%D1($sp)
lq%p1\t%0,%1
stq%p0\t%1,%0"
[(set_attr "type" "fx2,fx2,shuf,load,store")])
[(set_attr "type" "fx2,fx2,shuf,shuf,load,store")])
(define_insn "_movti"
[(set (match_operand:TI 0 "spu_nonimm_operand" "=r,r,r,r,m")
(match_operand:TI 1 "spu_mov_operand" "r,U,f,m,r"))]
[(set (match_operand:TI 0 "spu_nonimm_operand" "=r,r,r,r,r,m")
(match_operand:TI 1 "spu_mov_operand" "r,U,f,l,m,r"))]
"spu_valid_move (operands)"
"@
ori\t%0,%1,0
il%t1\t%0,%T1
fsmbi\t%0,%H1
fsmbi\t%0,%T1
c%t1d\t%0,%T1($sp)
lq%p1\t%0,%1
stq%p0\t%1,%0"
[(set_attr "type" "fx2,fx2,shuf,load,store")])
[(set_attr "type" "fx2,fx2,shuf,shuf,load,store")])
(define_insn_and_split "load"
[(set (match_operand 0 "spu_reg_operand" "=r")
@ -358,10 +354,26 @@
{ spu_split_store(operands); DONE; })
;; Operand 3 is the number of bytes. 1:b 2:h 4:w 8:d
(define_insn "cpat"
(define_expand "cpat"
[(set (match_operand:TI 0 "spu_reg_operand" "=r,r")
(unspec:TI [(match_operand:SI 1 "spu_reg_operand" "r,r")
(match_operand:SI 2 "spu_nonmem_operand" "r,n")
(unspec:TI [(match_operand:SI 1 "spu_reg_operand" "r,r")
(match_operand:SI 2 "spu_nonmem_operand" "r,n")
(match_operand:SI 3 "immediate_operand" "i,i")] UNSPEC_CPAT))]
""
{
rtx x = gen_cpat_const (operands);
if (x)
{
emit_move_insn (operands[0], x);
DONE;
}
})
(define_insn "_cpat"
[(set (match_operand:TI 0 "spu_reg_operand" "=r,r")
(unspec:TI [(match_operand:SI 1 "spu_reg_operand" "r,r")
(match_operand:SI 2 "spu_nonmem_operand" "r,n")
(match_operand:SI 3 "immediate_operand" "i,i")] UNSPEC_CPAT))]
""
"@
@ -369,6 +381,19 @@
c%M3d\t%0,%C2(%1)"
[(set_attr "type" "shuf")])
(define_split
[(set (match_operand:TI 0 "spu_reg_operand")
(unspec:TI [(match_operand:SI 1 "spu_nonmem_operand")
(match_operand:SI 2 "immediate_operand")
(match_operand:SI 3 "immediate_operand")] UNSPEC_CPAT))]
""
[(set (match_dup:TI 0)
(match_dup:TI 4))]
{
operands[4] = gen_cpat_const (operands);
if (!operands[4])
FAIL;
})
;; extend