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]
Other format: [Raw text]

[tree-ssa] another simplification reorg patch


This patch changes the simplifier in a couple of ways:

1) We will now try to simplify everything, and not check beforehand whether
   something is adequately simple.  My plan is to change the predicates so
   they only check the top-level form of an expression, not walk through
   the whole expression to see if it is simple; once we've simplified an
   expression, we know it's simple, we just don't know if it is of a
   suitable form, or if we need to copy it into a temp.
2) The main simplification code is now a loop; if a simplifier replaces
   *expr_p with a different node, we simplify the new one, too.  This makes
   it easier to simplify something like &* by just stripping off the
   ADDR_EXPR and INDIRECT_REF and starting again.

As a result of #1 more builtins are being exposed to simplification, so I
needed to add more codes to is_simplifiable_builtin.

c99-array-lval-3.c was failing because the NON_LVALUE_EXPR caused us to try
to copy an array into a temp.  I've fixed this by not wrapping the array
with a NON_LVALUE_EXPR in C99 mode; this seems reasonable to me.

Tested i686-pc-linux-gnu.

2002-08-12  Jason Merrill  <jason@redhat.com>

	* c-typeck.c (build_component_ref): Don't add a NON_LVALUE_EXPR
	in C99 mode.

	* c-simplify.c (simplify_expr): Always simplify.  Loop if *expr_p
	changed.
	(simplify_addr_expr): Just replace *expr_p if we have a '&*'.
	* tree-simple.c (is_simplifiable_builtin): Add more tree codes.

*** c-simplify.c.~1~	Sun Aug 11 23:14:34 2002
--- c-simplify.c	Sun Aug 11 23:19:24 2002
*************** simplify_expr (expr_p, pre_p, post_p, si
*** 997,1188 ****
       fallback_t fallback;
  {
    tree tmp;
    tree internal_post = NULL_TREE;
!   int done;
  
!   if (pre_p == NULL)
!     {
!       /* Temporary kludge: If pre_p is null, this is a statement.  Hand off
! 	 to the C-specific code.  Soon we will have a l-i notion of
! 	 statements.  */
!       return (*lang_hooks.simplify_expr) (expr_p, pre_p, post_p);
!     }
! 
! #if defined CHECKING
!   if (simple_test_f == NULL)
!     abort ();
! #endif
! 
!   if ((*simple_test_f) (*expr_p))
      return 1;
  
!   /* Set up our internal postqueue if needed.  */
    if (post_p == NULL)
      post_p = &internal_post;
  
!   /* First do any language-specific simplification.  */
!   done = (*lang_hooks.simplify_expr) (expr_p, pre_p, post_p);
! 
!   if (done)
!     /* The frontend completely simplified this node.  */;
!   else switch (TREE_CODE (*expr_p))
      {
!       /* First deal with the special cases.  */
! 
!     case POSTINCREMENT_EXPR:
!     case POSTDECREMENT_EXPR:
!     case PREINCREMENT_EXPR:
!     case PREDECREMENT_EXPR:
!       simplify_self_mod_expr (expr_p, pre_p, post_p);
!       break;
! 
!     case ARRAY_REF:
!       simplify_array_ref (expr_p, pre_p, post_p);
!       break;
! 
!     case COMPONENT_REF:
!       simplify_component_ref (expr_p, pre_p, post_p);
!       break;
!       
!     case COND_EXPR:
!       simplify_cond_expr (expr_p, pre_p);
!       break;
! 
!     case CALL_EXPR:
!       simplify_call_expr (expr_p, pre_p, post_p);
!       break;
! 
!     case TREE_LIST:
!       simplify_tree_list (expr_p, pre_p, post_p);
!       break;
! 
!     case COMPOUND_EXPR:
!       simplify_compound_expr (expr_p, pre_p, post_p);
!       break;
! 
!     case REALPART_EXPR:
!     case IMAGPART_EXPR:
!       return simplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
! 		            simple_test_f, fallback);
! 
!     case MODIFY_EXPR:
!     case INIT_EXPR:
!       simplify_modify_expr (expr_p, pre_p, post_p);
!       break;
! 
!     case TRUTH_ANDIF_EXPR:
!     case TRUTH_ORIF_EXPR:
!       simplify_boolean_expr (expr_p, pre_p);
!       break;
  
!     case TRUTH_NOT_EXPR:
!       tmp = TREE_OPERAND (*expr_p, 0);
!       simplify_expr (&tmp, pre_p, post_p, is_simple_id, fb_rvalue);
!       *expr_p = build (EQ_EXPR, TREE_TYPE (*expr_p), tmp, integer_zero_node);
!       break;
  
!     case ADDR_EXPR:
!       simplify_addr_expr (expr_p, pre_p, post_p);
!       break;
! 
!     /* va_arg expressions should also be left alone to avoid confusing the
!        vararg code.  FIXME: Is this really necessary?  */
!     case VA_ARG_EXPR:
!       walk_tree (expr_p, mark_not_simple_r, NULL, NULL);
!       break;
  
!     case NOP_EXPR:
!     case CONVERT_EXPR:
!     case FIX_TRUNC_EXPR:
!     case FIX_CEIL_EXPR:
!     case FIX_FLOOR_EXPR:
!     case FIX_ROUND_EXPR:
!       simplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
! 	             is_simple_varname, fb_rvalue);
!       break;
! 
!     case INDIRECT_REF:
!       simplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p, is_simple_id,
! 	             fb_rvalue);
!       break;
! 
!     case NEGATE_EXPR:
!       simplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p, is_simple_val,
! 	             fb_rvalue);
!       break;
! 
!     /* Constants need not be simplified.  */
!     case INTEGER_CST:
!     case REAL_CST:
!     case STRING_CST:
!     case COMPLEX_CST:
!       break;
! 
!     case CONSTRUCTOR:
!       simplify_constructor (*expr_p, pre_p, post_p);
!       break;
! 
!     /* The following are special cases that are not handled by the original
!        SIMPLE grammar.  */
! 
!     /* SAVE_EXPR nodes are converted into a SIMPLE identifier and
!        eliminated.  */
!     case SAVE_EXPR:
!       simplify_save_expr (expr_p, pre_p);
!       break;
! 
!     case EXPR_WITH_FILE_LOCATION:
!       simplify_expr_wfl (expr_p, pre_p, post_p, simple_test_f);
!       break;
! 
!     /* FIXME: This breaks stage2.  I still haven't figured out why.  When
! 	      fixing remember to undo a similar change in
! 	      is_simple_unary_expr.  */
!     case BIT_FIELD_REF:
  #if 0
!       simplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p, is_simple_id);
!       simplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p, is_simple_val);
!       simplify_expr (&TREE_OPERAND (*expr_p, 2), pre_p, post_p, is_simple_val);
  #else
!       walk_tree (expr_p, mark_not_simple_r, NULL, NULL);
  #endif
!       break;
  
!     case NON_LVALUE_EXPR:
!       simplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p, simple_test_f,
! 	             fb_rvalue);
!       break;
! 
!     /* If *EXPR_P does not need to be special-cased, handle it according to
!        its class.  */
!     default:
!       {
! 	if (TREE_CODE_CLASS (TREE_CODE (*expr_p)) == '1')
  	  {
! 	    simplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
! 	                   is_simple_val, fb_rvalue);
  	  }
! 	else if (TREE_CODE_CLASS (TREE_CODE (*expr_p)) == '2'
! 	         || TREE_CODE_CLASS (TREE_CODE (*expr_p)) == '<'
! 		 || TREE_CODE (*expr_p) == TRUTH_AND_EXPR
! 		 || TREE_CODE (*expr_p) == TRUTH_OR_EXPR
! 		 || TREE_CODE (*expr_p) == TRUTH_XOR_EXPR)
! 	  {
! 	    simplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
! 			   is_simple_val, fb_rvalue);
  
! 	    simplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p,
! 			   is_simple_val, fb_rvalue);
! 	  }
! 	else
! 	  {
! 	    fprintf (stderr, "unhandled expression in simplify_expr ():\n");
! 	    debug_tree (*expr_p);
! 	    abort ();
! 	  }
!       }
      }
  
    /* If it's sufficiently simple already, we're done.  Unless we are
       handling some post-effects internally; if that's the case, we need to
       copy into a temp before adding the post-effects to the tree.  */
--- 997,1204 ----
       fallback_t fallback;
  {
    tree tmp;
+   tree internal_pre = NULL_TREE;
    tree internal_post = NULL_TREE;
!   tree save_expr;
!   int is_statement = (pre_p == NULL);
  
!   if (*expr_p == NULL_TREE)
      return 1;
  
!   /* Set up our internal queues if needed.  */
!   if (pre_p == NULL)
!     pre_p = &internal_pre;
    if (post_p == NULL)
      post_p = &internal_post;
  
!   /* Loop over the specific simplifiers until the toplevel node remains the
!      same.  */
!   do
      {
!       /* First do any language-specific simplification.  */
!       (*lang_hooks.simplify_expr) (expr_p, pre_p, post_p);
  
!       /* Then remember the expr.  */
!       save_expr = *expr_p;
  
!       switch (TREE_CODE (*expr_p))
! 	{
! 	  /* First deal with the special cases.  */
  
! 	case POSTINCREMENT_EXPR:
! 	case POSTDECREMENT_EXPR:
! 	case PREINCREMENT_EXPR:
! 	case PREDECREMENT_EXPR:
! 	  simplify_self_mod_expr (expr_p, pre_p, post_p);
! 	  break;
! 
! 	case ARRAY_REF:
! 	  simplify_array_ref (expr_p, pre_p, post_p);
! 	  break;
! 
! 	case COMPONENT_REF:
! 	  simplify_component_ref (expr_p, pre_p, post_p);
! 	  break;
!       
! 	case COND_EXPR:
! 	  simplify_cond_expr (expr_p, pre_p);
! 	  break;
! 
! 	case CALL_EXPR:
! 	  simplify_call_expr (expr_p, pre_p, post_p);
! 	  break;
! 
! 	case TREE_LIST:
! 	  simplify_tree_list (expr_p, pre_p, post_p);
! 	  break;
! 
! 	case COMPOUND_EXPR:
! 	  simplify_compound_expr (expr_p, pre_p, post_p);
! 	  break;
! 
! 	case REALPART_EXPR:
! 	case IMAGPART_EXPR:
! 	  return simplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
! 				simple_test_f, fallback);
! 
! 	case MODIFY_EXPR:
! 	case INIT_EXPR:
! 	  simplify_modify_expr (expr_p, pre_p, post_p);
! 	  break;
! 
! 	case TRUTH_ANDIF_EXPR:
! 	case TRUTH_ORIF_EXPR:
! 	  simplify_boolean_expr (expr_p, pre_p);
! 	  break;
! 
! 	case TRUTH_NOT_EXPR:
! 	  tmp = TREE_OPERAND (*expr_p, 0);
! 	  simplify_expr (&tmp, pre_p, post_p, is_simple_id, fb_rvalue);
! 	  *expr_p = build (EQ_EXPR, TREE_TYPE (*expr_p), tmp, integer_zero_node);
! 	  break;
! 
! 	case ADDR_EXPR:
! 	  simplify_addr_expr (expr_p, pre_p, post_p);
! 	  break;
! 
! 	  /* va_arg expressions should also be left alone to avoid confusing the
! 	     vararg code.  FIXME: Is this really necessary?  */
! 	case VA_ARG_EXPR:
! 	  walk_tree (expr_p, mark_not_simple_r, NULL, NULL);
! 	  break;
! 
! 	case NOP_EXPR:
! 	  if (VOID_TYPE_P (TREE_TYPE (*expr_p)))
! 	    {
! 	      /* Just strip a conversion to void and try again.  */
! 	      *expr_p = TREE_OPERAND (*expr_p, 0);
! 	      break;
! 	    }
! 	case CONVERT_EXPR:
! 	case FIX_TRUNC_EXPR:
! 	case FIX_CEIL_EXPR:
! 	case FIX_FLOOR_EXPR:
! 	case FIX_ROUND_EXPR:
! 	  simplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
! 			 is_simple_varname, fb_rvalue);
! 	  break;
! 
! 	case INDIRECT_REF:
! 	  simplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p, is_simple_id,
! 			 fb_rvalue);
! 	  break;
! 
! 	case NEGATE_EXPR:
! 	  simplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p, is_simple_val,
! 			 fb_rvalue);
! 	  break;
! 
! 	  /* Constants need not be simplified.  */
! 	case INTEGER_CST:
! 	case REAL_CST:
! 	case STRING_CST:
! 	case COMPLEX_CST:
! 	  break;
! 
! 	case CONSTRUCTOR:
! 	  simplify_constructor (*expr_p, pre_p, post_p);
! 	  break;
! 
! 	  /* The following are special cases that are not handled by the original
! 	     SIMPLE grammar.  */
! 
! 	  /* SAVE_EXPR nodes are converted into a SIMPLE identifier and
! 	     eliminated.  */
! 	case SAVE_EXPR:
! 	  simplify_save_expr (expr_p, pre_p);
! 	  break;
! 
! 	case EXPR_WITH_FILE_LOCATION:
! 	  simplify_expr_wfl (expr_p, pre_p, post_p, simple_test_f);
! 	  break;
! 
! 	  /* FIXME: This breaks stage2.  I still haven't figured out why.  When
! 	     fixing remember to undo a similar change in
! 	     is_simple_unary_expr.  */
! 	case BIT_FIELD_REF:
  #if 0
! 	  simplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p, is_simple_id);
! 	  simplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p, is_simple_val);
! 	  simplify_expr (&TREE_OPERAND (*expr_p, 2), pre_p, post_p, is_simple_val);
  #else
! 	  walk_tree (expr_p, mark_not_simple_r, NULL, NULL);
  #endif
! 	  break;
  
! 	case NON_LVALUE_EXPR:
! 	  simplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p, simple_test_f,
! 			 fb_rvalue);
! 	  break;
! 
! 	  /* If *EXPR_P does not need to be special-cased, handle it according to
! 	     its class.  */
! 	default:
  	  {
! 	    if (TREE_CODE_CLASS (TREE_CODE (*expr_p)) == '1')
! 	      {
! 		simplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
! 			       is_simple_val, fb_rvalue);
! 	      }
! 	    else if (TREE_CODE_CLASS (TREE_CODE (*expr_p)) == '2'
! 		     || TREE_CODE_CLASS (TREE_CODE (*expr_p)) == '<'
! 		     || TREE_CODE (*expr_p) == TRUTH_AND_EXPR
! 		     || TREE_CODE (*expr_p) == TRUTH_OR_EXPR
! 		     || TREE_CODE (*expr_p) == TRUTH_XOR_EXPR)
! 	      {
! 		simplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
! 			       is_simple_val, fb_rvalue);
! 
! 		simplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p,
! 			       is_simple_val, fb_rvalue);
! 	      }
  	  }
! 	}
!     }
!   /* If we replaced *expr_p, simplify again.  */
!   while (*expr_p != save_expr);
  
!   /* If we are simplifying at the statement level, we're done.  Tack
!      everything together and replace the original statement with the
!      simplified form.  */
!   if (is_statement)
!     {
! #if 0
!       /* Soon.  */
!       add_tree (*expr_p, pre_p);
!       add_tree (internal_post, pre_p);
!       *expr_p = rationalize_compound_expr (internal_pre);
! #endif
!       return 1;
      }
  
+   /* Otherwise we're simplifying a subexpression, so the resulting value is
+      interesting.  */
+ 
    /* If it's sufficiently simple already, we're done.  Unless we are
       handling some post-effects internally; if that's the case, we need to
       copy into a temp before adding the post-effects to the tree.  */
*************** simplify_addr_expr (expr_p, pre_p, post_
*** 2025,2040 ****
      simplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p, 
  		   is_simple_addr_expr_arg, fb_lvalue);
    else
!     {
!       /* Fold &*EXPR into EXPR and simplify EXPR into a legal argument for
! 	 ADDR_EXPR.  Notice that we need to request an rvalue because EXPR is
! 	 already the lvalue that we were looking for originally.
! 
!          ??? is_simple_addr_expr_arg is wrong here.  we really want to tell
!          simplify_expr to start over.  */
!       *expr_p = TREE_OPERAND (TREE_OPERAND (*expr_p, 0), 0);
!       simplify_expr (expr_p, pre_p, post_p, is_simple_addr_expr_arg, fb_rvalue);
!     }
  }
  
  
--- 2041,2048 ----
      simplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p, 
  		   is_simple_addr_expr_arg, fb_lvalue);
    else
!     /* Fold &*EXPR into EXPR.  simplify_expr will re-simplify EXPR.  */
!     *expr_p = TREE_OPERAND (TREE_OPERAND (*expr_p, 0), 0);
  }
  
  
*** c-typeck.c.~1~	Fri Aug  2 13:24:24 2002
--- c-typeck.c	Sun Aug 11 23:35:30 2002
*************** build_component_ref (datum, component)
*** 1108,1114 ****
        {
  	tree value = build_component_ref (TREE_OPERAND (datum, 1), component);
  	return build (COMPOUND_EXPR, TREE_TYPE (value),
! 		      TREE_OPERAND (datum, 0), pedantic_non_lvalue (value));
        }
      default:
        break;
--- 1108,1115 ----
        {
  	tree value = build_component_ref (TREE_OPERAND (datum, 1), component);
  	return build (COMPOUND_EXPR, TREE_TYPE (value),
! 		      TREE_OPERAND (datum, 0),
! 		      flag_isoc99 ? value : pedantic_non_lvalue (value));
        }
      default:
        break;
*** tree-simple.c.~1~	Sun Aug 11 23:14:34 2002
--- tree-simple.c	Sun Aug 11 23:10:00 2002
*************** Boston, MA 02111-1307, USA.  */
*** 192,197 ****
--- 192,202 ----
  
       ----------------------------------------------------------------------  */
  
+ /* FIXME all of the is_simple_* predicates should be changed to only test
+    for appropriate top-level structures; we can safely assume that after
+    simplification, a PLUS_EXPR is a simple PLUS_EXPR, so the predicate only
+    needs to decide whether or not a PLUS_EXPR is suitable here.  */
+ 
  /* Returns nonzero if T is a simple CONSTRUCTOR:
  
       aggr_init: '{' vals '}'
*************** is_simplifiable_builtin (expr)
*** 859,869 ****
--- 864,880 ----
           constants.  Make sure we don't simplify something which will
           be folded by the builtin later.  */
  
+       /* FIXME this is a horrible kludge.  The builtin expanders should use
+ 	 dfa info to handle simplified arguments.  */
+ 
        /* foo (const char *, const char *, ...).  */
+     case BUILT_IN_STRCMP:
      case BUILT_IN_STRNCMP:
      case BUILT_IN_STRSPN:
      case BUILT_IN_STRSTR:
      case BUILT_IN_STRCSPN:
+     case BUILT_IN_STRPBRK:
+     case BUILT_IN_MEMCMP:
        t1 = TREE_VALUE (TREE_OPERAND (expr, 1));
        t2 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (expr, 1)));
        return !(string_constant (t1, &t3) || string_constant (t2, &t3));
*************** is_simplifiable_builtin (expr)
*** 873,879 ****
--- 884,892 ----
      case BUILT_IN_STRRCHR:
      case BUILT_IN_STRCHR:
      case BUILT_IN_INDEX:
+     case BUILT_IN_RINDEX:
      case BUILT_IN_FPUTS:
+     case BUILT_IN_PRINTF:
        t1 = TREE_VALUE (TREE_OPERAND (expr, 1));
        return !string_constant (t1, &t3);
  
*************** is_simplifiable_builtin (expr)
*** 882,887 ****
--- 895,901 ----
      case BUILT_IN_STRNCPY:
      case BUILT_IN_STRCAT:
      case BUILT_IN_STRNCAT:
+     case BUILT_IN_FPRINTF:
        t2 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (expr, 1)));
        return !string_constant (t2, &t3);
  

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