aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree.c
diff options
context:
space:
mode:
authorJeffrey A Law <law@cygnus.com>2000-03-17 14:40:45 -0800
committerRichard Henderson <rth@gcc.gnu.org>2000-03-17 14:40:45 -0800
commit0a1c58a25ab5df1a3e4596024774641ebae8be2a (patch)
tree720b4c50b7ea074422601de35cfc7e48ed679e49 /gcc/tree.c
parentf1fd8077fd1260362aa134deefc197948da270f8 (diff)
downloadgcc-0a1c58a25ab5df1a3e4596024774641ebae8be2a.zip
gcc-0a1c58a25ab5df1a3e4596024774641ebae8be2a.tar.gz
gcc-0a1c58a25ab5df1a3e4596024774641ebae8be2a.tar.bz2
Sibling call optimizations.
Co-Authored-By: Richard Henderson <rth@cygnus.com> From-SVN: r32612
Diffstat (limited to 'gcc/tree.c')
-rw-r--r--gcc/tree.c79
1 files changed, 79 insertions, 0 deletions
diff --git a/gcc/tree.c b/gcc/tree.c
index 72d85ee..c6045ff 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -285,6 +285,9 @@ static void mark_type_hash PARAMS ((void *));
void (*lang_unsave) PARAMS ((tree *));
void (*lang_unsave_expr_now) PARAMS ((tree));
+/* If non-null, a language specific version of safe_for_unsave. */
+int (*lang_safe_for_unsave) PARAMS ((tree));
+
/* The string used as a placeholder instead of a source file name for
built-in tree nodes. The variable, which is dynamically allocated,
should be used; the macro is only used to initialize it. */
@@ -2666,6 +2669,82 @@ unsave_expr_now (expr)
return expr;
}
+
+/* Return nonzero if it is safe to unsave EXPR, else return zero.
+ It is not safe to unsave EXPR if it contains any embedded RTL_EXPRs. */
+
+int
+safe_for_unsave (expr)
+ tree expr;
+{
+ enum tree_code code;
+ register int i;
+ int first_rtl;
+
+ if (expr == NULL_TREE)
+ return 1;
+
+ code = TREE_CODE (expr);
+ first_rtl = first_rtl_op (code);
+ switch (code)
+ {
+ case RTL_EXPR:
+ return 0;
+
+ case CALL_EXPR:
+ if (TREE_OPERAND (expr, 1)
+ && TREE_CODE (TREE_OPERAND (expr, 1)) == TREE_LIST)
+ {
+ tree exp = TREE_OPERAND (expr, 1);
+ while (exp)
+ {
+ if (! safe_for_unsave (TREE_VALUE (exp)))
+ return 0;
+ exp = TREE_CHAIN (exp);
+ }
+ }
+ break;
+
+ default:
+ if (lang_safe_for_unsave)
+ switch ((*lang_safe_for_unsave) (expr))
+ {
+ case -1:
+ break;
+ case 0:
+ return 0;
+ case 1:
+ return 1;
+ default:
+ abort ();
+ }
+ break;
+ }
+
+ switch (TREE_CODE_CLASS (code))
+ {
+ case 'c': /* a constant */
+ case 't': /* a type node */
+ case 'x': /* something random, like an identifier or an ERROR_MARK. */
+ case 'd': /* A decl node */
+ case 'b': /* A block node */
+ return 1;
+
+ case 'e': /* an expression */
+ case 'r': /* a reference */
+ case 's': /* an expression with side effects */
+ case '<': /* a comparison expression */
+ case '2': /* a binary arithmetic expression */
+ case '1': /* a unary arithmetic expression */
+ for (i = first_rtl - 1; i >= 0; i--)
+ if (! safe_for_unsave (TREE_OPERAND (expr, i)))
+ return 0;
+ return 1;
+
+ default:
+ return 0;
+ }
+}
/* Return 1 if EXP contains a PLACEHOLDER_EXPR; i.e., if it represents a size
or offset that depends on a field within a record. */