aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Meissner <meissner@gcc.gnu.org>1996-03-11 18:57:23 +0000
committerMichael Meissner <meissner@gcc.gnu.org>1996-03-11 18:57:23 +0000
commit4e74d8ec4b55e5a28738f5d3a2cb99335c0098f4 (patch)
treeb5fa20378e26ae7489158972aa94a5c3eecf201d
parent9740123d5c5e2fd32c7413dd9bdbdabdbb6b07b2 (diff)
downloadgcc-4e74d8ec4b55e5a28738f5d3a2cb99335c0098f4.zip
gcc-4e74d8ec4b55e5a28738f5d3a2cb99335c0098f4.tar.gz
gcc-4e74d8ec4b55e5a28738f5d3a2cb99335c0098f4.tar.bz2
Make long longs use normal CONST_DOUBLE in movdi, do not split too early
From-SVN: r11513
-rw-r--r--gcc/config/rs6000/rs6000.c112
-rw-r--r--gcc/config/rs6000/rs6000.h11
-rw-r--r--gcc/config/rs6000/rs6000.md181
3 files changed, 246 insertions, 58 deletions
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 6d89bea..34fdab7 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -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;
diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h
index f49c687..aa1e5f0 100644
--- a/gcc/config/rs6000/rs6000.h
+++ b/gcc/config/rs6000/rs6000.h
@@ -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 ();
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index aa1b0fe..5c47d6a 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -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)