Commit 7c82106f by Uros Bizjak Committed by Uros Bizjak

i386-protos.h (ix86_split_fp_branch): New rtx argument.

        * config/i386/i386-protos.h (ix86_split_fp_branch): New rtx
        argument.

        * config/i386/i386.c (output_fp_compare): Fix is_sse condition.
        Use EFLAGS_P only when fcomi insn should be used. Fix handling
        of eflags_p variable. Change alt table accordingly. For non-fcomi
        compare insn always use trailing fnstsw insn. Fix intmode
        calculation for ficom insn.
        (ix86_split_fp_branch): Add "rtx pushed" as new parameter. Call
        ix86_free_from_memory when "pushed" is specified.
        (ix86_expand_branch): Change call to ix86_split_fp_branch.

        * config/i386/i386.md (*cmpfp_0_sf, *cmpfp_0_df, *cmpfp_0_xf):
        Change eflags_p parameter in call to output_fp_compare.
        (*cmpfp_2_sf, *cmpfp_2_df, *cmpfp_2_xf): Remove.
        (*cmpfp_2_sf_1, *cmpfp_2_df_1, *cmpfp_2_xf_1): Rename to
        *cmpfp_2_sf, *cmpfp_2_df, *cmpfp_2_xf.  Change eflags_p
        parameter in call to output_fp_compare.
        (*cmpfp_2_u): Remove.
        (*cmpfp_2_u_1): Rename to *cmpfp_2_u. Change eflags_p parameter
        in call to output_fp_compare.
        (*ficom_1): Remove insn definition and corresponding define_split.
        (*cmpfp_si): New insn definition.
        (*fp_jcc_8): New insn definition. Add new splitters for
        "memory_operand" and "register_operand".
        (define_split): Add new parameter in call to ix86_split_fp_branch.

        config/i386/predicates.md (float_operator): New predicate.

From-SVN: r91856
parent ac1b13f4
2004-12-07 Uros Bizjak <uros@kss-loka.si>
* config/i386/i386-protos.h (ix86_split_fp_branch): New rtx
argument.
* config/i386/i386.c (output_fp_compare): Fix is_sse condition.
Use EFLAGS_P only when fcomi insn should be used. Fix handling
of eflags_p variable. Change alt table accordingly. For non-fcomi
compare insn always use trailing fnstsw insn. Fix intmode
calculation for ficom insn.
(ix86_split_fp_branch): Add "rtx pushed" as new parameter. Call
ix86_free_from_memory when "pushed" is specified.
(ix86_expand_branch): Change call to ix86_split_fp_branch.
* config/i386/i386.md (*cmpfp_0_sf, *cmpfp_0_df, *cmpfp_0_xf):
Change eflags_p parameter in call to output_fp_compare.
(*cmpfp_2_sf, *cmpfp_2_df, *cmpfp_2_xf): Remove.
(*cmpfp_2_sf_1, *cmpfp_2_df_1, *cmpfp_2_xf_1): Rename to
*cmpfp_2_sf, *cmpfp_2_df, *cmpfp_2_xf. Change eflags_p
parameter in call to output_fp_compare.
(*cmpfp_2_u): Remove.
(*cmpfp_2_u_1): Rename to *cmpfp_2_u. Change eflags_p parameter
in call to output_fp_compare.
(*ficom_1): Remove insn definition and corresponding define_split.
(*cmpfp_si): New insn definition.
(*fp_jcc_8): New insn definition. Add new splitters for
"memory_operand" and "register_operand".
(define_split): Add new parameter in call to ix86_split_fp_branch.
config/i386/predicates.md (float_operator): New predicate.
2004-12-08 Kazu Hirata <kazu@cs.umass.edu>
* c-common.c (verify_tree): Don't check code length if we know
......
......@@ -165,7 +165,8 @@ extern rtx ix86_va_arg (tree, tree);
extern rtx ix86_force_to_memory (enum machine_mode, rtx);
extern void ix86_free_from_memory (enum machine_mode);
extern void ix86_split_fp_branch (enum rtx_code code, rtx, rtx, rtx, rtx, rtx);
extern void ix86_split_fp_branch (enum rtx_code code, rtx, rtx,
rtx, rtx, rtx, rtx);
extern int ix86_hard_regno_mode_ok (int, enum machine_mode);
extern int ix86_register_move_cost (enum machine_mode, enum reg_class,
enum reg_class);
......
......@@ -7208,25 +7208,24 @@ output_fix_trunc (rtx insn, rtx *operands)
}
/* Output code for INSN to compare OPERANDS. EFLAGS_P is 1 when fcomi
should be used and 2 when fnstsw should be used. UNORDERED_P is true
when fucom should be used. */
should be used. UNORDERED_P is true when fucom should be used. */
const char *
output_fp_compare (rtx insn, rtx *operands, int eflags_p, int unordered_p)
{
int stack_top_dies;
rtx cmp_op0, cmp_op1;
int is_sse = SSE_REG_P (operands[0]) | SSE_REG_P (operands[1]);
int is_sse = SSE_REG_P (operands[0]) || SSE_REG_P (operands[1]);
if (eflags_p == 2)
if (eflags_p)
{
cmp_op0 = operands[1];
cmp_op1 = operands[2];
cmp_op0 = operands[0];
cmp_op1 = operands[1];
}
else
{
cmp_op0 = operands[0];
cmp_op1 = operands[1];
cmp_op0 = operands[1];
cmp_op1 = operands[2];
}
if (is_sse)
......@@ -7268,7 +7267,7 @@ output_fp_compare (rtx insn, rtx *operands, int eflags_p, int unordered_p)
is also a stack register that dies, then this must be a
`fcompp' float compare */
if (eflags_p == 1)
if (eflags_p)
{
/* There is no double popping fcomi variant. Fortunately,
eflags is immune from the fstp's cc clobbering. */
......@@ -7280,35 +7279,25 @@ output_fp_compare (rtx insn, rtx *operands, int eflags_p, int unordered_p)
}
else
{
if (eflags_p == 2)
{
if (unordered_p)
return "fucompp\n\tfnstsw\t%0";
else
return "fcompp\n\tfnstsw\t%0";
}
if (unordered_p)
return "fucompp\n\tfnstsw\t%0";
else
{
if (unordered_p)
return "fucompp";
else
return "fcompp";
}
return "fcompp\n\tfnstsw\t%0";
}
}
else
{
/* Encoded here as eflags_p | intmode | unordered_p | stack_top_dies. */
static const char * const alt[24] =
static const char * const alt[16] =
{
"fcom%z1\t%y1",
"fcomp%z1\t%y1",
"fucom%z1\t%y1",
"fucomp%z1\t%y1",
"fcom%z2\t%y2\n\tfnstsw\t%0",
"fcomp%z2\t%y2\n\tfnstsw\t%0",
"fucom%z2\t%y2\n\tfnstsw\t%0",
"fucomp%z2\t%y2\n\tfnstsw\t%0",
"ficom%z1\t%y1",
"ficomp%z1\t%y1",
"ficom%z2\t%y2\n\tfnstsw\t%0",
"ficomp%z2\t%y2\n\tfnstsw\t%0",
NULL,
NULL,
......@@ -7320,16 +7309,6 @@ output_fp_compare (rtx insn, rtx *operands, int eflags_p, int unordered_p)
NULL,
NULL,
NULL,
NULL,
"fcom%z2\t%y2\n\tfnstsw\t%0",
"fcomp%z2\t%y2\n\tfnstsw\t%0",
"fucom%z2\t%y2\n\tfnstsw\t%0",
"fucomp%z2\t%y2\n\tfnstsw\t%0",
"ficom%z2\t%y2\n\tfnstsw\t%0",
"ficomp%z2\t%y2\n\tfnstsw\t%0",
NULL,
NULL
};
......@@ -7337,11 +7316,11 @@ output_fp_compare (rtx insn, rtx *operands, int eflags_p, int unordered_p)
const char *ret;
mask = eflags_p << 3;
mask |= (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT) << 2;
mask |= (GET_MODE_CLASS (GET_MODE (cmp_op1)) == MODE_INT) << 2;
mask |= unordered_p << 1;
mask |= stack_top_dies;
if (mask >= 24)
if (mask >= 16)
abort ();
ret = alt[mask];
if (ret == NULL)
......@@ -8458,7 +8437,7 @@ ix86_expand_branch (enum rtx_code code, rtx label)
{
ix86_split_fp_branch (code, ix86_compare_op0, ix86_compare_op1,
gen_rtx_LABEL_REF (VOIDmode, label),
pc_rtx, NULL_RTX);
pc_rtx, NULL_RTX, NULL_RTX);
}
else
{
......@@ -8606,7 +8585,7 @@ ix86_expand_branch (enum rtx_code code, rtx label)
/* Split branch based on floating point condition. */
void
ix86_split_fp_branch (enum rtx_code code, rtx op1, rtx op2,
rtx target1, rtx target2, rtx tmp)
rtx target1, rtx target2, rtx tmp, rtx pushed)
{
rtx second, bypass;
rtx label = NULL_RTX;
......@@ -8625,6 +8604,10 @@ ix86_split_fp_branch (enum rtx_code code, rtx op1, rtx op2,
condition = ix86_expand_fp_compare (code, op1, op2,
tmp, &second, &bypass);
/* Remove pushed operand from stack. */
if (pushed)
ix86_free_from_memory (GET_MODE (pushed));
if (split_branch_probability >= 0)
{
/* Distribute the probabilities across the jumps.
......
......@@ -797,6 +797,9 @@
;; CCFPmode compare with exceptions
;; CCFPUmode compare with no exceptions
;; We may not use "#" to split and emit these, since the REG_DEAD notes
;; used to manage the reg stack popping would not be preserved.
(define_insn "*cmpfp_0_sf"
[(set (match_operand:HI 0 "register_operand" "=a")
(unspec:HI
......@@ -805,7 +808,7 @@
(match_operand:SF 2 "const0_operand" "X"))]
UNSPEC_FNSTSW))]
"TARGET_80387"
"* return output_fp_compare (insn, operands, 2, 0);"
"* return output_fp_compare (insn, operands, 0, 0);"
[(set_attr "type" "multi")
(set_attr "mode" "SF")])
......@@ -817,7 +820,7 @@
(match_operand:DF 2 "const0_operand" "X"))]
UNSPEC_FNSTSW))]
"TARGET_80387"
"* return output_fp_compare (insn, operands, 2, 0);"
"* return output_fp_compare (insn, operands, 0, 0);"
[(set_attr "type" "multi")
(set_attr "mode" "DF")])
......@@ -829,24 +832,11 @@
(match_operand:XF 2 "const0_operand" "X"))]
UNSPEC_FNSTSW))]
"TARGET_80387"
"* return output_fp_compare (insn, operands, 2, 0);"
"* return output_fp_compare (insn, operands, 0, 0);"
[(set_attr "type" "multi")
(set_attr "mode" "XF")])
;; We may not use "#" to split and emit these, since the REG_DEAD notes
;; used to manage the reg stack popping would not be preserved.
(define_insn "*cmpfp_2_sf"
[(set (reg:CCFP FPSR_REG)
(compare:CCFP
(match_operand:SF 0 "register_operand" "f")
(match_operand:SF 1 "nonimmediate_operand" "fm")))]
"TARGET_80387"
"* return output_fp_compare (insn, operands, 0, 0);"
[(set_attr "type" "fcmp")
(set_attr "mode" "SF")])
(define_insn "*cmpfp_2_sf_1"
(define_insn "*cmpfp_sf"
[(set (match_operand:HI 0 "register_operand" "=a")
(unspec:HI
[(compare:CCFP
......@@ -854,21 +844,11 @@
(match_operand:SF 2 "nonimmediate_operand" "fm"))]
UNSPEC_FNSTSW))]
"TARGET_80387"
"* return output_fp_compare (insn, operands, 2, 0);"
[(set_attr "type" "fcmp")
(set_attr "mode" "SF")])
(define_insn "*cmpfp_2_df"
[(set (reg:CCFP FPSR_REG)
(compare:CCFP
(match_operand:DF 0 "register_operand" "f")
(match_operand:DF 1 "nonimmediate_operand" "fm")))]
"TARGET_80387"
"* return output_fp_compare (insn, operands, 0, 0);"
[(set_attr "type" "fcmp")
(set_attr "mode" "DF")])
(set_attr "mode" "SF")])
(define_insn "*cmpfp_2_df_1"
(define_insn "*cmpfp_df"
[(set (match_operand:HI 0 "register_operand" "=a")
(unspec:HI
[(compare:CCFP
......@@ -876,21 +856,11 @@
(match_operand:DF 2 "nonimmediate_operand" "fm"))]
UNSPEC_FNSTSW))]
"TARGET_80387"
"* return output_fp_compare (insn, operands, 2, 0);"
"* return output_fp_compare (insn, operands, 0, 0);"
[(set_attr "type" "multi")
(set_attr "mode" "DF")])
(define_insn "*cmpfp_2_xf"
[(set (reg:CCFP FPSR_REG)
(compare:CCFP
(match_operand:XF 0 "register_operand" "f")
(match_operand:XF 1 "register_operand" "f")))]
"TARGET_80387"
"* return output_fp_compare (insn, operands, 0, 0);"
[(set_attr "type" "fcmp")
(set_attr "mode" "XF")])
(define_insn "*cmpfp_2_xf_1"
(define_insn "*cmpfp_xf"
[(set (match_operand:HI 0 "register_operand" "=a")
(unspec:HI
[(compare:CCFP
......@@ -898,29 +868,11 @@
(match_operand:XF 2 "register_operand" "f"))]
UNSPEC_FNSTSW))]
"TARGET_80387"
"* return output_fp_compare (insn, operands, 2, 0);"
"* return output_fp_compare (insn, operands, 0, 0);"
[(set_attr "type" "multi")
(set_attr "mode" "XF")])
(define_insn "*cmpfp_2u"
[(set (reg:CCFPU FPSR_REG)
(compare:CCFPU
(match_operand 0 "register_operand" "f")
(match_operand 1 "register_operand" "f")))]
"TARGET_80387
&& FLOAT_MODE_P (GET_MODE (operands[0]))
&& GET_MODE (operands[0]) == GET_MODE (operands[1])"
"* return output_fp_compare (insn, operands, 0, 1);"
[(set_attr "type" "fcmp")
(set (attr "mode")
(cond [(match_operand:SF 1 "" "")
(const_string "SF")
(match_operand:DF 1 "" "")
(const_string "DF")
]
(const_string "XF")))])
(define_insn "*cmpfp_2u_1"
(define_insn "*cmpfp_u"
[(set (match_operand:HI 0 "register_operand" "=a")
(unspec:HI
[(compare:CCFPU
......@@ -930,7 +882,7 @@
"TARGET_80387
&& FLOAT_MODE_P (GET_MODE (operands[1]))
&& GET_MODE (operands[1]) == GET_MODE (operands[2])"
"* return output_fp_compare (insn, operands, 2, 1);"
"* return output_fp_compare (insn, operands, 0, 1);"
[(set_attr "type" "multi")
(set (attr "mode")
(cond [(match_operand:SF 1 "" "")
......@@ -940,40 +892,21 @@
]
(const_string "XF")))])
;; Patterns to match the SImode-in-memory ficom instructions.
;;
;; %%% Play games with accepting gp registers, as otherwise we have to
;; force them to memory during rtl generation, which is no good. We
;; can get rid of this once we teach reload to do memory input reloads
;; via pushes.
(define_insn "*ficom_1"
[(set (reg:CCFP FPSR_REG)
(compare:CCFP
(match_operand 0 "register_operand" "f,f")
(float (match_operand:SI 1 "nonimmediate_operand" "m,?r"))))]
"0 && TARGET_80387 && FLOAT_MODE_P (GET_MODE (operands[0]))
&& GET_MODE (XEXP (SET_SRC (PATTERN (insn)), 1)) == GET_MODE (operands[0])"
"#")
;; Split the not-really-implemented gp register case into a
;; push-op-pop sequence.
;;
;; %%% This is most efficient, but am I gonna get in trouble
;; for separating cc0_setter and cc0_user?
(define_split
[(set (reg:CCFP FPSR_REG)
(compare:CCFP
(match_operand:SF 0 "register_operand" "")
(float (match_operand:SI 1 "register_operand" ""))))]
"0 && TARGET_80387 && reload_completed"
[(set (mem:SI (pre_dec:SI (reg:SI SP_REG))) (match_dup 1))
(set (reg:CCFP FPSR_REG) (compare:CCFP (match_dup 0) (match_dup 2)))
(parallel [(set (match_dup 1) (mem:SI (reg:SI SP_REG)))
(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int 4)))])]
"operands[2] = gen_rtx_MEM (Pmode, stack_pointer_rtx);
operands[2] = gen_rtx_FLOAT (GET_MODE (operands[0]), operands[2]);")
(define_insn "*cmpfp_si"
[(set (match_operand:HI 0 "register_operand" "=a")
(unspec:HI
[(compare:CCFP
(match_operand 1 "register_operand" "f")
(match_operator 3 "float_operator"
[(match_operand:SI 2 "memory_operand" "m")]))]
UNSPEC_FNSTSW))]
"TARGET_80387 && TARGET_USE_FIOP
&& FLOAT_MODE_P (GET_MODE (operands[1]))
&& (GET_MODE (operands [3]) == GET_MODE (operands[1]))"
"* return output_fp_compare (insn, operands, 0, 0);"
[(set_attr "type" "multi")
(set_attr "fp_int_src" "true")
(set_attr "mode" "SI")])
;; FP compares, step 2
;; Move the fpsw to ax.
......@@ -13298,6 +13231,30 @@
&& ix86_fp_jump_nontrivial_p (GET_CODE (operands[0]))"
"#")
;; The order of operands in *fp_jcc_8 is forced by combine in
;; simplify_comparison () function. Float operator is treated as RTX_OBJ
;; with a precedence over other operators and is always put in the first
;; place. Swap condition and operands to match ficom instruction.
(define_insn "*fp_jcc_8"
[(set (pc)
(if_then_else (match_operator 0 "comparison_operator"
[(match_operator 1 "float_operator"
[(match_operand:SI 2 "nonimmediate_operand" "m,?r")])
(match_operand 3 "register_operand" "f,f")])
(label_ref (match_operand 4 "" ""))
(pc)))
(clobber (reg:CCFP FPSR_REG))
(clobber (reg:CCFP FLAGS_REG))
(clobber (match_scratch:HI 5 "=a,a"))]
"TARGET_80387 && TARGET_USE_FIOP
&& FLOAT_MODE_P (GET_MODE (operands[3]))
&& GET_MODE (operands[1]) == GET_MODE (operands[3])
&& !ix86_use_fcomi_compare (swap_condition (GET_CODE (operands[0])))
&& ix86_fp_compare_mode (swap_condition (GET_CODE (operands[0]))) == CCFPmode
&& ix86_fp_jump_nontrivial_p (swap_condition (GET_CODE (operands[0])))"
"#")
(define_split
[(set (pc)
(if_then_else (match_operator 0 "comparison_operator"
......@@ -13311,7 +13268,7 @@
[(const_int 0)]
{
ix86_split_fp_branch (GET_CODE (operands[0]), operands[1], operands[2],
operands[3], operands[4], NULL_RTX);
operands[3], operands[4], NULL_RTX, NULL_RTX);
DONE;
})
......@@ -13329,7 +13286,51 @@
[(const_int 0)]
{
ix86_split_fp_branch (GET_CODE (operands[0]), operands[1], operands[2],
operands[3], operands[4], operands[5]);
operands[3], operands[4], operands[5], NULL_RTX);
DONE;
})
(define_split
[(set (pc)
(if_then_else (match_operator 0 "comparison_operator"
[(match_operator 1 "float_operator"
[(match_operand:SI 2 "memory_operand" "")])
(match_operand 3 "register_operand" "")])
(match_operand 4 "" "")
(match_operand 5 "" "")))
(clobber (reg:CCFP FPSR_REG))
(clobber (reg:CCFP FLAGS_REG))
(clobber (match_scratch:HI 6 "=a"))]
"reload_completed"
[(const_int 0)]
{
operands[7] = gen_rtx_FLOAT (GET_MODE (operands[1]), operands[2]);
ix86_split_fp_branch (swap_condition (GET_CODE (operands[0])),
operands[3], operands[7],
operands[4], operands[5], operands[6], NULL_RTX);
DONE;
})
;; %%% Kill this when reload knows how to do it.
(define_split
[(set (pc)
(if_then_else (match_operator 0 "comparison_operator"
[(match_operator 1 "float_operator"
[(match_operand:SI 2 "register_operand" "")])
(match_operand 3 "register_operand" "")])
(match_operand 4 "" "")
(match_operand 5 "" "")))
(clobber (reg:CCFP FPSR_REG))
(clobber (reg:CCFP FLAGS_REG))
(clobber (match_scratch:HI 6 "=a"))]
"reload_completed"
[(const_int 0)]
{
operands[7] = ix86_force_to_memory (GET_MODE (operands[2]), operands[2]);
operands[7] = gen_rtx_FLOAT (GET_MODE (operands[1]), operands[7]);
ix86_split_fp_branch (swap_condition (GET_CODE (operands[0])),
operands[3], operands[7],
operands[4], operands[5], operands[6], operands[2]);
DONE;
})
......
......@@ -795,6 +795,10 @@
(define_predicate "div_operator"
(match_code "div"))
;; Return true if this is a float extend operation.
(define_predicate "float_operator"
(match_code "float"))
;; Return true for ARITHMETIC_P.
(define_predicate "arith_or_logical_operator"
(match_code "PLUS,MULT,AND,IOR,XOR,SMIN,SMAX,UMIN,UMAX,COMPARE,MINUS,DIV,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment