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]

[rfc cpp] extra checking for build(...)


For tree-ssa, I need to add an extra operand to CALL_EXPR.  This
means updating all places that we build CALL_EXPRs.  I think I
got them all, but the last one took quite a while to locate.

I was thinking that something like this would make it easier to
track this sort of thing down.  In time we could transition to 
the buildN functions, much like we've done with gen_rtx_fmt_ee,
but that's more churn than I'm willing to get myself into all at
once.

Is there a good way to get the preprocessor not to bitch about
the use of a gcc extension here?  #pragma extensions on/off?

I'll note that I don't know how to write this construct with
c99 __VA_ARGS__, since (1) apparently c99 requires __VA_ARGS__
to be *used*, and we don't in _buildC2 and (2) I don't think you
can handle zero arguments.


r~




Index: convert.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/convert.c,v
retrieving revision 1.35
diff -c -p -d -r1.35 convert.c
*** convert.c	1 Sep 2003 05:02:08 -0000	1.35
--- convert.c	15 Feb 2004 10:30:38 -0000
*************** convert_to_integer (tree type, tree expr
*** 523,530 ****
  		    return convert (type,
  				    fold (build (ex_form, typex,
  						 convert (typex, arg0),
! 						 convert (typex, arg1),
! 						 0)));
  		  }
  	      }
  	  }
--- 523,529 ----
  		    return convert (type,
  				    fold (build (ex_form, typex,
  						 convert (typex, arg0),
! 						 convert (typex, arg1))));
  		  }
  	      }
  	  }
Index: tree.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.c,v
retrieving revision 1.347
diff -c -p -d -r1.347 tree.c
*** tree.c	11 Feb 2004 01:55:28 -0000	1.347
--- tree.c	15 Feb 2004 10:30:38 -0000
*************** stabilize_reference_1 (tree e)
*** 2286,2412 ****
  
  /* Low-level constructors for expressions.  */
  
! /* Build an expression of code CODE, data type TYPE,
!    and operands as specified by the arguments ARG1 and following arguments.
!    Expressions and reference nodes can be created this way.
!    Constants, decls, types and misc nodes cannot be.  */
  
  tree
! build (enum tree_code code, tree tt, ...)
  {
    tree t;
-   int length;
-   int i;
-   int fro;
-   int constant;
-   va_list p;
-   tree node;
  
!   va_start (p, tt);
  
    t = make_node (code);
-   length = TREE_CODE_LENGTH (code);
    TREE_TYPE (t) = tt;
  
-   /* Below, we automatically set TREE_SIDE_EFFECTS and TREE_READONLY for the
-      result based on those same flags for the arguments.  But if the
-      arguments aren't really even `tree' expressions, we shouldn't be trying
-      to do this.  */
-   fro = first_rtl_op (code);
- 
-   /* Expressions without side effects may be constant if their
-      arguments are as well.  */
-   constant = (TREE_CODE_CLASS (code) == '<'
- 	      || TREE_CODE_CLASS (code) == '1'
- 	      || TREE_CODE_CLASS (code) == '2'
- 	      || TREE_CODE_CLASS (code) == 'c');
- 
-   if (length == 2)
-     {
-       /* This is equivalent to the loop below, but faster.  */
-       tree arg0 = va_arg (p, tree);
-       tree arg1 = va_arg (p, tree);
- 
-       TREE_OPERAND (t, 0) = arg0;
-       TREE_OPERAND (t, 1) = arg1;
-       TREE_READONLY (t) = 1;
-       if (arg0 && fro > 0)
- 	{
- 	  if (TREE_SIDE_EFFECTS (arg0))
- 	    TREE_SIDE_EFFECTS (t) = 1;
- 	  if (!TREE_READONLY (arg0))
- 	    TREE_READONLY (t) = 0;
- 	  if (!TREE_CONSTANT (arg0))
- 	    constant = 0;
- 	}
- 
-       if (arg1 && fro > 1)
- 	{
- 	  if (TREE_SIDE_EFFECTS (arg1))
- 	    TREE_SIDE_EFFECTS (t) = 1;
- 	  if (!TREE_READONLY (arg1))
- 	    TREE_READONLY (t) = 0;
- 	  if (!TREE_CONSTANT (arg1))
- 	    constant = 0;
- 	}
-     }
-   else if (length == 1)
-     {
-       tree arg0 = va_arg (p, tree);
- 
-       /* The only one-operand cases we handle here are those with side-effects.
- 	 Others are handled with build1.  So don't bother checked if the
- 	 arg has side-effects since we'll already have set it.
- 
- 	 ??? This really should use build1 too.  */
-       if (TREE_CODE_CLASS (code) != 's')
- 	abort ();
-       TREE_OPERAND (t, 0) = arg0;
-     }
-   else
-     {
-       for (i = 0; i < length; i++)
- 	{
- 	  tree operand = va_arg (p, tree);
- 
- 	  TREE_OPERAND (t, i) = operand;
- 	  if (operand && fro > i)
- 	    {
- 	      if (TREE_SIDE_EFFECTS (operand))
- 		TREE_SIDE_EFFECTS (t) = 1;
- 	      if (!TREE_CONSTANT (operand))
- 		constant = 0;
- 	    }
- 	}
-     }
-   va_end (p);
- 
-   TREE_CONSTANT (t) = constant;
-   
-   if (code == CALL_EXPR && !TREE_SIDE_EFFECTS (t))
-     {
-       /* Calls have side-effects, except those to const or
- 	 pure functions.  */
-       i = call_expr_flags (t);
-       if (!(i & (ECF_CONST | ECF_PURE)))
- 	TREE_SIDE_EFFECTS (t) = 1;
- 
-       /* And even those have side-effects if their arguments do.  */
-       else for (node = TREE_OPERAND (t, 1); node; node = TREE_CHAIN (node))
- 	if (TREE_SIDE_EFFECTS (TREE_VALUE (node)))
- 	  {
- 	    TREE_SIDE_EFFECTS (t) = 1;
- 	    break;
- 	  }
-     }
- 
    return t;
  }
  
- /* Same as above, but only builds for unary operators.
-    Saves lions share of calls to `build'; cuts down use
-    of varargs, which is expensive for RISC machines.  */
- 
  tree
  build1 (enum tree_code code, tree type, tree node)
  {
--- 2286,2316 ----
  
  /* Low-level constructors for expressions.  */
  
! /* Build an expression of code CODE, data type TYPE, and operands as
!    specified.  Expressions and reference nodes can be created this way.
!    Constants, decls, types and misc nodes cannot be.
! 
!    We define 5 non-variadic functions, from 0 to 4 arguments.  This is
!    enough for all extant tree codes.  These functions can be called 
!    directly (preferably!), but can also be obtained via GCC preprocessor
!    magic within the build macro.  */
  
  tree
! build0 (enum tree_code code, tree tt)
  {
    tree t;
  
! #ifdef ENABLE_CHECKING
!   if (TREE_CODE_LENGTH (code) != 0)
!     abort ();
! #endif
  
    t = make_node (code);
    TREE_TYPE (t) = tt;
  
    return t;
  }
  
  tree
  build1 (enum tree_code code, tree type, tree node)
  {
*************** build1 (enum tree_code code, tree type, 
*** 2435,2443 ****
  #endif
  
  #ifdef ENABLE_CHECKING
!   if (TREE_CODE_CLASS (code) == '2'
!       || TREE_CODE_CLASS (code) == '<'
!       || TREE_CODE_LENGTH (code) != 1)
      abort ();
  #endif /* ENABLE_CHECKING */
  
--- 2339,2345 ----
  #endif
  
  #ifdef ENABLE_CHECKING
!   if (TREE_CODE_LENGTH (code) != 1)
      abort ();
  #endif /* ENABLE_CHECKING */
  
*************** build1 (enum tree_code code, tree type, 
*** 2508,2513 ****
--- 2410,2600 ----
  	TREE_CONSTANT (t) = 1;
        break;
      }
+ 
+   return t;
+ }
+ 
+ #define PROCESS_ARG(N)			\
+   do {					\
+     TREE_OPERAND (t, N) = arg##N;	\
+     if (arg##N && fro > N)		\
+       {					\
+         if (TREE_SIDE_EFFECTS (arg##N))	\
+ 	  side_effects = 1;		\
+         if (!TREE_READONLY (arg##N))	\
+ 	  read_only = 0;		\
+         if (!TREE_CONSTANT (arg##N))	\
+ 	  constant = 0;			\
+       }					\
+   } while (0)
+ 
+ tree
+ build2 (enum tree_code code, tree tt, tree arg0, tree arg1)
+ {
+   bool constant, read_only, side_effects;
+   tree t;
+   int fro;
+ 
+ #ifdef ENABLE_CHECKING
+   if (TREE_CODE_LENGTH (code) != 2)
+     abort ();
+ #endif
+ 
+   t = make_node (code);
+   TREE_TYPE (t) = tt;
+ 
+   /* Below, we automatically set TREE_SIDE_EFFECTS and TREE_READONLY for the
+      result based on those same flags for the arguments.  But if the
+      arguments aren't really even `tree' expressions, we shouldn't be trying
+      to do this.  */
+   fro = first_rtl_op (code);
+ 
+   /* Expressions without side effects may be constant if their
+      arguments are as well.  */
+   constant = (TREE_CODE_CLASS (code) == '<'
+ 	      || TREE_CODE_CLASS (code) == '2');
+   read_only = 1;
+   side_effects = TREE_SIDE_EFFECTS (t);
+ 
+   PROCESS_ARG(0);
+   PROCESS_ARG(1);
+ 
+   if (code == CALL_EXPR && !side_effects)
+     {
+       tree node;
+       int i;
+ 
+       /* Calls have side-effects, except those to const or
+ 	 pure functions.  */
+       i = call_expr_flags (t);
+       if (!(i & (ECF_CONST | ECF_PURE)))
+ 	side_effects = 1;
+ 
+       /* And even those have side-effects if their arguments do.  */
+       else for (node = TREE_OPERAND (t, 1); node; node = TREE_CHAIN (node))
+ 	if (TREE_SIDE_EFFECTS (TREE_VALUE (node)))
+ 	  {
+ 	    side_effects = 1;
+ 	    break;
+ 	  }
+     }
+ 
+   TREE_READONLY (t) = read_only;
+   TREE_CONSTANT (t) = constant;
+   TREE_SIDE_EFFECTS (t) = side_effects;  
+ 
+   return t;
+ }
+ 
+ tree
+ build3 (enum tree_code code, tree tt, tree arg0, tree arg1, tree arg2)
+ {
+   bool constant, read_only, side_effects;
+   tree t;
+   int fro;
+ 
+   /* ??? Quite a lot of existing code passes one too many arguments to
+      CALL_EXPR.  Not going to fix them, because CALL_EXPR is about to
+      grow a new argument, so it would just mean changing them back.  */
+   if (code == CALL_EXPR)
+     {
+       if (arg2 != NULL_TREE)
+ 	abort ();
+       return build2 (code, tt, arg0, arg1);
+     }
+ 
+ #ifdef ENABLE_CHECKING
+   if (TREE_CODE_LENGTH (code) != 3)
+     abort ();
+ #endif
+ 
+   t = make_node (code);
+   TREE_TYPE (t) = tt;
+ 
+   fro = first_rtl_op (code);
+ 
+   side_effects = TREE_SIDE_EFFECTS (t);
+ 
+   PROCESS_ARG(0);
+   PROCESS_ARG(1);
+   PROCESS_ARG(2);
+ 
+   TREE_SIDE_EFFECTS (t) = side_effects;  
+ 
+   return t;
+ }
+ 
+ tree
+ build4 (enum tree_code code, tree tt, tree arg0, tree arg1,
+ 	tree arg2, tree arg3)
+ {
+   bool constant, read_only, side_effects;
+   tree t;
+   int fro;
+ 
+ #ifdef ENABLE_CHECKING
+   if (TREE_CODE_LENGTH (code) != 4)
+     abort ();
+ #endif
+ 
+   t = make_node (code);
+   TREE_TYPE (t) = tt;
+ 
+   fro = first_rtl_op (code);
+ 
+   side_effects = TREE_SIDE_EFFECTS (t);
+ 
+   PROCESS_ARG(0);
+   PROCESS_ARG(1);
+   PROCESS_ARG(2);
+   PROCESS_ARG(3);
+ 
+   TREE_SIDE_EFFECTS (t) = side_effects;  
+ 
+   return t;
+ }
+ 
+ /* Backup definition for non-gcc build compilers.  */
+ 
+ tree
+ (build) (enum tree_code code, tree tt, ...)
+ {
+   tree t, arg0, arg1, arg2, arg3;
+   int length = TREE_CODE_LENGTH (code);
+   va_list p;
+ 
+   va_start (p, tt);
+   switch (length)
+     {
+     case 0:
+       t = build0 (code, tt);
+       break;
+     case 1:
+       arg0 = va_arg (p, tree);
+       t = build1 (code, tt, arg0);
+       break;
+     case 2:
+       arg0 = va_arg (p, tree);
+       arg1 = va_arg (p, tree);
+       t = build2 (code, tt, arg0, arg1);
+       break;
+     case 3:
+       arg0 = va_arg (p, tree);
+       arg1 = va_arg (p, tree);
+       arg2 = va_arg (p, tree);
+       t = build3 (code, tt, arg0, arg1, arg2);
+       break;
+     case 4:
+       arg0 = va_arg (p, tree);
+       arg1 = va_arg (p, tree);
+       arg2 = va_arg (p, tree);
+       arg3 = va_arg (p, tree);
+       t = build4 (code, tt, arg0, arg1, arg2, arg3);
+       break;
+     default:
+       abort ();
+     }
+   va_end (p);
  
    return t;
  }
Index: tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.h,v
retrieving revision 1.467
diff -c -p -d -r1.467 tree.h
*** tree.h	11 Feb 2004 20:16:06 -0000	1.467
--- tree.h	15 Feb 2004 10:30:39 -0000
*************** extern tree maybe_get_identifier (const 
*** 2111,2123 ****
  extern tree build (enum tree_code, tree, ...);
  extern tree build_nt (enum tree_code, ...);
  
  extern tree build_int_2_wide (unsigned HOST_WIDE_INT, HOST_WIDE_INT);
  extern tree build_vector (tree, tree);
  extern tree build_constructor (tree, tree);
  extern tree build_real_from_int_cst (tree, tree);
  extern tree build_complex (tree, tree, tree);
  extern tree build_string (int, const char *);
- extern tree build1 (enum tree_code, tree, tree);
  extern tree build_tree_list (tree, tree);
  extern tree build_decl (enum tree_code, tree, tree);
  extern tree build_block (tree, tree, tree, tree, tree);
--- 2111,2140 ----
  extern tree build (enum tree_code, tree, ...);
  extern tree build_nt (enum tree_code, ...);
  
+ #if GCC_VERSION >= 3000
+ /* Use preprocessor trickery to map "build" to "buildN" where N is the
+    expected number of arguments.  This is used for both efficiency (no
+    varargs), and checking (verifying number of passed arguments).  */
+ #define build(code, type, rest...) \
+   _buildN1(build, _buildC1(rest))(code, type, ##rest)
+ #define _buildN1(BASE, X)	_buildN2(BASE, X)
+ #define _buildN2(BASE, X)	BASE##X
+ #define _buildC1(X...)		_buildC2(,##X,4,3,2,1,0)
+ #define _buildC2(a,b,c,d,e,f,...) f
+ #endif
+ 
+ extern tree build0 (enum tree_code, tree);
+ extern tree build1 (enum tree_code, tree, tree);
+ extern tree build2 (enum tree_code, tree, tree, tree);
+ extern tree build3 (enum tree_code, tree, tree, tree, tree);
+ extern tree build4 (enum tree_code, tree, tree, tree, tree, tree);
+ 
  extern tree build_int_2_wide (unsigned HOST_WIDE_INT, HOST_WIDE_INT);
  extern tree build_vector (tree, tree);
  extern tree build_constructor (tree, tree);
  extern tree build_real_from_int_cst (tree, tree);
  extern tree build_complex (tree, tree, tree);
  extern tree build_string (int, const char *);
  extern tree build_tree_list (tree, tree);
  extern tree build_decl (enum tree_code, tree, tree);
  extern tree build_block (tree, tree, tree, tree, tree);


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