X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Ftree-gimple.c;h=e723b47217785948664b37756061f8a850318cd1;hb=576aff9d272cd8ebec2b93b10dcf5eae125e9667;hp=7e4c14b534814070aede3855f9e871b87b73f24b;hpb=f0ac919b1f8f69ca28c569ed17560962d5d45076;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/tree-gimple.c b/gcc/tree-gimple.c index 7e4c14b5348..e723b472177 100644 --- a/gcc/tree-gimple.c +++ b/gcc/tree-gimple.c @@ -1,5 +1,5 @@ /* Functions to analyze and validate GIMPLE trees. - Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. Contributed by Diego Novillo Rewritten by Jason Merrill @@ -27,163 +27,30 @@ Boston, MA 02111-1307, USA. */ #include "tm.h" #include "tree.h" #include "tree-gimple.h" +#include "tree-flow.h" #include "output.h" #include "rtl.h" #include "expr.h" #include "bitmap.h" -/* GCC GIMPLE structure - - Inspired by the SIMPLE C grammar at - - http://www-acaps.cs.mcgill.ca/info/McCAT/McCAT.html - - function : FUNCTION_DECL - DECL_SAVED_TREE -> compound-stmt - - compound-stmt: STATEMENT_LIST - members -> stmt - - stmt : block - | if-stmt - | switch-stmt - | goto-stmt - | return-stmt - | resx-stmt - | label-stmt - | try-stmt - | modify-stmt - | call-stmt - - block : BIND_EXPR - BIND_EXPR_VARS -> chain of DECLs - BIND_EXPR_BLOCK -> BLOCK - BIND_EXPR_BODY -> compound-stmt - - if-stmt : COND_EXPR - op0 -> condition - op1 -> compound-stmt - op2 -> compound-stmt - - switch-stmt : SWITCH_EXPR - op0 -> val - op1 -> NULL - op2 -> TREE_VEC of CASE_LABEL_EXPRs - The CASE_LABEL_EXPRs are sorted by CASE_LOW, - and default is last. - - goto-stmt : GOTO_EXPR - op0 -> LABEL_DECL | val - - return-stmt : RETURN_EXPR - op0 -> return-value - - return-value : NULL - | RESULT_DECL - | MODIFY_EXPR - op0 -> RESULT_DECL - op1 -> lhs - - resx-stmt : RESX_EXPR - - label-stmt : LABEL_EXPR - op0 -> LABEL_DECL - - try-stmt : TRY_CATCH_EXPR - op0 -> compound-stmt - op1 -> handler - | TRY_FINALLY_EXPR - op0 -> compound-stmt - op1 -> compound-stmt - - handler : catch-seq - | EH_FILTER_EXPR - | compound-stmt - - catch-seq : STATEMENT_LIST - members -> CATCH_EXPR - - modify-stmt : MODIFY_EXPR - op0 -> lhs - op1 -> rhs - - call-stmt : CALL_EXPR - op0 -> val | OBJ_TYPE_REF - op1 -> call-arg-list - - call-arg-list: TREE_LIST - members -> lhs - - addr-expr-arg: ID - | compref - - lhs : addr-expr-arg - | '*' val - | bitfieldref - - min-lval : ID - | '*' val - - bitfieldref : BIT_FIELD_REF - op0 -> inner-compref - op1 -> CONST - op2 -> var - - compref : inner-compref - | REALPART_EXPR - op0 -> inner-compref - | IMAGPART_EXPR - op0 -> inner-compref - - inner-compref: min-lval - | COMPONENT_REF - op0 -> inner-compref - op1 -> FIELD_DECL - op2 -> val - | ARRAY_REF - op0 -> inner-compref - op1 -> val - op2 -> val - op3 -> val - | ARRAY_RANGE_REF - op0 -> inner-compref - op1 -> val - op2 -> val - op3 -> val - | VIEW_CONVERT_EXPR - op0 -> inner-compref - - condition : val - | val RELOP val - - val : ID - | CONST - - rhs : lhs - | CONST - | '&' addr-expr-arg - | call_expr - | UNOP val - | val BINOP val - | val RELOP val -*/ +/* For the definitive definition of GIMPLE, see doc/tree-ssa.texi. */ 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_formal_tmp_rhs (tree t) { enum tree_code code = TREE_CODE (t); switch (TREE_CODE_CLASS (code)) { - case '1': - case '2': - case '<': + case tcc_unary: + case tcc_binary: + case tcc_comparison: return true; default: @@ -200,14 +67,13 @@ is_gimple_rhs (tree 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: case COMPLEX_CST: case VECTOR_CST: case OBJ_TYPE_REF: + case ASSERT_EXPR: return true; default: @@ -217,14 +83,57 @@ is_gimple_rhs (tree t) return is_gimple_lvalue (t) || is_gimple_val (t); } -/* Returns true if T is a valid CONSTRUCTOR component in GIMPLE, either - a val or another CONSTRUCTOR. */ +/* Returns true iff T is a valid RHS for an assignment to a renamed + user -- or front-end generated artificial -- variable. */ bool -is_gimple_constructor_elt (tree t) +is_gimple_reg_rhs (tree t) { - return (is_gimple_val (t) - || TREE_CODE (t) == CONSTRUCTOR); + /* 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 formal + temporary. This way the optimizers can determine that the user + variable is only modified if evaluation of the RHS does not throw. + + 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. */ + + if (is_gimple_reg_type (TREE_TYPE (t)) + && ((TREE_CODE (t) == CALL_EXPR && TREE_SIDE_EFFECTS (t)) + || tree_could_throw_p (t))) + return false; + + return is_gimple_formal_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. Also force a temporary if the type doesn't need + to be stored in memory, since it's cheap and prevents erroneous + tailcalls (PR 17526). */ + if (is_gimple_reg_type (TREE_TYPE (t)) + || TYPE_MODE (TREE_TYPE (t)) != BLKmode) + return is_gimple_val (t); + else + return is_gimple_formal_tmp_rhs (t); +} + +/* Returns the appropriate RHS predicate for this LHS. */ + +gimple_predicate +rhs_predicate_for (tree lhs) +{ + if (is_gimple_formal_tmp_var (lhs)) + return is_gimple_formal_tmp_rhs; + else if (is_gimple_reg (lhs)) + return is_gimple_reg_rhs; + else + return is_gimple_mem_rhs; } /* Return true if T is a valid LHS for a GIMPLE assignment expression. */ @@ -232,8 +141,8 @@ is_gimple_constructor_elt (tree t) 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); @@ -244,22 +153,16 @@ is_gimple_lvalue (tree t) bool is_gimple_condexpr (tree t) { - return (is_gimple_val (t) - || TREE_CODE_CLASS (TREE_CODE (t)) == '<'); + return (is_gimple_val (t) || COMPARISON_CLASS_P (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 - || TREE_CODE (t) == REALPART_EXPR - || TREE_CODE (t) == IMAGPART_EXPR - || TREE_CODE (t) == INDIRECT_REF); + return (is_gimple_id (t) || handled_component_p (t) + || INDIRECT_REF_P (t)); } /* Return true if T is function invariant. Or rather a restricted @@ -278,7 +181,7 @@ is_gimple_min_invariant (tree t) case STRING_CST: case COMPLEX_CST: case VECTOR_CST: - return !TREE_OVERFLOW (t); + return true; default: return false; @@ -318,10 +221,6 @@ is_gimple_stmt (tree t) /* 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. */ @@ -351,6 +250,7 @@ is_gimple_id (tree t) 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); } @@ -373,13 +273,64 @@ is_gimple_reg (tree t) if (TREE_CODE (t) == SSA_NAME) t = SSA_NAME_VAR (t); - return (is_gimple_variable (t) - && is_gimple_reg_type (TREE_TYPE (t)) - /* 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)); + if (!is_gimple_variable (t)) + return false; + if (!is_gimple_reg_type (TREE_TYPE (t))) + return false; + + /* A volatile decl is not acceptable because we can't reuse it as + needed. We need to copy it into a temp first. */ + if (TREE_THIS_VOLATILE (t)) + return false; + + /* We define "registers" as things that can be renamed as needed, + which with our infrastructure does not apply to memory. */ + if (needs_to_live_in_memory (t)) + return false; + + /* Hard register variables are an interesting case. For those that + are call-clobbered, we don't know where all the calls are, since + we don't (want to) take into account which operations will turn + into libcalls at the rtl level. For those that are call-saved, + we don't currently model the fact that calls may in fact change + global hard registers, nor do we examine ASM_CLOBBERS at the tree + level, and so miss variable changes that might imply. All around, + it seems safest to not do too much optimization with these at the + tree level at all. We'll have to rely on the rtl optimizers to + clean this up, as there we've got all the appropriate bits exposed. */ + if (TREE_CODE (t) == VAR_DECL && DECL_HARD_REGISTER (t)) + return false; + + return true; +} + +/* Returns true if T is a GIMPLE formal temporary variable. */ + +bool +is_gimple_formal_tmp_var (tree t) +{ + if (TREE_CODE (t) == SSA_NAME) + return true; + + return TREE_CODE (t) == VAR_DECL && DECL_GIMPLE_FORMAL_TEMP_P (t); +} + +/* Returns true if T is a GIMPLE formal temporary register variable. */ + +bool +is_gimple_formal_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 (!is_gimple_formal_tmp_var (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. */ @@ -390,9 +341,7 @@ is_gimple_non_addressable (tree t) 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. */ @@ -414,6 +363,16 @@ is_gimple_val (tree t) return (is_gimple_variable (t) || is_gimple_min_invariant (t)); } +/* Similarly, but accept hard registers as inputs to asm statements. */ + +bool +is_gimple_asm_val (tree t) +{ + if (TREE_CODE (t) == VAR_DECL && DECL_HARD_REGISTER (t)) + return true; + + return is_gimple_val (t); +} /* Return true if T is a GIMPLE minimal lvalue. */ @@ -454,27 +413,32 @@ get_call_expr_in (tree t) { 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; } -/* Given a memory reference expression, return the base address. Note that, - in contrast with get_base_var, this will not recurse inside INDIRECT_REF - expressions. Therefore, given the reference PTR->FIELD, this function - will return *PTR. Whereas get_base_var would've returned PTR. */ +/* Given a memory reference expression T, return its base address. + The base address of a memory reference expression is the main + object being referenced. For instance, the base address for + 'array[i].fld[j]' is 'array'. You can think of this as stripping + away the offset part from a memory address. + + This function calls handled_component_p to strip away all the inner + parts of the memory reference until it reaches the base object. */ tree get_base_address (tree t) { - while (TREE_CODE (t) == REALPART_EXPR || TREE_CODE (t) == IMAGPART_EXPR - || handled_component_p (t)) + while (handled_component_p (t)) t = TREE_OPERAND (t, 0); if (SSA_VAR_P (t) || TREE_CODE (t) == STRING_CST || TREE_CODE (t) == CONSTRUCTOR - || TREE_CODE (t) == INDIRECT_REF) + || INDIRECT_REF_P (t)) return t; else return NULL_TREE; @@ -484,18 +448,17 @@ void recalculate_side_effects (tree t) { enum tree_code code = TREE_CODE (t); - int fro = first_rtl_op (code); + int len = TREE_CODE_LENGTH (code); int i; switch (TREE_CODE_CLASS (code)) { - case 'e': + case tcc_expression: switch (code) { case INIT_EXPR: case MODIFY_EXPR: case VA_ARG_EXPR: - case RTL_EXPR: case PREDECREMENT_EXPR: case PREINCREMENT_EXPR: case POSTDECREMENT_EXPR: @@ -509,17 +472,21 @@ recalculate_side_effects (tree t) } /* Fall through. */ - case '<': /* a comparison expression */ - case '1': /* a unary arithmetic expression */ - case '2': /* a binary arithmetic expression */ - case 'r': /* a reference */ + case tcc_comparison: /* a comparison expression */ + case tcc_unary: /* a unary arithmetic expression */ + case tcc_binary: /* a binary arithmetic expression */ + case tcc_reference: /* a reference */ TREE_SIDE_EFFECTS (t) = TREE_THIS_VOLATILE (t); - for (i = 0; i < fro; ++i) + for (i = 0; i < len; ++i) { tree op = TREE_OPERAND (t, i); if (op && TREE_SIDE_EFFECTS (op)) TREE_SIDE_EFFECTS (t) = 1; } break; + + default: + /* Can never be used with non-expressions. */ + gcc_unreachable (); } }