summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormrs <mrs@138bc75d-0d04-0410-961f-82ee72b054a4>1996-05-17 20:13:01 +0000
committermrs <mrs@138bc75d-0d04-0410-961f-82ee72b054a4>1996-05-17 20:13:01 +0000
commit0e676ec9ec5dbfc271f292230e054b8e5af88a11 (patch)
tree984e0626a1a5e2e8f7ff306f11134448208ba86c
parent23b44fdadc6ae299eda159f023667a7602ce5a07 (diff)
downloadgcc-0e676ec9ec5dbfc271f292230e054b8e5af88a11.tar.gz
* expr.c (expand_expr, cond UNSAVE_EXPR): Move from the C++
frontend to the backend where it belongs. * tree.c (unsave_expr): Ditto. (unsave_expr_now): Ditto. * tree.def (UNSAVE_EXPR): Ditto. * tree.h (unsave_expr): Ditto. (unsave_expr_now): Ditto. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@12015 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/expr.c8
-rw-r--r--gcc/tree.c85
-rw-r--r--gcc/tree.def9
-rw-r--r--gcc/tree.h11
4 files changed, 113 insertions, 0 deletions
diff --git a/gcc/expr.c b/gcc/expr.c
index 87305aa5dc9..c10ff7b90e9 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -4905,6 +4905,14 @@ expand_expr (exp, target, tmode, modifier)
return SAVE_EXPR_RTL (exp);
+ case UNSAVE_EXPR:
+ {
+ rtx temp;
+ temp = expand_expr (TREE_OPERAND (exp, 0), target, tmode, modifier);
+ TREE_OPERAND (exp, 0) = unsave_expr_now (TREE_OPERAND (exp, 0));
+ return temp;
+ }
+
case PLACEHOLDER_EXPR:
/* If there is an object on the head of the placeholder list,
see if some object in it's references is of type TYPE. For
diff --git a/gcc/tree.c b/gcc/tree.c
index 7aa6c7736b1..fc4c983568a 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -2156,6 +2156,91 @@ save_expr (expr)
TREE_SIDE_EFFECTS (t) = 1;
return t;
}
+
+/* Arrange for an expression to be expanded multiple independent
+ times. This is useful for cleanup actions, as the backend can
+ expand them multiple times in different places. */
+tree
+unsave_expr (expr)
+ tree expr;
+{
+ tree t;
+
+ /* If this is already protected, no sense in protecting it again. */
+ if (TREE_CODE (expr) == UNSAVE_EXPR)
+ return expr;
+
+ t = build1 (UNSAVE_EXPR, TREE_TYPE (expr), expr);
+ TREE_SIDE_EFFECTS (t) = TREE_SIDE_EFFECTS (expr);
+ return t;
+}
+
+/* Modify a tree in place so that all the evaluate only once things
+ are cleared out. Return the EXPR given. */
+tree
+unsave_expr_now (expr)
+ tree expr;
+{
+ enum tree_code code;
+ register int i;
+
+ if (expr == NULL_TREE)
+ return expr;
+
+ code = TREE_CODE (expr);
+ switch (code)
+ {
+ case SAVE_EXPR:
+ SAVE_EXPR_RTL (expr) = NULL_RTX;
+ break;
+
+ case TARGET_EXPR:
+ sorry ("TARGET_EXPR reused inside UNSAVE_EXPR");
+ break;
+
+ case RTL_EXPR:
+ warning ("RTL_EXPR reused inside UNSAVE_EXPR");
+ RTL_EXPR_SEQUENCE (expr) = NULL_RTX;
+ break;
+
+ case CALL_EXPR:
+ CALL_EXPR_RTL (expr) = NULL_RTX;
+ if (TREE_OPERAND (expr, 1)
+ && TREE_CODE (TREE_OPERAND (expr, 1)) == TREE_LIST)
+ {
+ tree exp = TREE_OPERAND (expr, 1);
+ while (exp)
+ {
+ unsave_expr_now (TREE_VALUE (exp));
+ exp = TREE_CHAIN (exp);
+ }
+ }
+ 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 expr;
+
+ 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 = tree_code_length[(int) code] - 1; i >= 0; i--)
+ unsave_expr_now (TREE_OPERAND (expr, i));
+ return expr;
+
+ default:
+ abort ();
+ }
+}
/* 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.
diff --git a/gcc/tree.def b/gcc/tree.def
index 9de2ca01d99..61f06a94a68 100644
--- a/gcc/tree.def
+++ b/gcc/tree.def
@@ -646,6 +646,15 @@ DEFTREECODE (NON_LVALUE_EXPR, "non_lvalue_expr", "1", 1)
nonzero only after the expression has been computed. */
DEFTREECODE (SAVE_EXPR, "save_expr", "e", 3)
+/* For a UNSAVE_EXPR, operand 0 is the value to unsave. By unsave, we
+ mean that all _EXPRs such as TARGET_EXPRs, SAVE_EXPRs,
+ CALL_EXPRs and RTL_EXPRs, that are protected
+ from being evaluated more than once should be reset so that a new
+ expand_expr call of this expr will cause those to be re-evaluated.
+ This is useful when we want to reuse a tree in different places,
+ but where we must re-expand. */
+DEFTREECODE (UNSAVE_EXPR, "unsave_expr", "e", 1)
+
/* Represents something whose RTL has already been expanded
as a sequence which should be emitted when this expression is expanded.
The first operand is the RTL to emit. It is the first of a chain of insns.
diff --git a/gcc/tree.h b/gcc/tree.h
index dea5d77e123..ab2df453a5d 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -1436,6 +1436,17 @@ extern int lvalue_or_else PROTO((tree, char *));
extern tree save_expr PROTO((tree));
+/* unsave_expr (EXP) returns an expression equivalent to EXP but it
+ can be used multiple times and will evaluate EXP, in it's entirety
+ each time. */
+
+extern tree unsave_expr PROTO((tree));
+
+/* unsave_expr_now (EXP) resets EXP in place, so that it can be
+ expanded again. */
+
+extern tree unsave_expr_now PROTO((tree));
+
/* 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.