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]

cond_exec patch 4/4


The actual COND_EXEC rtx code. 

The distinction between COND_EXEC and IF_THEN_ELSE is that
COND_EXEC is defined to be a no-op if the predicate is false,
whereas IF_THEN_ELSE may or may not incur side effects from
the false branch. 

In practice there is also a difference in scheduling too:
architectures that provide only a tradidional conditional move
require both true and false inputs to be ready, whereas an
architecture with predication will not stall waiting for
inputs of an insn whose predicate is false.

This patch merely recognizes COND_EXEC in important places.
The bits to actually generate it have not yet been merged
from the branch.


r~


        * rtl.def (COND_EXEC): New.
        * rtl.h (COND_EXEC_TEST, COND_EXEC_CODE): New.
        * tm.texi (MAX_CONDITIONAL_EXECUTE): Document.

        * genconfig.c (have_cond_arith_flag): Remove.
        (have_cond_exec_flag): New.
        (walk_insn_part): Detect COND_EXEC, not arithmetic in IF_THEN_ELSE.
        (main): Print HAVE_conditional_execution.

        * haifa-sched.c (haifa_classify_insn): Recognize COND_EXEC.
        (sched_analyze_insn, print_pattern): Likewise.
	* reload.c (find_equiv_reg): Likewise.
	* rtlanal.c (reg_referenced_p): Likewise.
        (note_stores, dead_or_set_regno_p): Likewise.
	(reg_overlap_mentioned_p): Rewrite to use a switch.

Index: genconfig.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/genconfig.c,v
retrieving revision 1.32
diff -c -p -d -r1.32 genconfig.c
*** genconfig.c	2000/02/26 13:50:42	1.32
--- genconfig.c	2000/04/07 08:56:54
*************** static int max_dup_operands;    /* Large
*** 39,45 ****
  static int max_clobbers_per_insn;
  static int have_cc0_flag;
  static int have_cmove_flag;
! static int have_cond_arith_flag;
  static int have_lo_sum_flag;
  static int have_peephole_flag;
  static int have_peephole2_flag;
--- 39,45 ----
  static int max_clobbers_per_insn;
  static int have_cc0_flag;
  static int have_cmove_flag;
! static int have_cond_exec_flag;
  static int have_lo_sum_flag;
  static int have_peephole_flag;
  static int have_peephole2_flag;
*************** walk_insn_part (part, recog_p, non_pc_se
*** 131,151 ****
  	 two arms of the IF_THEN_ELSE are both MATCH_OPERAND.  Otherwise,
  	 we have some specific IF_THEN_ELSE construct (like the doz
  	 instruction on the RS/6000) that can't be used in the general
! 	 context we want it for.  If the first operand is an arithmetic
! 	 operation and the second is a MATCH_OPERNAND, show we have
! 	 conditional arithmetic.  */
  
        if (recog_p && non_pc_set_src
  	  && GET_CODE (XEXP (part, 1)) == MATCH_OPERAND
  	  && GET_CODE (XEXP (part, 2)) == MATCH_OPERAND)
  	have_cmove_flag = 1;
!       else if (recog_p && non_pc_set_src
! 	       && (GET_RTX_CLASS (GET_CODE (XEXP (part, 1))) == '1'
! 		   || GET_RTX_CLASS (GET_CODE (XEXP (part, 1))) == '2'
! 		   || GET_RTX_CLASS (GET_CODE (XEXP (part, 1))) == 'c')
! 	       && GET_CODE (XEXP (XEXP (part, 1), 0)) == MATCH_OPERAND
! 	       && GET_CODE (XEXP (part, 2)) == MATCH_OPERAND)
! 	have_cond_arith_flag = 1;
        break;
  
      case REG: case CONST_INT: case SYMBOL_REF:
--- 131,147 ----
  	 two arms of the IF_THEN_ELSE are both MATCH_OPERAND.  Otherwise,
  	 we have some specific IF_THEN_ELSE construct (like the doz
  	 instruction on the RS/6000) that can't be used in the general
! 	 context we want it for.  */
  
        if (recog_p && non_pc_set_src
  	  && GET_CODE (XEXP (part, 1)) == MATCH_OPERAND
  	  && GET_CODE (XEXP (part, 2)) == MATCH_OPERAND)
  	have_cmove_flag = 1;
!       break;
! 
!     case COND_EXEC:
!       if (recog_p)
! 	have_cond_exec_flag = 1;
        break;
  
      case REG: case CONST_INT: case SYMBOL_REF:
*************** from the machine description file `md'. 
*** 341,348 ****
  
    /* This is conditionally defined, in case the user writes code which emits
       more splits than we can readily see (and knows s/he does it).  */
!   printf ("#ifndef MAX_INSNS_PER_SPLIT\n#define MAX_INSNS_PER_SPLIT %d\n#endif\n",
! 	  max_insns_per_split);
  
    if (have_cc0_flag)
      printf ("#define HAVE_cc0\n");
--- 337,345 ----
  
    /* This is conditionally defined, in case the user writes code which emits
       more splits than we can readily see (and knows s/he does it).  */
!   printf ("#ifndef MAX_INSNS_PER_SPLIT\n");
!   printf ("#define MAX_INSNS_PER_SPLIT %d\n", max_insns_per_split);
!   printf ("#endif\n");
  
    if (have_cc0_flag)
      printf ("#define HAVE_cc0\n");
*************** from the machine description file `md'. 
*** 350,360 ****
    if (have_cmove_flag)
      printf ("#define HAVE_conditional_move\n");
  
! #if 0
!   /* Disabled.  See the discussion in jump.c.  */
!   if (have_cond_arith_flag)
!     printf ("#define HAVE_conditional_arithmetic\n");
! #endif
  
    if (have_lo_sum_flag)
      printf ("#define HAVE_lo_sum\n");
--- 347,354 ----
    if (have_cmove_flag)
      printf ("#define HAVE_conditional_move\n");
  
!   if (have_cond_exec_flag)
!     printf ("#define HAVE_conditional_execution\n");
  
    if (have_lo_sum_flag)
      printf ("#define HAVE_lo_sum\n");
Index: haifa-sched.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/haifa-sched.c,v
retrieving revision 1.146
diff -c -p -d -r1.146 haifa-sched.c
*** haifa-sched.c	2000/03/05 22:35:27	1.146
--- haifa-sched.c	2000/04/07 08:56:54
*************** haifa_classify_insn (insn)
*** 2588,2593 ****
--- 2588,2594 ----
  		WORST_CLASS (tmp_class,
  			   may_trap_exp (SET_SRC (XVECEXP (pat, 0, i)), 0));
  	      break;
+ 	    case COND_EXEC:
  	    case TRAP_IF:
  	      tmp_class = TRAP_RISKY;
  	      break;
*************** haifa_classify_insn (insn)
*** 2617,2622 ****
--- 2618,2624 ----
  	    WORST_CLASS (tmp_class,
  			 may_trap_exp (SET_SRC (pat), 0));
  	  break;
+ 	case COND_EXEC:
  	case TRAP_IF:
  	  tmp_class = TRAP_RISKY;
  	  break;
*************** sched_analyze_insn (deps, x, insn, loop_
*** 3649,3654 ****
--- 3651,3665 ----
    int maxreg = max_reg_num ();
    int i;
  
+   if (code == COND_EXEC)
+     {
+       sched_analyze_2 (deps, COND_EXEC_TEST (x), insn);
+ 
+       /* ??? Should be recording conditions so we reduce the number of
+ 	 false dependancies.  */
+       x = COND_EXEC_CODE (x);
+       code = GET_CODE (x);
+     }
    if (code == SET || code == CLOBBER)
      sched_analyze_1 (deps, x, insn);
    else if (code == PARALLEL)
*************** sched_analyze_insn (deps, x, insn, loop_
*** 3656,3666 ****
        register int i;
        for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
  	{
! 	  code = GET_CODE (XVECEXP (x, 0, i));
  	  if (code == SET || code == CLOBBER)
! 	    sched_analyze_1 (deps, XVECEXP (x, 0, i), insn);
  	  else
! 	    sched_analyze_2 (deps, XVECEXP (x, 0, i), insn);
  	}
      }
    else
--- 3667,3685 ----
        register int i;
        for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
  	{
! 	  rtx sub = XVECEXP (x, 0, i);
! 	  code = GET_CODE (sub);
! 
! 	  if (code == COND_EXEC)
! 	    {
! 	      sched_analyze_2 (deps, COND_EXEC_TEST (sub), insn);
! 	      sub = COND_EXEC_CODE (sub);
! 	      code = GET_CODE (sub);
! 	    }
  	  if (code == SET || code == CLOBBER)
! 	    sched_analyze_1 (deps, sub, insn);
  	  else
! 	    sched_analyze_2 (deps, sub, insn);
  	}
      }
    else
*************** print_pattern (buf, x, verbose)
*** 5312,5317 ****
--- 5331,5341 ----
      case USE:
        print_value (t1, XEXP (x, 0), verbose);
        sprintf (buf, "use %s", t1);
+       break;
+     case COND_EXEC:
+       print_value (t1, COND_EXEC_CODE (x), verbose);
+       print_value (t2, COND_EXEC_TEST (x), verbose);
+       sprintf (buf, "cond_exec %s %s", t1, t2);
        break;
      case PARALLEL:
        {
Index: reload.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/reload.c,v
retrieving revision 1.102
diff -c -p -d -r1.102 reload.c
*** reload.c	2000/03/25 18:34:03	1.102
--- reload.c	2000/04/07 08:56:54
*************** find_equiv_reg (goal, insn, class, other
*** 6190,6195 ****
--- 6190,6197 ----
  	     If GOAL is a memory ref and its address is not constant,
  	     and this insn P changes a register used in GOAL, return 0.  */
  
+ 	  if (GET_CODE (pat) == COND_EXEC)
+ 	    pat = COND_EXEC_CODE (pat);
  	  if (GET_CODE (pat) == SET || GET_CODE (pat) == CLOBBER)
  	    {
  	      register rtx dest = SET_DEST (pat);
*************** find_equiv_reg (goal, insn, class, other
*** 6232,6237 ****
--- 6234,6241 ----
  	      for (i = XVECLEN (pat, 0) - 1; i >= 0; i--)
  		{
  		  register rtx v1 = XVECEXP (pat, 0, i);
+ 		  if (GET_CODE (v1) == COND_EXEC)
+ 		    v1 = COND_EXEC_CODE (v1);
  		  if (GET_CODE (v1) == SET || GET_CODE (v1) == CLOBBER)
  		    {
  		      register rtx dest = SET_DEST (v1);
Index: rtl.def
===================================================================
RCS file: /cvs/gcc/egcs/gcc/rtl.def,v
retrieving revision 1.31
diff -c -p -d -r1.31 rtl.def
*** rtl.def	2000/03/17 22:40:44	1.31
--- rtl.def	2000/04/07 08:56:54
*************** DEF_RTL_EXPR(CALL_PLACEHOLDER, "call_pla
*** 900,905 ****
--- 900,912 ----
     of canonical RTL.  It is, however, easier to manipulate this way.  */
  DEF_RTL_EXPR(PHI, "phi", "E", 'x')
  
+ /* Conditionally execute code.
+    Operand 0 is the condition that if true, the code is executed.
+    Operand 1 is the code to be executed (typically a SET). 
+ 
+    Semantics are that there are no side effects if the condition
+    is false.  */
+ DEF_RTL_EXPR(COND_EXEC, "cond_exec", "ee", 'x')
  
  /*
  Local variables:
Index: rtl.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/rtl.h,v
retrieving revision 1.185
diff -c -p -d -r1.185 rtl.h
*** rtl.h	2000/04/06 21:22:48	1.185
--- rtl.h	2000/04/07 08:56:54
*************** extern const char * const note_insn_name
*** 807,812 ****
--- 807,818 ----
  #define TRAP_CONDITION(RTX) XCEXP(RTX, 0, TRAP_IF)
  #define TRAP_CODE(RTX) XCEXP(RTX, 1, TRAP_IF)
  
+ /* For a COND_EXEC rtx, COND_EXEC_TEST is the condition to base
+    conditionally executing the code on, COND_EXEC_CODE is the code
+    to execute if the condition is true.  */
+ #define COND_EXEC_TEST(RTX) XCEXP(RTX, 0, COND_EXEC)
+ #define COND_EXEC_CODE(RTX) XCEXP(RTX, 1, COND_EXEC)
+ 
  /* 1 in a SYMBOL_REF if it addresses this function's constants pool.  */
  #define CONSTANT_POOL_ADDRESS_P(RTX) ((RTX)->unchanging)
  
Index: rtlanal.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/rtlanal.c,v
retrieving revision 1.56
diff -c -p -d -r1.56 rtlanal.c
*** rtlanal.c	2000/03/25 18:34:04	1.56
--- rtlanal.c	2000/04/07 08:56:54
*************** reg_referenced_p (x, body)
*** 429,434 ****
--- 429,439 ----
  	  return 1;
        return 0;
  
+     case COND_EXEC:
+       if (reg_overlap_mentioned_p (x, COND_EXEC_TEST (body)))
+ 	return 1;
+       return reg_referenced_p (x, COND_EXEC_CODE (body));
+ 
      default:
        return 0;
      }
*************** reg_overlap_mentioned_p (x, in)
*** 949,1000 ****
    /* If either argument is a constant, then modifying X can not affect IN.  */
    if (CONSTANT_P (x) || CONSTANT_P (in))
      return 0;
!   else if (GET_CODE (x) == SUBREG)
      {
        regno = REGNO (SUBREG_REG (x));
        if (regno < FIRST_PSEUDO_REGISTER)
  	regno += SUBREG_WORD (x);
!     }
!   else if (GET_CODE (x) == REG)
!     regno = REGNO (x);
!   else if (GET_CODE (x) == MEM)
!     {
!       const char *fmt;
!       int i;
  
!       if (GET_CODE (in) == MEM)
! 	return 1;
  
!       fmt = GET_RTX_FORMAT (GET_CODE (in));
  
!       for (i = GET_RTX_LENGTH (GET_CODE (in)) - 1; i >= 0; i--)
! 	if (fmt[i] == 'e' && reg_overlap_mentioned_p (x, XEXP (in, i)))
  	  return 1;
  
!       return 0;
!     }
!   else if (GET_CODE (x) == SCRATCH || GET_CODE (x) == PC
! 	   || GET_CODE (x) == CC0)
!     return reg_mentioned_p (x, in);
!   else if (GET_CODE (x) == PARALLEL
! 	   && GET_MODE (x) == BLKmode)
!     {
!       register int i;
  
!       /* If any register in here refers to it
! 	 we return true.  */
!       for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
! 	if (reg_overlap_mentioned_p (SET_DEST (XVECEXP (x, 0, i)), in))
! 	  return 1;
!       return 0;
!     }
!   else
!     abort ();
  
!   endregno = regno + (regno < FIRST_PSEUDO_REGISTER
! 		      ? HARD_REGNO_NREGS (regno, GET_MODE (x)) : 1);
  
!   return refers_to_regno_p (regno, endregno, in, NULL_PTR);
  }
  
  /* Used for communications between the next few functions.  */
--- 954,1014 ----
    /* If either argument is a constant, then modifying X can not affect IN.  */
    if (CONSTANT_P (x) || CONSTANT_P (in))
      return 0;
! 
!   switch (GET_CODE (x))
      {
+     case SUBREG:
        regno = REGNO (SUBREG_REG (x));
        if (regno < FIRST_PSEUDO_REGISTER)
  	regno += SUBREG_WORD (x);
!       goto do_reg;
  
!     case REG:
!       regno = REGNO (x);
!     do_reg:
!       endregno = regno + (regno < FIRST_PSEUDO_REGISTER
! 			  ? HARD_REGNO_NREGS (regno, GET_MODE (x)) : 1);
!       return refers_to_regno_p (regno, endregno, in, NULL_PTR);
  
!     case MEM:
!       {
! 	const char *fmt;
! 	int i;
  
! 	if (GET_CODE (in) == MEM)
  	  return 1;
  
! 	fmt = GET_RTX_FORMAT (GET_CODE (in));
! 	for (i = GET_RTX_LENGTH (GET_CODE (in)) - 1; i >= 0; i--)
! 	  if (fmt[i] == 'e' && reg_overlap_mentioned_p (x, XEXP (in, i)))
! 	    return 1;
  
! 	return 0;
!       }
  
!     case SCRATCH:
!     case PC:
!     case CC0:
!       return reg_mentioned_p (x, in);
  
!     case PARALLEL:
!       if (GET_MODE (x) == BLKmode)
! 	{
! 	  register int i;
! 
! 	  /* If any register in here refers to it we return true.  */
! 	  for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
! 	    if (reg_overlap_mentioned_p (SET_DEST (XVECEXP (x, 0, i)), in))
! 	      return 1;
! 	  return 0;
! 	}
!       break;
! 
!     default:
!       break;
!     }
! 
!   abort ();
  }
  
  /* Used for communications between the next few functions.  */
*************** note_stores (x, fun, data)
*** 1108,1114 ****
       void (*fun) PARAMS ((rtx, rtx, void *));
       void *data;
  {
!   if ((GET_CODE (x) == SET || GET_CODE (x) == CLOBBER))
      {
        register rtx dest = SET_DEST (x);
        while ((GET_CODE (dest) == SUBREG
--- 1122,1130 ----
       void (*fun) PARAMS ((rtx, rtx, void *));
       void *data;
  {
!   if (GET_CODE (x) == COND_EXEC)
!     x = COND_EXEC_CODE (x);
!   if (GET_CODE (x) == SET || GET_CODE (x) == CLOBBER)
      {
        register rtx dest = SET_DEST (x);
        while ((GET_CODE (dest) == SUBREG
*************** note_stores (x, fun, data)
*** 1135,1140 ****
--- 1151,1158 ----
        for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
  	{
  	  register rtx y = XVECEXP (x, 0, i);
+ 	  if (GET_CODE (y) == COND_EXEC)
+ 	    y = COND_EXEC_CODE (y);
  	  if (GET_CODE (y) == SET || GET_CODE (y) == CLOBBER)
  	    {
  	      register rtx dest = SET_DEST (y);
*************** dead_or_set_regno_p (insn, test_regno)
*** 1213,1219 ****
       unsigned int test_regno;
  {
    unsigned int regno, endregno;
!   rtx link;
  
    /* See if there is a death note for something that includes
       TEST_REGNO.  */
--- 1231,1237 ----
       unsigned int test_regno;
  {
    unsigned int regno, endregno;
!   rtx link, pattern;
  
    /* See if there is a death note for something that includes
       TEST_REGNO.  */
*************** dead_or_set_regno_p (insn, test_regno)
*** 1236,1242 ****
        && find_regno_fusage (insn, CLOBBER, test_regno))
      return 1;
  
!   if (GET_CODE (PATTERN (insn)) == SET)
      {
        rtx dest = SET_DEST (PATTERN (insn));
   
--- 1254,1265 ----
        && find_regno_fusage (insn, CLOBBER, test_regno))
      return 1;
  
!   pattern = PATTERN (insn);
! 
!   if (GET_CODE (pattern) == COND_EXEC)
!     pattern = COND_EXEC_CODE (pattern);
! 
!   if (GET_CODE (pattern) == SET)
      {
        rtx dest = SET_DEST (PATTERN (insn));
   
*************** dead_or_set_regno_p (insn, test_regno)
*** 1259,1271 ****
  
        return (test_regno >= regno && test_regno < endregno);
      }
!   else if (GET_CODE (PATTERN (insn)) == PARALLEL)
      {
        register int i;
  
!       for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
  	{
! 	  rtx body = XVECEXP (PATTERN (insn), 0, i);
  
  	  if (GET_CODE (body) == SET || GET_CODE (body) == CLOBBER)
  	    {
--- 1282,1297 ----
  
        return (test_regno >= regno && test_regno < endregno);
      }
!   else if (GET_CODE (pattern) == PARALLEL)
      {
        register int i;
  
!       for (i = XVECLEN (pattern, 0) - 1; i >= 0; i--)
  	{
! 	  rtx body = XVECEXP (pattern, 0, i);
! 
! 	  if (GET_CODE (body) == COND_EXEC)
! 	    body = COND_EXEC_CODE (body);
  
  	  if (GET_CODE (body) == SET || GET_CODE (body) == CLOBBER)
  	    {
Index: tm.texi
===================================================================
RCS file: /cvs/gcc/egcs/gcc/tm.texi,v
retrieving revision 1.121
diff -c -p -d -r1.121 tm.texi
*** tm.texi	2000/03/29 13:10:41	1.121
--- tm.texi	2000/04/07 08:56:55
*************** Note that this functionality is part of 
*** 7942,7945 ****
--- 7942,7953 ----
  Defining @code{TARGET_HAS_F_SETLKW} will enable the test coverage code
  to use file locking when exiting a program, which avoids race conditions
  if the program has forked.
+ 
+ @findex MAX_CONDITIONAL_EXECUTE
+ @item MAX_CONDITIONAL_EXECUTE
+ 
+ A C expression for the maximum number of instructions to execute via
+ conditional execution instructions instead of a branch.  A value of
+ @code{BRANCH_COST}+1 is the default if the machine does not use cc0, and
+ 1 if it does use cc0.
  @end table

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