#include "tm.h"
#include "tree.h"
#include "tree-gimple.h"
+#include "tree-flow.h"
#include "output.h"
#include "rtl.h"
#include "expr.h"
addr-expr-arg: ID
| compref
- lhs : addr-expr-arg
- | '*' val
+ addressable : addr-expr-arg
+ | indirectref
+
+ with-size-arg: addressable
+ | call-stmt
+
+ indirectref : INDIRECT_REF
+ op0 -> val
+
+ lhs : addressable
| bitfieldref
+ | WITH_SIZE_EXPR
+ op0 -> with-size-arg
+ op1 -> val
min-lval : ID
- | '*' val
+ | indirectref
bitfieldref : BIT_FIELD_REF
op0 -> inner-compref
op0 -> inner-compref
condition : val
- | val RELOP val
+ | RELOP
+ op0 -> val
+ op1 -> val
val : ID
| CONST
rhs : lhs
| CONST
- | '&' addr-expr-arg
- | call_expr
- | UNOP val
- | val BINOP val
- | val RELOP val
+ | call-stmt
+ | ADDR_EXPR
+ op0 -> addr-expr-arg
+ | UNOP
+ op0 -> val
+ | BINOP
+ op0 -> val
+ op1 -> val
+ | RELOP
+ op0 -> val
+ op1 -> val
*/
static inline bool is_gimple_id (tree);
/* Validation of GIMPLE expressions. */
-/* Return true if T is a GIMPLE RHS. */
+/* Return true if T is a GIMPLE RHS for an assignment to a temporary. */
bool
-is_gimple_rhs (tree t)
+is_gimple_tmp_rhs (tree t)
{
enum tree_code code = TREE_CODE (t);
case CALL_EXPR:
case CONSTRUCTOR:
case COMPLEX_EXPR:
- /* FIXME lower VA_ARG_EXPR. */
- case VA_ARG_EXPR:
case INTEGER_CST:
case REAL_CST:
case STRING_CST:
return is_gimple_lvalue (t) || is_gimple_val (t);
}
+/* Returns true iff T is a valid RHS for an assignment to a renamed user
+ variable. */
+
+bool
+is_gimple_reg_rhs (tree t)
+{
+ /* If the RHS of the MODIFY_EXPR may throw or make a nonlocal goto and
+ the LHS is a user variable, then we need to introduce a temporary.
+ ie temp = RHS; LHS = temp.
+
+ This way the optimizers can determine that the user variable is
+ only modified if evaluation of the RHS does not throw. */
+ if (is_gimple_reg_type (TREE_TYPE (t))
+ && TREE_SIDE_EFFECTS (t)
+ && (TREE_CODE (t) == CALL_EXPR
+ || (flag_non_call_exceptions && tree_could_trap_p (t))))
+ return is_gimple_val (t);
+ else
+ /* Don't force a temp of a non-renamable type; the copy could be
+ arbitrarily expensive. Instead we will generate a V_MAY_DEF for
+ the assignment. */
+ return is_gimple_tmp_rhs (t);
+}
+
+/* Returns true iff T is a valid RHS for an assignment to an un-renamed
+ LHS, or for a call argument. */
+
+bool
+is_gimple_mem_rhs (tree t)
+{
+ /* If we're dealing with a renamable type, either source or dest
+ must be a renamed variable. */
+ if (is_gimple_reg_type (TREE_TYPE (t)))
+ return is_gimple_val (t);
+ else
+ return is_gimple_tmp_rhs (t);
+}
+
+/* Returns the appropriate RHS predicate for this LHS. */
+
+gimple_predicate
+rhs_predicate_for (tree lhs)
+{
+ if (is_gimple_tmp_var (lhs))
+ return is_gimple_tmp_rhs;
+ else if (is_gimple_reg (lhs))
+ return is_gimple_reg_rhs;
+ else
+ return is_gimple_mem_rhs;
+}
+
/* Returns true if T is a valid CONSTRUCTOR component in GIMPLE, either
a val or another CONSTRUCTOR. */
bool
is_gimple_lvalue (tree t)
{
- return (is_gimple_addr_expr_arg (t)
- || TREE_CODE (t) == INDIRECT_REF
+ return (is_gimple_addressable (t)
+ || TREE_CODE (t) == WITH_SIZE_EXPR
/* These are complex lvalues, but don't have addresses, so they
go here. */
|| TREE_CODE (t) == BIT_FIELD_REF);
|| TREE_CODE_CLASS (TREE_CODE (t)) == '<');
}
-/* Return true if T is a valid operand for ADDR_EXPR. */
+/* Return true if T is something whose address can be taken. */
bool
-is_gimple_addr_expr_arg (tree t)
+is_gimple_addressable (tree t)
{
- return (is_gimple_id (t)
- || TREE_CODE (t) == ARRAY_REF
- || TREE_CODE (t) == ARRAY_RANGE_REF
- || TREE_CODE (t) == COMPONENT_REF
+ return (is_gimple_id (t) || handled_component_p (t)
|| TREE_CODE (t) == REALPART_EXPR
|| TREE_CODE (t) == IMAGPART_EXPR
|| TREE_CODE (t) == INDIRECT_REF);
/* These are always void. */
return true;
- case VA_ARG_EXPR:
- /* FIXME this should be lowered. */
- return true;
-
case CALL_EXPR:
case MODIFY_EXPR:
/* These are valid regardless of their type. */
return (is_gimple_variable (t)
|| TREE_CODE (t) == FUNCTION_DECL
|| TREE_CODE (t) == LABEL_DECL
+ || TREE_CODE (t) == CONST_DECL
/* Allow string constants, since they are addressable. */
|| TREE_CODE (t) == STRING_CST);
}
/* A volatile decl is not acceptable because we can't reuse it as
needed. We need to copy it into a temp first. */
&& ! TREE_THIS_VOLATILE (t)
- && ! TREE_ADDRESSABLE (t)
&& ! needs_to_live_in_memory (t));
}
+/* Returns true if T is a GIMPLE temporary variable, false otherwise. */
+
+bool
+is_gimple_tmp_var (tree t)
+{
+ /* FIXME this could trigger for other local artificials, too. */
+ return (TREE_CODE (t) == VAR_DECL && DECL_ARTIFICIAL (t)
+ && !TREE_STATIC (t) && !DECL_EXTERNAL (t));
+}
+
+/* Returns true if T is a GIMPLE temporary register variable. */
+
+bool
+is_gimple_tmp_reg (tree t)
+{
+ /* The intent of this is to get hold of a value that won't change.
+ An SSA_NAME qualifies no matter if its of a user variable or not. */
+ if (TREE_CODE (t) == SSA_NAME)
+ return true;
+
+ /* We don't know the lifetime characteristics of user variables. */
+ if (TREE_CODE (t) != VAR_DECL || !DECL_ARTIFICIAL (t))
+ return false;
+
+ /* Finally, it must be capable of being placed in a register. */
+ return is_gimple_reg (t);
+}
+
/* Return true if T is a GIMPLE variable whose address is not needed. */
bool
if (TREE_CODE (t) == SSA_NAME)
t = SSA_NAME_VAR (t);
- return (is_gimple_variable (t)
- && ! TREE_ADDRESSABLE (t)
- && ! needs_to_live_in_memory (t));
+ return (is_gimple_variable (t) && ! needs_to_live_in_memory (t));
}
/* Return true if T is a GIMPLE rvalue, i.e. an identifier or a constant. */
{
if (TREE_CODE (t) == MODIFY_EXPR)
t = TREE_OPERAND (t, 1);
+ if (TREE_CODE (t) == WITH_SIZE_EXPR)
+ t = TREE_OPERAND (t, 0);
if (TREE_CODE (t) == CALL_EXPR)
return t;
return NULL_TREE;