This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

i386 conditional moves and fp conditionals



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;
  }")

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]