(define_insn "*pushsf"
[(set (match_operand:SF 0 "push_operand" "=<,<")
- (match_operand:SF 1 "general_operand" "f,Ffm*r"))]
+ (match_operand:SF 1 "general_operand" "f#r,rFm#f"))]
""
"*
{
(set (mem:SF (reg:SI 7)) (match_dup 1))])
(define_insn "*movsf_1"
- [(set (match_operand:SF 0 "nonimmediate_operand" "=f,m,f,*r,m,*r")
- (match_operand:SF 1 "general_operand" "fm,f,G,*rm,F*r,GF"))]
- ""
+ [(set (match_operand:SF 0 "nonimmediate_operand" "=f#r,m,f#r,r#f,m")
+ (match_operand:SF 1 "general_operand" "fm#r,f#r,G,rmF#f,Fr#f"))]
+ "GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM"
"*
{
switch (which_alternative)
case 3:
case 4:
- case 5:
return \"mov{l}\\t{%1, %0|%0, %1}\";
default:
abort();
}
}"
- [(set_attr "type" "fmov,fmov,fmov,imov,imov,imov")])
+ [(set_attr "type" "fmov,fmov,fmov,imov,imov")])
(define_insn "swapsf"
[(set (match_operand:SF 0 "register_operand" "+f")
""
"ix86_expand_move (DFmode, operands); DONE;")
+;; Size of pushdf is 3 (for sub) + 2 (for fstp) + memory operand size.
+;; Size of pushdf using integer insturctions is 2+2*memory operand size
+;; On the average, pushdf using integers can be still shorter. Allow this
+;; pattern for optimize_size too.
+
(define_insn "*pushdf"
[(set (match_operand:DF 0 "push_operand" "=<,<")
- (match_operand:DF 1 "general_operand" "f,ofF*r"))]
+ (match_operand:DF 1 "general_operand" "f#r,rFo#f"))]
""
"*
{
[(const_int 0)]
"if (!ix86_split_long_move (operands)) abort (); DONE;")
-(define_insn "*movdf_1"
+;; Moving is usually shorter when only FP registers are used. This separate
+;; movdf pattern avoids the use of integer registers for FP operations
+;; when optimizing for size.
+
+(define_insn "*movdf_nointeger"
[(set (match_operand:DF 0 "nonimmediate_operand" "=f,m,f,*r,o")
(match_operand:DF 1 "general_operand" "fm,f,G,*roF,F*r"))]
- ""
+ "(GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
+ && optimize_size"
+ "*
+{
+ switch (which_alternative)
+ {
+ case 0:
+ if (REG_P (operands[1])
+ && find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
+ return \"fstp\\t%y0\";
+ else if (STACK_TOP_P (operands[0]))
+ return \"fld%z1\\t%y1\";
+ else
+ return \"fst\\t%y0\";
+
+ case 1:
+ if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
+ return \"fstp%z0\\t%y0\";
+ else
+ return \"fst%z0\\t%y0\";
+
+ case 2:
+ switch (standard_80387_constant_p (operands[1]))
+ {
+ case 1:
+ return \"fldz\";
+ case 2:
+ return \"fld1\";
+ }
+ abort();
+
+ case 3:
+ case 4:
+ return \"#\";
+
+ default:
+ abort();
+ }
+}"
+ [(set_attr "type" "fmov,fmov,fmov,multi,multi")])
+
+(define_insn "*movdf_integer"
+ [(set (match_operand:DF 0 "nonimmediate_operand" "=f#r,m,f#r,r#f,o")
+ (match_operand:DF 1 "general_operand" "fm#r,f#r,G,roF#f,Fr#f"))]
+ "(GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
+ && !optimize_size"
"*
{
switch (which_alternative)
""
"ix86_expand_move (XFmode, operands); DONE;")
-(define_insn "*pushxf"
+;; Size of pushdf is 3 (for sub) + 2 (for fstp) + memory operand size.
+;; Size of pushdf using integer insturctions is 3+3*memory operand size
+;; Pushing using integer instructions is longer except for constants
+;; and direct memory references.
+;; (assuming that any given constant is pushed only once, but this ought to be
+;; handled elsewhere).
+
+(define_insn "*pushxf_nointeger"
+ [(set (match_operand:XF 0 "push_operand" "=<,<,<")
+ (match_operand:XF 1 "general_operand" "f,Fo,*r"))]
+ "optimize_size"
+ "*
+{
+ switch (which_alternative)
+ {
+ case 0:
+ /* %%% We loose REG_DEAD notes for controling pops if we split late. */
+ operands[0] = gen_rtx_MEM (XFmode, stack_pointer_rtx);
+ operands[2] = stack_pointer_rtx;
+ operands[3] = GEN_INT (12);
+ if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
+ return \"sub{l}\\t{%3, %2|%2, %3}\;fstp%z0\\t%y0\";
+ else
+ return \"sub{l}\\t{%3, %2|%2, %3}\;fst%z0\\t%y0\";
+
+ case 1:
+ case 2:
+ return \"#\";
+
+ default:
+ abort ();
+ }
+}"
+ [(set_attr "type" "multi")])
+
+(define_insn "*pushxf_integer"
[(set (match_operand:XF 0 "push_operand" "=<,<")
- (match_operand:XF 1 "register_operand" "f,oF*r"))]
- ""
+ (match_operand:XF 1 "general_operand" "f#r,rFo#f"))]
+ "!optimize_size"
"*
{
- /* %%% We loose REG_DEAD notes for controling pops if we split late. */
- operands[0] = gen_rtx_MEM (XFmode, stack_pointer_rtx);
- operands[2] = stack_pointer_rtx;
- operands[3] = GEN_INT (12);
- if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
- return \"sub{l}\\t{%3, %2|%2, %3}\;fstp%z0\\t%y0\";
- else
- return \"sub{l}\\t{%3, %2|%2, %3}\;fst%z0\\t%y0\";
+ switch (which_alternative)
+ {
+ case 0:
+ /* %%% We loose REG_DEAD notes for controling pops if we split late. */
+ operands[0] = gen_rtx_MEM (XFmode, stack_pointer_rtx);
+ operands[2] = stack_pointer_rtx;
+ operands[3] = GEN_INT (12);
+ if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
+ return \"sub{l}\\t{%3, %2|%2, %3}\;fstp%z0\\t%y0\";
+ else
+ return \"sub{l}\\t{%3, %2|%2, %3}\;fst%z0\\t%y0\";
+
+ case 1:
+ return \"#\";
+
+ default:
+ abort ();
+ }
}"
[(set_attr "type" "multi")])
[(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -12)))
(set (mem:XF (reg:SI 7)) (match_dup 1))])
-(define_split
- [(set (match_operand:DF 0 "push_operand" "")
- (match_operand:DF 1 "memory_operand" ""))]
- "reload_completed"
- [(set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 2))
- (set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 1))
- (set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 0))]
- "
+;; Do not use integer registers when optimizing for size
+(define_insn "*movxf_nointeger"
+ [(set (match_operand:XF 0 "nonimmediate_operand" "=f,m,f,*r,o")
+ (match_operand:XF 1 "general_operand" "fm,f,G,*roF,F*r"))]
+ "(GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
+ && optimize_size"
+ "*
{
- operands[0] = change_address (operands[1], SImode, NULL_RTX);
- operands[1] = adj_offsettable_operand (operands[0], 4);
- operands[2] = adj_offsettable_operand (operands[0], 8);
- /* Compensate for the fact that we're changing stack offsets in
- the middle of this operation. */
- if (reg_mentioned_p (stack_pointer_rtx, operands[1]))
- operands[1] = adj_offsettable_operand (operands[1], 4);
- if (reg_mentioned_p (stack_pointer_rtx, operands[0]))
- operands[0] = adj_offsettable_operand (operands[0], 8);
-}")
+ switch (which_alternative)
+ {
+ case 0:
+ if (REG_P (operands[1])
+ && find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
+ return \"fstp\\t%y0\";
+ else if (STACK_TOP_P (operands[0]))
+ return \"fld%z1\\t%y1\";
+ else
+ return \"fst\\t%y0\";
-(define_insn "*movxf_1"
- [(set (match_operand:XF 0 "nonimmediate_operand" "=f,m,f,*r,o")
- (match_operand:XF 1 "general_operand" "fm,f,G,*roF,*r"))]
- ""
+ case 1:
+ /* There is no non-popping store to memory for XFmode. So if
+ we need one, follow the store with a load. */
+ if (! find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
+ return \"fstp%z0\\t%y0\;fld%z0\\t%y0\";
+ else
+ return \"fstp%z0\\t%y0\";
+
+ case 2:
+ switch (standard_80387_constant_p (operands[1]))
+ {
+ case 1:
+ return \"fldz\";
+ case 2:
+ return \"fld1\";
+ }
+ break;
+
+ case 3: case 4:
+ return \"#\";
+ }
+ abort();
+}"
+ [(set_attr "type" "fmov,fmov,fmov,multi,multi")])
+
+(define_insn "*movxf_integer"
+ [(set (match_operand:XF 0 "nonimmediate_operand" "=f#r,m,f#r,r#f,o")
+ (match_operand:XF 1 "general_operand" "fm#r,f#r,G,roF#f,Fr#f"))]
+ "(GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
+ && !optimize_size"
"*
{
switch (which_alternative)
}
abort();
}"
- [(set_attr "type" "fmov")])
+ [(set_attr "type" "fmov,fmov,fmov,multi,multi")])
(define_split
[(set (match_operand:XF 0 "nonimmediate_operand" "")
(match_operand:XF 1 "general_operand" ""))]
"reload_completed
- && ((REG_P (operands[0]) && ! FP_REGNO_P (REGNO (operands[0])))
- || (REG_P (operands[1]) && ! FP_REGNO_P (REGNO (operands[1]))))"
+ && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
+ && ! (FP_REG_P (operands[0]) ||
+ (GET_CODE (operands[0]) == SUBREG
+ && FP_REG_P (SUBREG_REG (operands[0]))))
+ && ! (FP_REG_P (operands[1]) ||
+ (GET_CODE (operands[1]) == SUBREG
+ && FP_REG_P (SUBREG_REG (operands[1]))))"
[(set (match_dup 2) (match_dup 5))
(set (match_dup 3) (match_dup 6))
(set (match_dup 4) (match_dup 7))]