}
/* 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)
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. */
}
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,
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
};
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)
{
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
{
/* 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;
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.
;; 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
(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")])
(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")])
(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
(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
(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
(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
"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 "" "")
]
(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.
&& 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"
[(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;
})
[(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;
})
\f