This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
i386 conditional moves and fp conditionals
- To: gcc-patches at gcc dot gnu dot org, patches at x86-64 dot org, rth at cygnus dot com
- Subject: i386 conditional moves and fp conditionals
- From: Jan Hubicka <jh at suse dot cz>
- Date: Sat, 13 Jan 2001 14:14:25 +0100
Hi
This patch adds support for multiple test conditionos to the conditional move
patterns. This allows gcc to emit nice conditinal moves like this one:
float a,b,c;
eq()
{
if (a!=b) c=a; else c=b;
}
to:
eq:
flds a
flds b
fucomi %st(1), %st
fcmovne %st(1), %st
fcmovu %st(1), %st
fstp %st(1)
fstps c
ret
So led 13 14:03:40 CET 2001 Jan Hubicka <jh@suse.cz>
* i386.c (ix86_expand_compare): Add bypass_test and second_test
parameters.
(ix86_expand_branch): Update.
(ix86_expand_setcc): Update to handle multiple test conditions.
(expand_int_movcc): Likewise.
(expand_fp_movcc): Likewise.
* i386-protos.h (ix86_expand_compare): New.
* i386.md (andqi_?_slp, orqi_?_slp): New.
(conditional trap expander): Update call to ix86_expand_compare.
*** i386.c.old Sat Jan 13 12:32:09 2001
--- i386.c Sat Jan 13 13:59:43 2001
*************** ix86_expand_fp_compare (code, op0, op1,
*** 5160,5175 ****
}
rtx
! ix86_expand_compare (code)
enum rtx_code code;
{
rtx op0, op1, ret;
op0 = ix86_compare_op0;
op1 = ix86_compare_op1;
if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
ret = ix86_expand_fp_compare (code, op0, op1, gen_reg_rtx (HImode),
! NULL, NULL);
else
ret = ix86_expand_int_compare (code, op0, op1);
--- 5160,5181 ----
}
rtx
! ix86_expand_compare (code, second_test, bypass_test)
enum rtx_code code;
+ rtx *second_test, *bypass_test;
{
rtx op0, op1, ret;
op0 = ix86_compare_op0;
op1 = ix86_compare_op1;
+ if (second_test)
+ *second_test = NULL_RTX;
+ if (bypass_test)
+ *bypass_test = NULL_RTX;
+
if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
ret = ix86_expand_fp_compare (code, op0, op1, gen_reg_rtx (HImode),
! second_test, bypass_test);
else
ret = ix86_expand_int_compare (code, op0, op1);
*************** ix86_expand_branch (code, label)
*** 5188,5194 ****
case QImode:
case HImode:
case SImode:
! tmp = ix86_expand_compare (code);
tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
gen_rtx_LABEL_REF (VOIDmode, label),
pc_rtx);
--- 5194,5200 ----
case QImode:
case HImode:
case SImode:
! tmp = ix86_expand_compare (code, NULL, NULL);
tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
gen_rtx_LABEL_REF (VOIDmode, label),
pc_rtx);
*************** ix86_expand_setcc (code, dest)
*** 5403,5409 ****
enum rtx_code code;
rtx dest;
{
! rtx ret, tmp;
int type;
if (GET_MODE (ix86_compare_op0) == DImode)
--- 5409,5416 ----
enum rtx_code code;
rtx dest;
{
! rtx ret, tmp, tmpreg;
! rtx second_test, bypass_test;
int type;
if (GET_MODE (ix86_compare_op0) == DImode)
*************** ix86_expand_setcc (code, dest)
*** 5429,5441 ****
if (type == 0)
emit_move_insn (dest, const0_rtx);
! ret = ix86_expand_compare (code);
PUT_MODE (ret, QImode);
tmp = dest;
if (type == 0)
{
tmp = gen_lowpart (QImode, dest);
tmp = gen_rtx_STRICT_LOW_PART (VOIDmode, tmp);
}
else if (type == 1)
--- 5436,5450 ----
if (type == 0)
emit_move_insn (dest, const0_rtx);
! ret = ix86_expand_compare (code, &second_test, &bypass_test);
PUT_MODE (ret, QImode);
tmp = dest;
+ tmpreg = dest;
if (type == 0)
{
tmp = gen_lowpart (QImode, dest);
+ tmpreg = tmp;
tmp = gen_rtx_STRICT_LOW_PART (VOIDmode, tmp);
}
else if (type == 1)
*************** ix86_expand_setcc (code, dest)
*** 5444,5452 ****
--- 5453,5483 ----
tmp = gen_reg_rtx (QImode);
else
tmp = gen_lowpart (QImode, dest);
+ tmpreg = tmp;
}
emit_insn (gen_rtx_SET (VOIDmode, tmp, ret));
+ if (bypass_test || second_test)
+ {
+ rtx test = second_test;
+ int bypass = 0;
+ rtx tmp2 = gen_reg_rtx (QImode);
+ if (bypass_test)
+ {
+ if (second_test)
+ abort();
+ test = bypass_test;
+ bypass = 1;
+ PUT_CODE (test, reverse_condition_maybe_unordered (GET_CODE (test)));
+ }
+ PUT_MODE (test, QImode);
+ emit_insn (gen_rtx_SET (VOIDmode, tmp2, test));
+
+ if (bypass)
+ emit_insn (gen_andqi3 (tmp, tmpreg, tmp2));
+ else
+ emit_insn (gen_iorqi3 (tmp, tmpreg, tmp2));
+ }
if (type == 1)
{
*************** ix86_expand_int_movcc (operands)
*** 5468,5473 ****
--- 5499,5505 ----
{
enum rtx_code code = GET_CODE (operands[1]), compare_code;
rtx compare_seq, compare_op;
+ rtx second_test, bypass_test;
/* When the compare code is not LTU or GEU, we can not use sbbl case.
In case comparsion is done with immediate, we can convert it to LTU or
*************** ix86_expand_int_movcc (operands)
*** 5488,5494 ****
}
start_sequence ();
! compare_op = ix86_expand_compare (code);
compare_seq = gen_sequence ();
end_sequence ();
--- 5520,5526 ----
}
start_sequence ();
! compare_op = ix86_expand_compare (code, &second_test, &bypass_test);
compare_seq = gen_sequence ();
end_sequence ();
*************** ix86_expand_int_movcc (operands)
*** 5506,5512 ****
HOST_WIDE_INT cf = INTVAL (operands[3]);
HOST_WIDE_INT diff;
! if (compare_code == LTU || compare_code == GEU)
{
/* Detect overlap between destination and compare sources. */
--- 5538,5545 ----
HOST_WIDE_INT cf = INTVAL (operands[3]);
HOST_WIDE_INT diff;
! if ((compare_code == LTU || compare_code == GEU)
! && !second_test && !bypass_test)
{
/* Detect overlap between destination and compare sources. */
*************** ix86_expand_int_movcc (operands)
*** 5795,5805 ****
--- 5828,5863 ----
if (! nonimmediate_operand (operands[3], GET_MODE (operands[0])))
operands[3] = force_reg (GET_MODE (operands[0]), operands[3]);
+ if (bypass_test && reg_overlap_mentioned_p (operands[0], operands[3]))
+ {
+ rtx tmp = gen_reg_rtx (GET_MODE (operands[0]));
+ emit_move_insn (tmp, operands[3]);
+ operands[3] = tmp;
+ }
+ if (second_test && reg_overlap_mentioned_p (operands[0], operands[2]))
+ {
+ rtx tmp = gen_reg_rtx (GET_MODE (operands[0]));
+ emit_move_insn (tmp, operands[2]);
+ operands[2] = tmp;
+ }
+
emit_insn (compare_seq);
emit_insn (gen_rtx_SET (VOIDmode, operands[0],
gen_rtx_IF_THEN_ELSE (GET_MODE (operands[0]),
compare_op, operands[2],
operands[3])));
+ if (bypass_test)
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0],
+ gen_rtx_IF_THEN_ELSE (GET_MODE (operands[0]),
+ bypass_test,
+ operands[3],
+ operands[0])));
+ if (second_test)
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0],
+ gen_rtx_IF_THEN_ELSE (GET_MODE (operands[0]),
+ second_test,
+ operands[2],
+ operands[0])));
return 1; /* DONE */
}
*************** ix86_expand_fp_movcc (operands)
*** 5812,5835 ****
enum machine_mode mode;
rtx tmp;
rtx compare_op;
/* The floating point conditional move instructions don't directly
support conditions resulting from a signed integer comparison. */
code = GET_CODE (operands[1]);
! compare_op = ix86_expand_compare (code);
/* The floating point conditional move instructions don't directly
support signed integer comparisons. */
if (!fcmov_comparison_operator (compare_op, VOIDmode))
{
tmp = gen_reg_rtx (QImode);
ix86_expand_setcc (code, tmp);
code = NE;
ix86_compare_op0 = tmp;
ix86_compare_op1 = const0_rtx;
! compare_op = ix86_expand_compare (code);
}
emit_insn (gen_rtx_SET (VOIDmode, operands[0],
--- 5870,5908 ----
enum machine_mode mode;
rtx tmp;
rtx compare_op;
+ rtx second_test, bypass_test;
/* The floating point conditional move instructions don't directly
support conditions resulting from a signed integer comparison. */
code = GET_CODE (operands[1]);
! compare_op = ix86_expand_compare (code, &second_test, &bypass_test);
/* The floating point conditional move instructions don't directly
support signed integer comparisons. */
if (!fcmov_comparison_operator (compare_op, VOIDmode))
{
+ if (second_test != NULL || bypass_test != NULL)
+ abort();
tmp = gen_reg_rtx (QImode);
ix86_expand_setcc (code, tmp);
code = NE;
ix86_compare_op0 = tmp;
ix86_compare_op1 = const0_rtx;
! compare_op = ix86_expand_compare (code, &second_test, &bypass_test);
! }
! if (bypass_test && reg_overlap_mentioned_p (operands[0], operands[3]))
! {
! tmp = gen_reg_rtx (GET_MODE (operands[0]));
! emit_move_insn (tmp, operands[3]);
! operands[3] = tmp;
! }
! if (second_test && reg_overlap_mentioned_p (operands[0], operands[2]))
! {
! tmp = gen_reg_rtx (GET_MODE (operands[0]));
! emit_move_insn (tmp, operands[2]);
! operands[2] = tmp;
}
emit_insn (gen_rtx_SET (VOIDmode, operands[0],
*************** ix86_expand_fp_movcc (operands)
*** 5837,5842 ****
--- 5910,5927 ----
compare_op,
operands[2],
operands[3])));
+ if (bypass_test)
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0],
+ gen_rtx_IF_THEN_ELSE (GET_MODE (operands[0]),
+ bypass_test,
+ operands[3],
+ operands[0])));
+ if (second_test)
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0],
+ gen_rtx_IF_THEN_ELSE (GET_MODE (operands[0]),
+ second_test,
+ operands[2],
+ operands[0])));
return 1;
}
*** i386-protos.h.old Sat Jan 13 12:31:53 2001
--- i386-protos.h Sat Jan 13 12:32:00 2001
*************** extern void ix86_expand_unary_operator P
*** 102,108 ****
extern int ix86_unary_operator_ok PARAMS ((enum rtx_code, enum machine_mode,
rtx[]));
extern int ix86_match_ccmode PARAMS ((rtx, enum machine_mode));
! extern rtx ix86_expand_compare PARAMS ((enum rtx_code));
extern int ix86_use_fcomi_compare PARAMS ((enum rtx_code));
extern void ix86_expand_branch PARAMS ((enum rtx_code, rtx));
extern int ix86_expand_setcc PARAMS ((enum rtx_code, rtx));
--- 102,108 ----
extern int ix86_unary_operator_ok PARAMS ((enum rtx_code, enum machine_mode,
rtx[]));
extern int ix86_match_ccmode PARAMS ((rtx, enum machine_mode));
! extern rtx ix86_expand_compare PARAMS ((enum rtx_code, rtx *, rtx *));
extern int ix86_use_fcomi_compare PARAMS ((enum rtx_code));
extern void ix86_expand_branch PARAMS ((enum rtx_code, rtx));
extern int ix86_expand_setcc PARAMS ((enum rtx_code, rtx));
*** i386.md.orig Sat Dec 16 20:00:57 2000
--- i386.md Sat Jan 13 13:53:15 2001
***************
*** 5713,5718 ****
--- 6263,6280 ----
[(set_attr "type" "alu")
(set_attr "mode" "QI,QI,SI")])
+ (define_insn "*andqi_1_slp"
+ [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm,q"))
+ (and:QI (match_dup 0)
+ (match_operand:QI 2 "general_operand" "qi,qmi")))
+ (clobber (reg:CC 17))]
+ "ix86_binary_operator_ok (AND, QImode, operands)"
+ "@
+ and{b}\\t{%2, %0|%0, %2}
+ and{b}\\t{%2, %0|%0, %2}"
+ [(set_attr "type" "alu")
+ (set_attr "mode" "QI,QI")])
+
(define_insn "*andqi_2"
[(set (reg 17)
(compare (and:QI
***************
*** 5730,5735 ****
--- 6292,6313 ----
[(set_attr "type" "alu")
(set_attr "mode" "QI,QI,SI")])
+ (define_insn "*andqi_2_slp"
+ [(set (reg 17)
+ (compare (and:QI
+ (match_operand:QI 1 "nonimmediate_operand" "+0,0")
+ (match_dup 0))
+ (const_int 0)))
+ (set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "=q,qm"))
+ (and:QI (match_dup 1) (match_dup 2)))]
+ "ix86_match_ccmode (insn, CCNOmode)
+ && ix86_binary_operator_ok (AND, QImode, operands)"
+ "@
+ and{b}\\t{%2, %0|%0, %2}
+ and{b}\\t{%2, %0|%0, %2}"
+ [(set_attr "type" "alu")
+ (set_attr "mode" "QI,QI")])
+
;; ??? A bug in recog prevents it from recognizing a const_int as an
;; operand to zero_extend in andqi_ext_1. It was checking explicitly
;; for a QImode operand, which of course failed.
***************
*** 5929,5934 ****
--- 6507,6524 ----
or{b}\\t{%2, %0|%0, %2}
or{l}\\t{%k2, %k0|%k0, %k2}"
[(set_attr "type" "alu")
+ (set_attr "mode" "QI,QI,SI")])
+
+ (define_insn "*iorqi_1_slp"
+ [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+q,m"))
+ (ior:QI (match_dup 0)
+ (match_operand:QI 2 "general_operand" "qmi,qi")))
+ (clobber (reg:CC 17))]
+ "ix86_binary_operator_ok (IOR, QImode, operands)"
+ "@
+ or{b}\\t{%2, %0|%0, %2}
+ or{b}\\t{%2, %0|%0, %2}"
+ [(set_attr "type" "alu")
(set_attr "mode" "QI")])
(define_insn "*iorqi_2"
***************
*** 5944,5949 ****
--- 6534,6552 ----
[(set_attr "type" "alu")
(set_attr "mode" "QI")])
+ (define_insn "*iorqi_2_slp"
+ [(set (reg 17)
+ (compare (ior:QI (match_dup 0)
+ (match_operand:QI 2 "general_operand" "qim,qi"))
+ (const_int 0)))
+ (set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+q,qm"))
+ (ior:QI (match_dup 1) (match_dup 2)))]
+ "ix86_match_ccmode (insn, CCNOmode)
+ && ix86_binary_operator_ok (IOR, QImode, operands)"
+ "or{b}\\t{%2, %0|%0, %2}"
+ [(set_attr "type" "alu")
+ (set_attr "mode" "QI")])
+
(define_insn "*iorqi_3"
[(set (reg 17)
(compare (ior:QI (match_operand:QI 1 "nonimmediate_operand" "%0")
***************
*** 11624,11630 ****
"
{
emit_insn (gen_rtx_TRAP_IF (VOIDmode,
! ix86_expand_compare (GET_CODE (operands[0])),
operands[1]));
DONE;
}")
--- 12549,12556 ----
"
{
emit_insn (gen_rtx_TRAP_IF (VOIDmode,
! ix86_expand_compare (GET_CODE (operands[0]),
! NULL_RTX, NULL_RTX),
operands[1]));
DONE;
}")