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}. */
{
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)
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;
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
&& 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
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;
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;
}
#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
}")
(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)
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
(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)