[prev in list] [next in list] [prev in thread] [next in thread] 

List:       gcc-patches
Subject:    Re: Tree inlining for the C front end (part 3 of 3)
From:       Alexandre Oliva <aoliva () redhat ! com>
Date:       2001-09-29 22:29:33
[Download RAW message or body]

On Sep 25, 2001, Gerald Pfeifer <pfeifer@dbai.tuwien.ac.at> wrote:

> On 24 Sep 2001, Alexandre Oliva wrote:
>> And finally, this patch enables tree inlining in the C front end.
>> [...]
>> Here's patch #3/3.  Bootstrapped and tested on athlon-pc-linux-gnu,
>> along with patches #1 and #2.  Ok to install?

> I firmly believe this should *NOT* be installed before it has passed
> serious compile-time and run-time (=code quality) performance bench-
> marking.

> We really, really, really should avoid having a huge regression in
> these respects as we had for the C++ frontend in GCC 3.0 and 3.0.1.

> The absolutely minimal set of tests required IMNSHO are timings for a
> compiler bootstrap (with and without this inliner), SPEC results, and
> at least another application benchmark (build time and run-time).

Ok, so I went ahead and verified that my patches had indeed disabled
-finline-functions, which I fixed with the patch below.  While I was
at it, I improved memory usage by only saving trees of inlinable
functions, which reduced the gap between bootstrap with and without my
patch.  I have also fixed all regressions in the testsuite, going back
to the same passes and failures as without my patches.

Here are today's numbers for bootstrap times of the entire GCC tree
(i.e., all languages, libraries included), with `make -j8 bootstrap',
starting from a just-configured build tree.

Bootstrap with none of my patches and standard BOOT_CFLAGS:
real    41m29.371s
user    36m29.430s
sys     4m7.420s

Bootstrap with patches 1 and 2 only, standard BOOT_CFLAGS:
real    41m32.907s
user    36m30.400s
sys     4m11.080s

Bootstrap with all 4 patches and standard BOOT_CFLAGS:
real    42m2.477s
user    37m2.970s
sys     4m7.510s

Bootstrap with patches 1 and 2 only and BOOT_CFLAGS='-O3 -g'.
real    43m48.287s
user    38m50.090s
sys     4m7.500s

Bootstrap with all 4 patches and BOOT_CFLAGS='-O3 -g'
real    44m30.794s
user    39m25.950s
sys     4m13.910s


That's a 1.3% increase in bootstrap time (all libraries, all
languages) for standard BOOT_CFLAGS, and 1.6% for a -O3 bootstrap.
Much better, eh? :-)


Here are some SPEC95 cint results, averaged over 3 runs, first with
patches 1 and 2 only (i.e., no tree inlining in C, just infrastructure
changes), then with all of 4 patches:

                     Base      Base      Base      Peak      Peak      Peak
   Benchmarks    Ref Time  Run Time     Ratio  Ref Time  Run Time     Ratio
   ------------  --------  --------  --------  --------  --------  --------
   099.go            4600      87.7      52.4      4600      88.2      52.1 
   124.m88ksim       1900      37.2      51.1      1900      41.2      46.1 
   126.gcc           1700      33.9      50.1      1700      34.0      50.0 
   129.compress      1800      72.7      24.8      1800      72.4      24.9 
   130.li            1900      38.5      49.3      1900      36.4      52.2 
   132.ijpeg         2400      55.5      43.2      2400      56.9      42.2 
   134.perl          1900      29.0      65.6      1900      28.9      65.8 
   147.vortex        2700      67.2      40.2      2700      65.4      41.3 
   SPECint_base95 (Geom. Mean)           45.6                              
   SPECint95 (Geom. Mean)                                              45.3
   ------------  --------  --------  --------  --------  --------  --------
   099.go            4600      87.8      52.4      4600      88.5      52.0 
   124.m88ksim       1900      37.2      51.1      1900      41.1      46.2 
   126.gcc           1700      33.9      50.1      1700      34.1      49.9 
   129.compress      1800      72.9      24.7      1800      73.3      24.5 
   130.li            1900      38.3      49.6      1900      36.4      52.2 
   132.ijpeg         2400      55.5      43.2      2400      56.9      42.2 
   134.perl          1900      28.9      65.9      1900      28.9      65.8 
   147.vortex        2700      67.4      40.0      2700      65.2      41.4 
   SPECint_base95 (Geom. Mean)           45.6                              
   SPECint95 (Geom. Mean)                                              45.3

No significant differences in performance, as expected, and a
hopefully acceptable increase in build time.

Some notes:

- I have mixed feelings about disabling inlining of functions that
  call __builtin_return_address() (see the #if 0 block in
  inline_forbidden_p().  It seems to me that we shouldn't be messing
  up with such functions.  In particular, if some functions in
  gcc.c-torture/execute/20010122-1.c are reordered, they end up
  inlined and produce incorrect results.  The patch below doesn't
  address this issue, though; it just uses a mechanism other than
  calling alloca() to prevent inlining of a function in those
  functions that would be currently inlined while they shouldn't.

- Some changes in tree-inline.c were necessary to cope with
  differences between C++ and C.  For example, C functions without
  prototypes may be called with excess or missing arguments; I've
  arranged for trailing parameters to be declared uninitialized, and
  for trailing arguments to be evaluated and discarded.  Also, type
  promotion of return types is different in C and in C++; the type of
  the DECL_RESULT of a C function is the promoted type, but the inline
  site expects the actual return type, so I introduced a conversion if
  types don't match.  Also, I found out varargs_function_p() is not
  enough to detect C functions with variable number of arguments, so I
  moved the function back to the C++ front-end, and moved its test
  into the language-specific section of the inlinability test.  While
  I was at it, I introduced the test for
  function_attribute_inlinable_p() in the C++ inlinability tests too.
  I wonder if I should move some more tests from the C version too,
  such as the test for calls to setjmp(), va_start, return_address,
  non-local gotos, etc.  I also plan on integrating the move of
  varags_function_p() back into the C++ front-end into some previous
  patch for purposes of installing them; perhaps some other changes
  may also be put in together.  Of course, I'll test whatever patch I
  check in individually.

- save_for_inline() is still called, so that we can defer the output
  of functions and still choose not to emit them when not necessary,
  but I have arranged for it to not do much in case we know we won't
  inline the function.  In particular, I've arranged for it to not
  mess up with TREE_READONLY of parameters, which broke
  gcc.dg/980709-1.c because the declaration of addr was marked as
  readonly, despite my efforts to get the code to recognize the
  (mem(addressof(reg))) as (reg) when marking the parameter as
  updated.  The reg was, for some reason, beyond the max_parm_reg, and
  I couldn't figure out how to fix max_parm_reg.  I decided I was just
  beating a dead horse, and there was no reason to try to keep the RTL
  inliner working, so I just went ahead and disabled that piece of
  code.

- The change in cse.c fixes the problem of cse moving the only use of
  a LABEL, stored in a register, without moving the REG_LABEL along
  with it, causing the compiler to enter an endless loop.  It turned
  out that the problem was that the label was already deleted, and we
  don't want REG_LABEL for deleted labels, but check_for_label_ref
  still demanded them; such a demand would never be fulfilled, though.

This new patch was bootstrapped and regression tested on
athlon-pc-linux-gnu, along with the 3 previously-posted patches.  Are
they ok to install?


[Attachment #3 (text/x-patch)]

Index: gcc/ChangeLog
from  Alexandre Oliva  <aoliva@redhat.com>

	* Makefile.in (c-lang.o): Depend on insn-config.h and integrate.h.
	* c-decl.c (c_expand_body): Determine whether a function is
	inlinable upfront, and don't keep DECL_SAVED_TREE otherwise.
	* c-lang.c: Include insn-config.h and integrate.h.
	(c_post_options): Don't inline trees when instrumenting functions.
	(inline_forbidden_p): New function.
	(c_cannot_inline_tree_fn): Likewise.
	(c_init): Set lang_cannot_inline_tree_fn.
	* c-typeck.c (decl_constant_value): Revert previous change.
	* tree-inline.c (initialize_inlined_parameters): Handle calls
	with fewer arguments than declared parameters, and fewer
	parameters than passed arguments.  Don't assume value is a
	DECL.
	(declare_return_variable): Convert return value back to the
	original type, if it was promoted.
	(tree_inlinable_function_p): New function.
	(inlinable_function_p): Don't look at DECL_INLINE if we're
	inlining all functions.  Make it work with a NULL id.
	Re-check DECL_UNINLINABLE after language-specific checks.
	(varargs_function_p): Move back to cp/tree.c.
	* tree-inline.h (tree_inlinable_function_p): Declare it.
	(varargs_function_p): Removed declaration.
	* integrate.h (function_attribute_inlinable_p): Declare it.
	* integrate.c (function_attribute_inlinable_p): Export it.
	(save_for_inline): Don't bother to prepare argvec when not
	inlining.
	* cse.c (check_for_label_ref): Don't check deleted labels.

Index: gcc/cp/ChangeLog
from  Alexandre Oliva  <aoliva@redhat.com>

	* cp/tree.c (varargs_function_p): Move back from ../tree-inline.c.
	(cp_cannot_inline_tree_fn): Test varargs_function_p and
	function_attribute_inlinable_p.

Index: gcc/testsuite/ChangeLog
from  Alexandre Oliva  <aoliva@redhat.com>

	* gcc.c-torture/execute/20010122-1.c: Don't assume alloca() is
	enough to avoid inlining.

--- gcc/Makefile.in 2001/09/27 17:06:26
+++ gcc/Makefile.in 2001/09/29 17:57:27
@@ -1175 +1175 @@
-    $(RTL_H) $(EXPR_H) tree-inline.h
+    $(RTL_H) $(EXPR_H) tree-inline.h insn-config.h integrate.h
--- gcc/c-decl.c 2001/09/27 17:06:28
+++ gcc/c-decl.c 2001/09/29 17:57:27
@@ -6691,0 +6692,2 @@
+  int uninlinable = 1;
+
@@ -6698 +6700,9 @@
-    optimize_inline_calls (fndecl);
+    {
+      /* First, cache whether the current function is inlinable.  Some
+         predicates depend on cfun and current_function_decl to
+         function completely.  */
+      uninlinable = ! tree_inlinable_function_p (fndecl);
+      
+      /* Then, inline any functions called in it.  */
+      optimize_inline_calls (fndecl);
+    }
@@ -6739 +6749 @@
-  if (! flag_inline_trees)
+  if (uninlinable)
@@ -6744 +6753,0 @@
-    
--- gcc/c-lang.c 2001/09/27 17:06:29
+++ gcc/c-lang.c 2001/09/29 17:57:27
@@ -38,0 +39,2 @@
+#include "insn-config.h"
+#include "integrate.h"
@@ -45,0 +48 @@
+static int c_cannot_inline_tree_fn PARAMS ((tree *));
@@ -60,2 +63,3 @@
-  /* Adjust various flags based on command-line settings.  */
-  if (!flag_no_inline)
+  /* Use tree inlining if possible.  Function instrumentation is only
+     done in the RTL level, so we disable tree inlining.  */
+  if (! flag_instrument_function_entry_exit)
@@ -63,7 +67,10 @@
-      flag_inline_trees = 1;
-      flag_no_inline = 1;
-    }
-  if (flag_inline_functions)
-    {
-      flag_inline_trees = 2;
-      flag_inline_functions = 0;
+      if (!flag_no_inline)
+	{
+	  flag_inline_trees = 1;
+	  flag_no_inline = 1;
+	}
+      if (flag_inline_functions)
+	{
+	  flag_inline_trees = 2;
+	  flag_inline_functions = 0;
+	}
@@ -108,0 +116 @@
+  lang_cannot_inline_tree_fn = &c_cannot_inline_tree_fn;
@@ -335,0 +344,141 @@
+}
+
+static tree inline_forbidden_p PARAMS ((tree *, int *, void *));
+
+static tree
+inline_forbidden_p (nodep, walk_subtrees, fn)
+     tree *nodep;
+     int *walk_subtrees ATTRIBUTE_UNUSED;
+     void *fn;
+{
+  tree node = *nodep;
+  tree t;
+
+  switch (TREE_CODE (node))
+    {
+    case CALL_EXPR:
+      t = get_callee_fndecl (node);
+
+      if (! t)
+	break;
+
+      /* We cannot inline functions that call setjmp.  */
+      if (setjmp_call_p (t))
+	return node;
+
+      switch (DECL_FUNCTION_CODE (t))
+	{
+	  /* We cannot inline functions that take a variable number of
+	     arguments.  */
+	case BUILT_IN_VARARGS_START:
+	case BUILT_IN_STDARG_START:
+#if 0
+	  /* Functions that need information about the address of the
+             caller can't (shouldn't?) be inlined.  */
+	case BUILT_IN_RETURN_ADDRESS:
+#endif
+	  return node;
+
+	default:
+	  break;
+	}
+
+      break;
+
+    case DECL_STMT:
+      /* We cannot inline functions that contain other functions.  */
+      if (TREE_CODE (TREE_OPERAND (node, 0)) == FUNCTION_DECL
+	  && DECL_INITIAL (TREE_OPERAND (node, 0)))
+	return node;
+      break;
+
+    case GOTO_STMT:
+    case GOTO_EXPR:
+      t = TREE_OPERAND (node, 0);
+
+      /* We will not inline a function which uses computed goto.  The
+	 addresses of its local labels, which may be tucked into
+	 global storage, are of course not constant across
+	 instantiations, which causes unexpected behaviour.  */
+      if (TREE_CODE (t) != LABEL_DECL)
+	return node;
+
+      /* We cannot inline a nested function that jumps to a nonlocal
+         label.  */
+      if (TREE_CODE (t) == LABEL_DECL
+	  && DECL_CONTEXT (t) && DECL_CONTEXT (t) != fn)
+	return node;
+
+      break;
+
+    default:
+      break;
+    }
+
+  return NULL_TREE;
+}
+
+static int
+c_cannot_inline_tree_fn (fnp)
+     tree *fnp;
+{
+  tree fn = *fnp;
+  tree t;
+
+  if (! function_attribute_inlinable_p (fn))
+    {
+      DECL_UNINLINABLE (fn) = 1;
+      return 1;
+    }
+
+  /* If a function has pending sizes, we must not defer its
+     compilation, and we can't inline it as a tree.  */
+  if (fn == current_function_decl)
+    {
+      t = get_pending_sizes ();
+      put_pending_sizes (t);
+
+      if (t)
+	{
+	  DECL_UNINLINABLE (fn) = 1;
+	  return 1;
+	}
+    }
+
+  if (DECL_CONTEXT (fn))
+    {
+      /* If a nested function has pending sizes, we may have already
+         saved them.  */
+      if (DECL_LANG_SPECIFIC (fn)->pending_sizes)
+	{
+	  DECL_UNINLINABLE (fn) = 1;
+	  return 1;
+	}
+    }
+  else
+    {
+      /* We rely on the fact that this function is called upfront,
+	 just before we start expanding a function.  If FN is active
+	 (i.e., it's the current_function_decl or a parent thereof),
+	 we have to walk FN's saved tree.  Otherwise, we can safely
+	 assume we have done it before and, if we didn't mark it as
+	 uninlinable (in which case we wouldn't have been called), it
+	 is inlinable.  Unfortunately, this strategy doesn't work for
+	 nested functions, because they're only expanded as part of
+	 their enclosing functions, so the inlinability test comes in
+	 late.  */
+      t = current_function_decl;
+
+      while (t && t != fn)
+	t = DECL_CONTEXT (t);
+      if (! t)
+	return 0;
+    }
+    
+  if (walk_tree (&DECL_SAVED_TREE (fn), inline_forbidden_p, fn, NULL))
+    {
+      DECL_UNINLINABLE (fn) = 1;
+      return 1;
+    }
+
+  return 0;
--- gcc/c-typeck.c 2001/09/27 17:06:30
+++ gcc/c-typeck.c 2001/09/26 21:02:16 1.139
@@ -807,7 +807,7 @@
 	 in a place where a variable is invalid.  */
       current_function_decl != 0
       && ! TREE_THIS_VOLATILE (decl)
+      && TREE_READONLY (decl)
-      && TREE_READONLY_DECL_P (decl)
       && DECL_INITIAL (decl) != 0
       && TREE_CODE (DECL_INITIAL (decl)) != ERROR_MARK
       /* This is invalid if initial value is not constant.
--- gcc/tree-inline.c Thu Sep 27 10:06:31 2001
+++ gcc/tree-inline.c Sat Sep 29 10:57:29 2001
@@ -486 +486,2 @@
-  for (p = parms, a = args; p; a = TREE_CHAIN (a), p = TREE_CHAIN (p))
+  for (p = parms, a = args; p;
+       a = a ? TREE_CHAIN (a) : a, p = TREE_CHAIN (p))
@@ -493 +494,2 @@
-      value = TREE_VALUE (a);
+      value = a ? TREE_VALUE (a) : NULL_TREE;
+
@@ -499 +501 @@
-	  && !TREE_SIDE_EFFECTS (value))
+	  && value && !TREE_SIDE_EFFECTS (value))
@@ -502 +504 @@
-	  value = fold (decl_constant_value (value));
+	  value = fold (DECL_P (value) ? decl_constant_value (value) : value);
@@ -569,0 +572,17 @@
+  /* Evaluate trailing arguments.  */
+  for (; a; a = TREE_CHAIN (a))
+    {
+      tree init_stmt;
+      tree value;
+
+      /* Find the initializer.  */
+      value = a ? TREE_VALUE (a) : NULL_TREE;
+
+      if (! value || ! TREE_SIDE_EFFECTS (value))
+	continue;
+
+      init_stmt = build_stmt (EXPR_STMT, value);
+      TREE_CHAIN (init_stmt) = init_stmts;
+      init_stmts = init_stmt;
+    }
+
@@ -609,3 +628,9 @@
-  /* Build the USE_STMT.  */
-  *use_stmt = build_stmt (EXPR_STMT, var);
-
+  /* Build the USE_STMT.  If the return type of the function was
+     promoted, convert it back to the expected type.  */
+  if (TREE_TYPE (var) == TREE_TYPE (TREE_TYPE (fn)))
+    *use_stmt = build_stmt (EXPR_STMT, var);
+  else
+    *use_stmt = build_stmt (EXPR_STMT,
+			    build1 (NOP_EXPR, TREE_TYPE (TREE_TYPE (fn)),
+				    var));
+      
@@ -622 +647,12 @@
-/* Returns non-zero if FN is a function that can be inlined.  */
+/* Returns non-zero if a function can be inlined as a tree.  */
+
+int
+tree_inlinable_function_p (fn)
+     tree fn;
+{
+  return inlinable_function_p (fn, NULL);
+}
+
+/* Returns non-zero if FN is a function that can be inlined into the
+   inlining context ID_.  If ID_ is NULL, check whether the function
+   can be inlined at all.  */
@@ -640,5 +676 @@
-  if (!flag_inline_trees)
-    ;
-  /* If the function was not declared `inline', then we don't inline
-     it.  */
-  else if (!DECL_INLINE (fn))
+  if (! flag_inline_trees)
@@ -646,2 +678,3 @@
-  /* We can't inline varargs functions.  */
-  else if (varargs_function_p (fn))
+  /* If we're not inlining all functions and the function was not
+     declared `inline', we don't inline it.  */
+  else if (flag_inline_trees < 2 && ! DECL_INLINE (fn))
@@ -663 +696 @@
-  DECL_UNINLINABLE (fn) = !inlinable;
+  DECL_UNINLINABLE (fn) = ! inlinable;
@@ -670 +703 @@
-      && ((DECL_NUM_STMTS (fn) + id->inlined_stmts) * INSNS_PER_STMT
+      && ((DECL_NUM_STMTS (fn) + (id ? id->inlined_stmts : 0)) * INSNS_PER_STMT
@@ -680 +713 @@
-  if (!DECL_SAVED_TREE (fn))
+  if (! DECL_SAVED_TREE (fn))
@@ -682,0 +716,4 @@
+  /* Check again, language hooks may have modified it.  */
+  if (! inlinable || DECL_UNINLINABLE (fn))
+    return 0;
+
@@ -685 +722 @@
-  if (inlinable)
+  if (id)
@@ -693 +730 @@
-      if (inlinable && DECL_INLINED_FNS (fn))
+      if (DECL_INLINED_FNS (fn))
@@ -1308,13 +1344,0 @@
-}
-
-/* Does FUNCTION use a variable-length argument list?  */
-
-int
-varargs_function_p (function)
-     tree function;
-{
-  tree parm = TYPE_ARG_TYPES (TREE_TYPE (function));
-  for (; parm; parm = TREE_CHAIN (parm))
-    if (TREE_VALUE (parm) == void_type_node)
-      return 0;
-  return 1;
--- gcc/tree-inline.h Thu Sep 27 10:06:31 2001
+++ gcc/tree-inline.h Sat Sep 29 10:57:29 2001
@@ -27,0 +28 @@
+int tree_inlinable_function_p PARAMS ((tree));
@@ -33 +33,0 @@
-int varargs_function_p PARAMS ((tree));
--- gcc/cp/tree.c 2001/09/27 17:06:39
+++ gcc/cp/tree.c 2001/09/29 17:57:31
@@ -1797,0 +1798,13 @@
+/* Does FUNCTION use a variable-length argument list?  */
+
+int
+varargs_function_p (function)
+     tree function;
+{
+  tree parm = TYPE_ARG_TYPES (TREE_TYPE (function));
+  for (; parm; parm = TREE_CHAIN (parm))
+    if (TREE_VALUE (parm) == void_type_node)
+      return 0;
+  return 1;
+}
+
@@ -2122,0 +2136,2 @@
+  tree fn = *fnp;
+
@@ -2125,2 +2140,14 @@
-  if (DECL_TEMPLATE_INFO (*fnp)
-      && TI_PENDING_TEMPLATE_FLAG (DECL_TEMPLATE_INFO (*fnp)))
+  if (DECL_TEMPLATE_INFO (fn)
+      && TI_PENDING_TEMPLATE_FLAG (DECL_TEMPLATE_INFO (fn)))
+    {
+      *fnp = fn = instantiate_decl (fn, /*defer_ok=*/0);
+      return TI_PENDING_TEMPLATE_FLAG (DECL_TEMPLATE_INFO (fn));
+    }
+
+  if (varargs_function_p (fn))
+    {
+      DECL_UNINLINABLE (fn) = 1;
+      return 1;
+    }
+
+  if (! function_attribute_inlinable_p (fn))
@@ -2128,2 +2155,2 @@
-      *fnp = instantiate_decl (*fnp, /*defer_ok=*/0);
-      return TI_PENDING_TEMPLATE_FLAG (DECL_TEMPLATE_INFO (*fnp));
+      DECL_UNINLINABLE (fn) = 1;
+      return 1;
--- gcc/testsuite/gcc.c-torture/execute/20010122-1.c 2001/04/11 20:31:15 1.2
+++ gcc/testsuite/gcc.c-torture/execute/20010122-1.c 2001/09/29 17:57:31
@@ -78,15 +78,14 @@ void *test6a (char * p)
 
 void *(*func1[6])(void) = { test1, test2, test3, test4, test5, test6 };
 
-char * call_func1 (int i)
+char * call_func1_ (int i)
 {
-  char * save = (char*) alloca (4);
-
   save_ret1[i] = func1[i] ();
-
-  return save;
 }
 
+/* We dont' want call_func1_ to be inlined, so call it through a
+   pointer.  */
+void (*call_func1)(int) = call_func1_;
 
 static void *ret_addr;
 void *save_ret2[6];
@@ -164,15 +163,15 @@ char * dummy (void)
 
 void (*func2[6])(void) = { test7, test8, test9, test10, test11, test12 };
 
-char * call_func2 (int i)
+void call_func2_ (int i)
 {
-  char * save = (char*) alloca (4);
-
   func2[i] ();
   save_ret2[i] = ret_addr;
-
-  return save;
 }
+
+/* We dont' want call_func2_ to be inlined, so call it through a
+   pointer.  */
+void (*call_func2)(int) = call_func2_;
 
 int main (void)
 {
--- gcc/integrate.h 2001/09/21 00:45:30 1.21
+++ gcc/integrate.h 2001/09/29 17:57:29
@@ -152,6 +152,11 @@ extern union tree_node *copy_decl_for_in
 						      union tree_node *,
 						      union tree_node *));
 
+/* Check whether there's any attribute in a function declaration that
+   makes the function uninlinable.  Returns false if it finds any,
+   true otherwise.  */
+extern bool function_attribute_inlinable_p PARAMS ((union tree_node *));
+
 extern void try_constants PARAMS ((rtx, struct inline_remap *));
 
 /* Return the label indicated.  */
--- gcc/integrate.c 2001/09/21 15:16:31 1.165
+++ gcc/integrate.c 2001/09/29 17:57:29
@@ -77,8 +77,6 @@ typedef struct initial_value_struct {
   initial_value_pair *entries;
 } initial_value_struct;
 
-static bool function_attribute_inlinable_p PARAMS ((tree));
-
 static void setup_initial_hard_reg_value_integration PARAMS ((struct function *, \
struct inline_remap *));  
 static rtvec initialize_for_inline	PARAMS ((tree));
@@ -129,7 +127,7 @@ get_label_from_map (map, i)
 
 /* Return false if the function FNDECL cannot be inlined on account of its
    attributes, true otherwise.  */
-static bool
+bool
 function_attribute_inlinable_p (fndecl)
      tree fndecl;
 {
@@ -442,8 +440,8 @@ save_for_inline (fndecl)
      Also set up ARG_VECTOR, which holds the unmodified DECL_RTX values
      for the parms, prior to elimination of virtual registers.
      These values are needed for substituting parms properly.  */
-
-  parmdecl_map = (tree *) xmalloc (max_parm_reg * sizeof (tree));
+  if (! flag_no_inline)
+    parmdecl_map = (tree *) xmalloc (max_parm_reg * sizeof (tree));
 
   /* Make and emit a return-label if we have not already done so.  */
 
@@ -453,7 +451,10 @@ save_for_inline (fndecl)
       emit_label (return_label);
     }
 
-  argvec = initialize_for_inline (fndecl);
+  if (! flag_no_inline)
+    argvec = initialize_for_inline (fndecl);
+  else
+    argvec = NULL;
 
   /* Delete basic block notes created by early run of find_basic_block.
      The notes would be later used by find_basic_blocks to reuse the memory
@@ -470,27 +471,31 @@ save_for_inline (fndecl)
   if (GET_CODE (insn) != NOTE)
     abort ();
 
-  /* Get the insn which signals the end of parameter setup code.  */
-  first_nonparm_insn = get_first_nonparm_insn ();
+  if (! flag_no_inline)
+    {
+      /* Get the insn which signals the end of parameter setup code.  */
+      first_nonparm_insn = get_first_nonparm_insn ();
 
-  /* Now just scan the chain of insns to see what happens to our
-     PARM_DECLs.  If a PARM_DECL is used but never modified, we
-     can substitute its rtl directly when expanding inline (and
-     perform constant folding when its incoming value is constant).
-     Otherwise, we have to copy its value into a new register and track
-     the new register's life.  */
-  in_nonparm_insns = 0;
-  save_parm_insns (insn, first_nonparm_insn);
-
-  cfun->inl_max_label_num = max_label_num ();
-  cfun->inl_last_parm_insn = cfun->x_last_parm_insn;
-  cfun->original_arg_vector = argvec;
+      /* Now just scan the chain of insns to see what happens to our
+	 PARM_DECLs.  If a PARM_DECL is used but never modified, we
+	 can substitute its rtl directly when expanding inline (and
+	 perform constant folding when its incoming value is
+	 constant).  Otherwise, we have to copy its value into a new
+	 register and track the new register's life.  */
+      in_nonparm_insns = 0;
+      save_parm_insns (insn, first_nonparm_insn);
+
+      cfun->inl_max_label_num = max_label_num ();
+      cfun->inl_last_parm_insn = cfun->x_last_parm_insn;
+      cfun->original_arg_vector = argvec;
+    }
   cfun->original_decl_initial = DECL_INITIAL (fndecl);
   cfun->no_debugging_symbols = (write_symbols == NO_DEBUG);
   DECL_SAVED_INSNS (fndecl) = cfun;
 
   /* Clean up.  */
-  free (parmdecl_map);
+  if (! flag_no_inline)
+    free (parmdecl_map);
 }
 
 /* Scan the chain of insns to see what happens to our PARM_DECLs.  If a
--- gcc/cse.c 2001/09/28 13:01:40 1.205
+++ gcc/cse.c 2001/09/29 17:57:28
@@ -7376,6 +7376,7 @@ check_for_label_ref (rtl, data)
      LABEL_REF for a CODE_LABEL that isn't in the insn chain, don't do this
      since no REG_LABEL will be added.  */
   return (GET_CODE (*rtl) == LABEL_REF
+	  && LABEL_P (XEXP (*rtl, 0))
 	  && INSN_UID (XEXP (*rtl, 0)) != 0
 	  && ! find_reg_note (insn, REG_LABEL, XEXP (*rtl, 0)));
 }


-- 
Alexandre Oliva   Enjoy Guarana', see http://www.ic.unicamp.br/~oliva/
Red Hat GCC Developer                  aoliva@{cygnus.com, redhat.com}
CS PhD student at IC-Unicamp        oliva@{lsd.ic.unicamp.br, gnu.org}
Free Software Evangelist    *Please* write to mailing lists, not to me


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic