else
abort ();
}
- if (GET_CODE (operands[1]) == MEM)
+ else if (GET_CODE (operands[1]) == MEM)
return "ld %1,%0";
- if (GET_CODE (operands[1]) == CONST_INT
- && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I'))
+ else if (GET_CODE (operands[1]) == CONST_DOUBLE)
+ {
+ int i;
+ union real_extract u;
+ union float_extract { float f; int i; } v;
+
+ /* Must be SFmode, otherwise this doesn't make sense. */
+ if (GET_MODE (operands[1]) != SFmode)
+ abort ();
+
+ bcopy (&CONST_DOUBLE_LOW (operands[1]), &u, sizeof u);
+ v.f = REAL_VALUE_TRUNCATE (SFmode, u.d);
+ i = v.i;
+
+ operands[1] = gen_rtx (CONST_INT, VOIDmode, i);
+
+ if (CONST_OK_FOR_LETTER_P (i, 'I'))
+ return "mov %1,%0";
+ else if ((i & 0x000003FF) != 0)
+ return "sethi %%hi(%a1),%0\n\tor %0,%%lo(%a1),%0";
+ else
+ return "sethi %%hi(%a1),%0";
+ }
+ else if (GET_CODE (operands[1]) == CONST_INT
+ && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I'))
{
int i = INTVAL (operands[1]);
else
return "sethi %%hi(%a1),%0";
}
- /* ??? Wrong if target is DImode? */
+ /* Operand 1 must be a register, or a 'I' type CONST_INT. */
return "mov %1,%0";
}
\f
in class CLASS, return the class of reg to actually use.
In general this is just CLASS; but on some machines
in some cases it is preferable to use a more restrictive class. */
-#define PREFERRED_RELOAD_CLASS(X,CLASS) CLASS
+/* We can't load constants into FP registers. We can't load any FP constant
+ if an 'E' constraint fails to match it. */
+#define PREFERRED_RELOAD_CLASS(X,CLASS) \
+ (CONSTANT_P (X) \
+ && ((CLASS) == FP_REGS \
+ || (GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT \
+ && (HOST_FLOAT_FORMAT != IEEE_FLOAT_FORMAT \
+ || HOST_BITS_PER_INT != BITS_PER_WORD))) \
+ ? NO_REGS : (CLASS))
/* Return the register class of a scratch register needed to load IN into
a register of class CLASS in MODE.
;; This pattern forces (set (reg:DF ...) (const_double ...))
;; to be reloaded by putting the constant into memory.
;; It must come before the more general movdf pattern.
-;; ??? A similar pattern for SF mode values would also be useful, but it
-;; is not as easy to write.
(define_insn ""
[(set (match_operand:DF 0 "general_operand" "=?r,f,o")
(match_operand:DF 1 "" "?E,m,G"))]
;; Floating-point move insns.
+;; This pattern forces (set (reg:SF ...) (const_double ...))
+;; to be reloaded by putting the constant into memory.
+;; It must come before the more general movsf pattern.
+(define_insn ""
+ [(set (match_operand:SF 0 "general_operand" "=?r,f,m")
+ (match_operand:SF 1 "" "?E,m,G"))]
+ "GET_CODE (operands[1]) == CONST_DOUBLE"
+ "*
+{
+ switch (which_alternative)
+ {
+ case 0:
+ return singlemove_string (operands);
+ case 1:
+ return \"ld %1,%0\";
+ case 2:
+ return \"st %%g0,%0\";
+ }
+}"
+ [(set_attr "type" "load,fpload,store")
+ (set_attr "length" "2,1,1")])
+
(define_expand "movsf"
[(set (match_operand:SF 0 "general_operand" "")
(match_operand:SF 1 "general_operand" ""))]
/* If the giv is an address destination, it could be something other
than a simple register, these have to be treated differently. */
else if (v->giv_type == DEST_REG)
- splittable_regs[REGNO (v->new_reg)] = value;
+ {
+ /* If value is not a constant, register, or register plus
+ constant, then compute its value into a register before
+ loop start. This prevents illegal rtx sharing, and should
+ generate better code. We can use bl->initial_value here
+ instead of splittable_regs[bl->regno] because this code
+ is going before the loop start. */
+ if (unroll_type == UNROLL_COMPLETELY
+ && GET_CODE (value) != CONST_INT
+ && GET_CODE (value) != REG
+ && (GET_CODE (value) != PLUS
+ || GET_CODE (XEXP (value, 0)) != REG
+ || GET_CODE (XEXP (value, 1)) != CONST_INT))
+ {
+ rtx tem = gen_reg_rtx (v->mode);
+ emit_iv_add_mult (bl->initial_value, v->mult_val,
+ v->add_val, tem, loop_start);
+ value = tem;
+ }
+
+ splittable_regs[REGNO (v->new_reg)] = value;
+ }
else
{
/* Splitting address givs is useful since it will often allow us