Make long longs use normal CONST_DOUBLE in movdi, do not split too early

From-SVN: r11513
This commit is contained in:
Michael Meissner 1996-03-11 18:57:23 +00:00
parent 9740123d5c
commit 4e74d8ec4b
3 changed files with 246 additions and 58 deletions

View File

@ -524,6 +524,90 @@ reg_or_cint_operand (op, mode)
return GET_CODE (op) == CONST_INT || gpc_reg_operand (op, mode);
}
/* Return the number of instructions it takes to form a constant in an
integer register. */
static int
num_insns_constant_wide (value)
HOST_WIDE_INT value;
{
/* signed constant loadable with {cal|addi} */
if (((unsigned HOST_WIDE_INT)value + 0x8000) < 0x10000)
return 1;
#if HOST_BITS_PER_WIDE_INT == 32
/* constant loadable with {cau|addis} */
else if ((value & 0xffff) == 0)
return 1;
#else
/* constant loadable with {cau|addis} */
else if ((value & 0xffff) == 0 && (value & ~0xffffffff) == 0)
return 1;
else if (TARGET_64BIT)
{
HOST_WIDE_INT low = value & 0xffffffff;
HOST_WIDE_INT high = value >> 32;
if (high == 0 && (low & 0x80000000) == 0)
return 2;
else if (high == 0xffffffff && (low & 0x80000000) != 0)
return 2;
else if (!low)
return num_insns_constant_wide (high) + 1;
else
return (num_insns_constant_wide (high)
+ num_insns_constant_low (low) + 1);
}
#endif
else
return 2;
}
int
num_insns_constant (op, mode)
rtx op;
enum machine_mode mode;
{
if (mode != SImode && mode != DImode)
abort ();
if (GET_CODE (op) == CONST_INT)
return num_insns_constant_wide (INTVAL (op));
else if (GET_CODE (op) == CONST_DOUBLE && TARGET_32BIT)
return (num_insns_constant_wide (CONST_DOUBLE_LOW (op))
+ num_insns_constant_wide (CONST_DOUBLE_HIGH (op)));
else if (GET_CODE (op) == CONST_DOUBLE && TARGET_64BIT)
{
HOST_WIDE_INT low = CONST_DOUBLE_LOW (op);
HOST_WIDE_INT high = CONST_DOUBLE_HIGH (op);
if (high == 0 && (low & 0x80000000) == 0)
return num_insns_constant_wide (low);
else if (((high & 0xffffffff) == 0xffffffff)
&& ((low & 0x80000000) != 0))
return num_insns_constant_wide (low);
else if (low == 0)
return num_insns_constant_wide (high) + 1;
else
return (num_insns_constant_wide (high)
+ num_insns_constant_wide (low) + 1);
}
else
abort ();
}
/* Return 1 if the operand is a CONST_DOUBLE and it can be put into a register
with one instruction per word. We only do this if we can safely read
CONST_DOUBLE_{LOW,HIGH}. */
@ -535,11 +619,11 @@ easy_fp_constant (op, mode)
{
if (GET_CODE (op) != CONST_DOUBLE
|| GET_MODE (op) != mode
|| GET_MODE_CLASS (mode) != MODE_FLOAT)
|| (GET_MODE_CLASS (mode) != MODE_FLOAT && mode != DImode))
return 0;
/* Consider all constants with -msoft-float to be easy */
if (TARGET_SOFT_FLOAT)
if (TARGET_SOFT_FLOAT && mode != DImode)
return 1;
if (mode == DFmode)
@ -550,10 +634,11 @@ easy_fp_constant (op, mode)
REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
REAL_VALUE_TO_TARGET_DOUBLE (rv, k);
return (((unsigned) (k[0] + 0x8000) < 0x10000 || (k[0] & 0xffff) == 0)
&& ((unsigned) (k[1] + 0x8000) < 0x10000 || (k[1] & 0xffff) == 0));
return (num_insns_constant_wide ((HOST_WIDE_INT)k[0]) == 1
&& num_insns_constant_wide ((HOST_WIDE_INT)k[1]) == 1);
}
else
else if (mode == SFmode)
{
long l;
REAL_VALUE_TYPE rv;
@ -561,8 +646,14 @@ easy_fp_constant (op, mode)
REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
REAL_VALUE_TO_TARGET_SINGLE (rv, l);
return ((unsigned) (l + 0x8000) < 0x10000 || (l & 0xffff) == 0);
return num_insns_constant_wide (l) == 1;
}
else if (mode == DImode && TARGET_32BIT)
return num_insns_constant (op, DImode) == 2;
else
abort ();
}
/* Return 1 if the operand is in volatile memory. Note that during the
@ -821,6 +912,11 @@ input_operand (op, mode)
&& easy_fp_constant (op, mode))
return 1;
/* Allow any integer constant. */
if (GET_MODE_CLASS (mode) == MODE_INT
&& (GET_CODE (op) == CONST_INT || GET_CODE (op) == CONST_DOUBLE))
return 1;
/* For floating-point or multi-word mode, the only remaining valid type
is a register. */
if (GET_MODE_CLASS (mode) == MODE_FLOAT
@ -833,10 +929,6 @@ input_operand (op, mode)
if (register_operand (op, mode))
return 1;
/* For integer modes, any constant is ok. */
if (GET_CODE (op) == CONST_INT)
return 1;
/* A SYMBOL_REF referring to the TOC is valid. */
if (LEGITIMATE_CONSTANT_POOL_ADDRESS_P (op))
return 1;

View File

@ -995,10 +995,14 @@ enum reg_class
Here VALUE is the CONST_DOUBLE rtx itself.
We flag for special constants when we can copy the constant into
a general register in two insns for DF and one insn for SF. */
a general register in two insns for DF/DI and one insn for SF.
#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) \
((C) == 'G' ? easy_fp_constant (VALUE, GET_MODE (VALUE)) : 0)
'H' is used for DI constants that take 3 insns. */
#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) \
((C) == 'G' ? easy_fp_constant (VALUE, GET_MODE (VALUE)) : \
(C) == 'H' ? (num_insns_constant (VALUE, DImode) == 3) : \
0)
/* Optional extra constraints for this machine.
@ -2819,6 +2823,7 @@ extern int reg_or_short_operand ();
extern int reg_or_neg_short_operand ();
extern int reg_or_u_short_operand ();
extern int reg_or_cint_operand ();
extern int num_insns_constant ();
extern int easy_fp_constant ();
extern int volatile_mem_operand ();
extern int offsettable_addr_operand ();

View File

@ -5429,8 +5429,9 @@
if (GET_CODE (operands[0]) != REG)
operands[1] = force_reg (DImode, operands[1]);
if (GET_CODE (operands[1]) == CONST_DOUBLE
|| GET_CODE (operands[1]) == CONST_INT)
if (TARGET_64BIT
&& (GET_CODE (operands[1]) == CONST_DOUBLE
|| GET_CODE (operands[1]) == CONST_INT))
{
HOST_WIDE_INT low;
HOST_WIDE_INT high;
@ -5453,39 +5454,23 @@
}
#endif
if (! TARGET_POWERPC64)
{
emit_move_insn (gen_rtx (SUBREG, SImode, operands[0],
WORDS_BIG_ENDIAN), GEN_INT (low));
emit_move_insn (gen_rtx (SUBREG, SImode, operands[0],
! WORDS_BIG_ENDIAN), GEN_INT (high));
DONE;
}
else
{
if (high + 0x8000 >= 0x10000)
{
emit_move_insn (gen_rtx (SUBREG, SImode, operands[0], 1),
GEN_INT (high));
emit_insn (gen_ashldi3 (operands[0], operands[0], GEN_INT(32)));
if (low)
{
HOST_WIDE_INT low_low = low & 0xffff;
HOST_WIDE_INT low_high = low & (~ (HOST_WIDE_INT) 0xffff);
if (low_high)
emit_insn (gen_iordi3 (operands[0], operands[0],
GEN_INT (low_high)));
if (low_low)
emit_insn (gen_iordi3 (operands[0], operands[0],
GEN_INT (low_low)));
}
}
else if (low)
emit_move_insn (gen_rtx (SUBREG, SImode, operands[0], 1),
GEN_INT (low));
DONE;
}
if (high)
{
emit_move_insn (operands[0], GEN_INT (high));
emit_insn (gen_ashldi3 (operands[0], operands[0], GEN_INT(32)));
if (low)
{
HOST_WIDE_INT low_low = low & 0xffff;
HOST_WIDE_INT low_high = low & (~ (HOST_WIDE_INT) 0xffff);
if (low_high)
emit_insn (gen_iordi3 (operands[0], operands[0],
GEN_INT (low_high)));
if (low_low)
emit_insn (gen_iordi3 (operands[0], operands[0],
GEN_INT (low_low)));
}
DONE;
}
}
/* Stores between FPR and any non-FPR registers must go through a
@ -5506,10 +5491,11 @@
}")
(define_insn ""
[(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,m,f,f,m")
(match_operand:DI 1 "input_operand" "r,m,r,f,m,f"))]
"! TARGET_POWERPC64 && (gpc_reg_operand (operands[0], DImode)
|| gpc_reg_operand (operands[1], DImode))"
[(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,m,f,f,m,r,r,r,r,r")
(match_operand:DI 1 "input_operand" "r,m,r,f,m,f,IJK,n,G,H,F"))]
"TARGET_32BIT
&& (gpc_reg_operand (operands[0], DImode)
|| gpc_reg_operand (operands[1], DImode))"
"*
{
switch (which_alternative)
@ -5540,16 +5526,121 @@
return \"lfd%U1%X1 %0,%1\";
case 5:
return \"stfd%U0%X0 %1,%0\";
case 6:
case 7:
case 8:
case 9:
case 10:
return \"#\";
}
}"
[(set_attr "type" "*,load,store,fp,fpload,fpstore")
(set_attr "length" "8,8,8,*,*,*")])
[(set_attr "type" "*,load,store,fp,fpload,fpstore,*,*,*,*,*")
(set_attr "length" "8,8,8,*,*,*,8,12,8,12,16")])
(define_split
[(set (match_operand:DI 0 "gpc_reg_operand" "")
(match_operand:DI 1 "const_int_operand" ""))]
"TARGET_32BIT && reload_completed && num_insns_constant (operands[1], DImode) <= 1"
[(set (match_dup 2) (match_dup 4))
(set (match_dup 3) (match_dup 1))]
"
{
operands[2] = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN == 0);
operands[3] = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN != 0);
operands[4] = (INTVAL (operands[1]) & 0x80000000) ? constm1_rtx : const0_rtx;
}")
(define_split
[(set (match_operand:DI 0 "gpc_reg_operand" "")
(match_operand:DI 1 "const_int_operand" ""))]
"TARGET_32BIT && reload_completed && num_insns_constant (operands[1], DImode) >= 2"
[(set (match_dup 3) (match_dup 5))
(set (match_dup 2) (match_dup 4))
(set (match_dup 3) (ior:SI (match_dup 3) (match_dup 6)))]
"
{
HOST_WIDE_INT value = INTVAL (operands[1]);
operands[2] = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN == 0);
operands[3] = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN != 0);
operands[4] = (value & 0x80000000) ? constm1_rtx : const0_rtx;
operands[5] = GEN_INT (value & 0xffff0000);
operands[6] = GEN_INT (value & 0x0000ffff);
}")
(define_split
[(set (match_operand:DI 0 "gpc_reg_operand" "")
(match_operand:DI 1 "const_double_operand" ""))]
"TARGET_32BIT && reload_completed && num_insns_constant (operands[1], DImode) <= 2"
[(set (match_dup 2) (match_dup 4))
(set (match_dup 3) (match_dup 5))]
"
{
operands[2] = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN == 0);
operands[3] = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN != 0);
operands[4] = GEN_INT (CONST_DOUBLE_HIGH (operands[1]));
operands[5] = GEN_INT (CONST_DOUBLE_LOW (operands[1]));
}")
(define_split
[(set (match_operand:DI 0 "gpc_reg_operand" "")
(match_operand:DI 1 "const_double_operand" ""))]
"TARGET_32BIT && reload_completed && num_insns_constant (operands[1], DImode) == 3"
[(set (match_dup 2) (match_dup 4))
(set (match_dup 3) (match_dup 5))
(set (match_dup 2) (ior:SI (match_dup 2) (match_dup 6)))]
"
{
HOST_WIDE_INT high = CONST_DOUBLE_HIGH (operands[1]);
HOST_WIDE_INT low = CONST_DOUBLE_LOW (operands[1]);
rtx high_reg = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN == 0);
rtx low_reg = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN != 0);
if (((unsigned HOST_WIDE_INT) (low + 0x8000) < 0x10000)
|| (low & 0xffff) == 0)
{
operands[2] = high_reg;
operands[3] = low_reg;
operands[4] = GEN_INT (high & 0xffff0000);
operands[5] = GEN_INT (low);
operands[6] = GEN_INT (high & 0x0000ffff);
}
else
{
operands[2] = low_reg;
operands[3] = high_reg;
operands[4] = GEN_INT (low & 0xffff0000);
operands[5] = GEN_INT (high);
operands[6] = GEN_INT (low & 0x0000ffff);
}
}")
(define_split
[(set (match_operand:DI 0 "gpc_reg_operand" "")
(match_operand:DI 1 "const_double_operand" ""))]
"TARGET_32BIT && reload_completed && num_insns_constant (operands[1], DImode) >= 4"
[(set (match_dup 2) (match_dup 4))
(set (match_dup 3) (match_dup 5))
(set (match_dup 2) (ior:SI (match_dup 2) (match_dup 6)))
(set (match_dup 3) (ior:SI (match_dup 3) (match_dup 7)))]
"
{
HOST_WIDE_INT high = CONST_DOUBLE_HIGH (operands[1]);
HOST_WIDE_INT low = CONST_DOUBLE_LOW (operands[1]);
operands[2] = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN == 0);
operands[3] = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN != 0);
operands[4] = GEN_INT (high & 0xffff0000);
operands[5] = GEN_INT (low & 0xffff0000);
operands[6] = GEN_INT (high & 0x0000ffff);
operands[7] = GEN_INT (low & 0x0000ffff);
}")
(define_insn ""
[(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,m,r,r,r,r,f,f,m,r,*h,*h")
(match_operand:DI 1 "input_operand" "r,m,r,I,J,n,R,f,m,f,*h,r,0"))]
"TARGET_POWERPC64 && (gpc_reg_operand (operands[0], DImode)
|| gpc_reg_operand (operands[1], DImode))"
(match_operand:DI 1 "input_operand" "r,m,r,I,J,nF,R,f,m,f,*h,r,0"))]
"TARGET_64BIT
&& (gpc_reg_operand (operands[0], DImode)
|| gpc_reg_operand (operands[1], DImode))"
"@
mr %0,%1
ld%U1%X1 %0,%1
@ -5574,7 +5665,7 @@
(define_split
[(set (match_operand:DI 0 "gpc_reg_operand" "")
(match_operand:DI 1 "const_double_operand" ""))]
"TARGET_POWERPC64"
"TARGET_64BIT && num_insns_constant (operands[1], DImode) > 1"
[(set (match_dup 0)
(match_dup 2))
(set (match_dup 0)