summaryrefslogtreecommitdiff
path: root/gcc/tree-gimple.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/tree-gimple.c')
-rw-r--r--gcc/tree-gimple.c642
1 files changed, 642 insertions, 0 deletions
diff --git a/gcc/tree-gimple.c b/gcc/tree-gimple.c
new file mode 100644
index 00000000000..dbe2966e1e9
--- /dev/null
+++ b/gcc/tree-gimple.c
@@ -0,0 +1,642 @@
+/* Functions to analyze and validate GIMPLE trees.
+ Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+ Contributed by Diego Novillo <dnovillo@redhat.com>
+ Rewritten by Jason Merrill <jason@redhat.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "ggc.h"
+#include "tm.h"
+#include "tree.h"
+#include "tree-gimple.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 -> block
+ block:
+ BIND_EXPR
+ BIND_EXPR_VARS -> DECL chain
+ BIND_EXPR_BLOCK -> BLOCK
+ BIND_EXPR_BODY -> compound-stmt
+ compound-stmt:
+ COMPOUND_EXPR
+ op0 -> non-compound-stmt
+ op1 -> stmt
+ | EXPR_VEC
+ (or other alternate solution)
+ stmt: compound-stmt | non-compound-stmt
+ non-compound-stmt:
+ block
+ | if-stmt
+ | switch-stmt
+ | jump-stmt
+ | label-stmt
+ | try-stmt
+ | modify-stmt
+ | call-stmt
+ if-stmt:
+ COND_EXPR
+ op0 -> condition
+ op1 -> stmt
+ op2 -> stmt
+ switch-stmt:
+ SWITCH_EXPR
+ op0 -> val
+ op1 -> stmt
+ op2 -> array of case labels (as LABEL_DECLs?)
+ FIXME: add case value info
+ jump-stmt:
+ GOTO_EXPR
+ op0 -> LABEL_DECL | '*' ID
+ | RETURN_EXPR
+ op0 -> modify-stmt | NULL_TREE
+ (maybe -> RESULT_DECL | NULL_TREE? seems like some of expand_return
+ depends on getting a MODIFY_EXPR.)
+ | THROW_EXPR? do we need/want such a thing for opts, perhaps
+ to generate an ERT_THROW region? I think so.
+ Hmm...this would only work at the GIMPLE level, where we know that
+ the call args don't have any EH impact. Perhaps
+ annotation of the CALL_EXPR would work better.
+ | RESX_EXPR
+ label-stmt:
+ LABEL_EXPR
+ op0 -> LABEL_DECL
+ | CASE_LABEL_EXPR
+ CASE_LOW -> val | NULL_TREE
+ CASE_HIGH -> val | NULL_TREE
+ CASE_LABEL -> LABEL_DECL FIXME
+ try-stmt:
+ TRY_CATCH_EXPR
+ op0 -> stmt
+ op1 -> handler
+ | TRY_FINALLY_EXPR
+ op0 -> stmt
+ op1 -> stmt
+ handler:
+ catch-seq
+ | EH_FILTER_EXPR
+ | stmt
+ modify-stmt:
+ MODIFY_EXPR
+ op0 -> lhs
+ op1 -> rhs
+ call-stmt: CALL_EXPR
+ op0 -> ID | '&' ID
+ op1 -> arglist
+
+ addr-expr-arg : compref | ID
+ lhs: addr-expr-arg | '*' ID | bitfieldref
+ min-lval: ID | '*' ID
+ bitfieldref :
+ BIT_FIELD_REF
+ op0 -> compref | min-lval
+ op1 -> CONST
+ op2 -> CONST
+ compref :
+ COMPONENT_REF
+ op0 -> compref | min-lval
+ | ARRAY_REF
+ op0 -> compref | min-lval
+ op1 -> val
+ | REALPART_EXPR
+ | IMAGPART_EXPR
+
+ condition : val | val relop val
+ val : ID | CONST
+
+ rhs : varname | CONST
+ | '*' ID
+ | '&' addr-expr-arg
+ | call_expr
+ | unop val
+ | val binop val
+ | '(' cast ')' val
+
+ (cast here stands for all valid C typecasts)
+
+ unop
+ : '+'
+ | '-'
+ | '!'
+ | '~'
+
+ binop
+ : relop | '-'
+ | '+'
+ | '/'
+ | '*'
+ | '%'
+ | '&'
+ | '|'
+ | '<<'
+ | '>>'
+ | '^'
+
+ relop
+ : '<'
+ | '<='
+ | '>'
+ | '>='
+ | '=='
+ | '!='
+
+*/
+
+static inline bool is_gimple_id (tree);
+
+/* Validation of GIMPLE expressions. */
+
+/* Return nonzero if T is a GIMPLE RHS:
+
+ rhs : varname | CONST
+ | '*' ID
+ | '&' varname_or_temp
+ | call_expr
+ | unop val
+ | val binop val
+ | '(' cast ')' val
+ | <CONSTRUCTOR <gimple_val ...>>
+
+ The last option is only valid GIMPLE for vector and complex types;
+ aggregate types should have their constructors decomposed. */
+
+bool
+is_gimple_rhs (tree t)
+{
+ enum tree_code code = TREE_CODE (t);
+
+ switch (TREE_CODE_CLASS (code))
+ {
+ case '1':
+ case '2':
+ case '<':
+ return 1;
+
+ default:
+ break;
+ }
+
+ switch (code)
+ {
+ case TRUTH_NOT_EXPR:
+ case TRUTH_AND_EXPR:
+ case TRUTH_OR_EXPR:
+ case TRUTH_XOR_EXPR:
+ case ADDR_EXPR:
+ 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:
+ return 1;
+
+ default:
+ break;
+ }
+
+ if (is_gimple_lvalue (t) || is_gimple_val (t))
+ return 1;
+
+ return 0;
+}
+
+/* Returns nonzero if T is a valid CONSTRUCTOR component in GIMPLE, either
+ a val or another CONSTRUCTOR. */
+
+bool
+is_gimple_constructor_elt (tree t)
+{
+ return (is_gimple_val (t)
+ || TREE_CODE (t) == CONSTRUCTOR);
+}
+
+/* Return nonzero if T is a valid LHS for a GIMPLE assignment expression. */
+
+bool
+is_gimple_lvalue (tree t)
+{
+ return (is_gimple_addr_expr_arg (t)
+ || TREE_CODE (t) == INDIRECT_REF
+ /* These are complex lvalues, but don't have addresses, so they
+ go here. */
+ || TREE_CODE (t) == BIT_FIELD_REF);
+}
+
+
+/* Return nonzero if T is a GIMPLE condition:
+
+ condexpr
+ : val
+ | val relop val */
+
+bool
+is_gimple_condexpr (tree t)
+{
+ return (is_gimple_val (t)
+ || TREE_CODE_CLASS (TREE_CODE (t)) == '<');
+}
+
+
+/* Return nonzero if T is a valid operand for '&':
+
+ varname
+ : arrayref
+ | compref
+ | ID */
+
+bool
+is_gimple_addr_expr_arg (tree t)
+{
+ return (is_gimple_id (t)
+ || TREE_CODE (t) == ARRAY_REF
+ || TREE_CODE (t) == COMPONENT_REF
+ || TREE_CODE (t) == REALPART_EXPR
+ || TREE_CODE (t) == IMAGPART_EXPR);
+}
+
+/* Return nonzero if T is function invariant. Or rather a restricted
+ form of function invariant. */
+
+bool
+is_gimple_min_invariant (tree t)
+{
+ switch (TREE_CODE (t))
+ {
+ case ADDR_EXPR:
+ return TREE_INVARIANT (t);
+
+ case INTEGER_CST:
+ case REAL_CST:
+ case STRING_CST:
+ case COMPLEX_CST:
+ case VECTOR_CST:
+ return !TREE_OVERFLOW (t);
+
+ default:
+ return false;
+ }
+}
+
+/* Return nonzero if T looks like a valid GIMPLE statement. */
+
+bool
+is_gimple_stmt (tree t)
+{
+ enum tree_code code = TREE_CODE (t);
+
+ if (IS_EMPTY_STMT (t))
+ return 1;
+
+ switch (code)
+ {
+ case BIND_EXPR:
+ case COND_EXPR:
+ /* These are only valid if they're void. */
+ return VOID_TYPE_P (TREE_TYPE (t));
+
+ case SWITCH_EXPR:
+ case GOTO_EXPR:
+ case RETURN_EXPR:
+ case LABEL_EXPR:
+ case CASE_LABEL_EXPR:
+ case TRY_CATCH_EXPR:
+ case TRY_FINALLY_EXPR:
+ case EH_FILTER_EXPR:
+ case CATCH_EXPR:
+ case ASM_EXPR:
+ case RESX_EXPR:
+ case PHI_NODE:
+ case STATEMENT_LIST:
+ /* These are always void. */
+ return 1;
+
+ case VA_ARG_EXPR:
+ /* FIXME this should be lowered. */
+ return 1;
+
+ case COMPOUND_EXPR:
+ /* FIXME should we work harder to make COMPOUND_EXPRs void? */
+ case CALL_EXPR:
+ case MODIFY_EXPR:
+ /* These are valid regardless of their type. */
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+/* Return nonzero if T is a variable. */
+
+bool
+is_gimple_variable (tree t)
+{
+ return (TREE_CODE (t) == VAR_DECL
+ || TREE_CODE (t) == PARM_DECL
+ || TREE_CODE (t) == RESULT_DECL
+ || TREE_CODE (t) == SSA_NAME);
+}
+
+/* Return nonzero if T is a GIMPLE identifier (something with an address). */
+
+static inline bool
+is_gimple_id (tree t)
+{
+ return (is_gimple_variable (t)
+ || TREE_CODE (t) == FUNCTION_DECL
+ || TREE_CODE (t) == LABEL_DECL
+ /* Allow string constants, since they are addressable. */
+ || TREE_CODE (t) == STRING_CST);
+}
+
+/* Return nonzero if TYPE is a suitable type for a scalar register
+ variable. */
+
+bool
+is_gimple_reg_type (tree type)
+{
+ return (!AGGREGATE_TYPE_P (type)
+ && TREE_CODE (type) != COMPLEX_TYPE);
+}
+
+
+/* Return nonzero if T is a scalar register variable. */
+
+bool
+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));
+}
+
+/* Return nonzero if T is a GIMPLE variable whose address is not needed. */
+
+bool
+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 nonzero if T is a GIMPLE rvalue, i.e. an identifier or a
+ constant. */
+
+bool
+is_gimple_val (tree t)
+{
+ /* Make loads from volatiles and memory vars explicit. */
+ if (is_gimple_variable (t)
+ && is_gimple_reg_type (TREE_TYPE (t))
+ && !is_gimple_reg (t))
+ return 0;
+
+ /* FIXME make these decls. That can happen only when we expose the
+ entire landing-pad construct at the tree level. */
+ if (TREE_CODE (t) == EXC_PTR_EXPR || TREE_CODE (t) == FILTER_EXPR)
+ return 1;
+
+ return (is_gimple_variable (t) || is_gimple_min_invariant (t));
+}
+
+
+/* Return true if T is a GIMPLE minimal lvalue, of the form
+
+ min_lval: ID | '(' '*' ID ')'
+
+ This never actually appears in the original SIMPLE grammar, but is
+ repeated in several places. */
+
+bool
+is_gimple_min_lval (tree t)
+{
+ return (is_gimple_id (t)
+ || TREE_CODE (t) == INDIRECT_REF);
+}
+
+/* Return nonzero if T is a typecast operation of the form
+ '(' cast ')' val. */
+
+bool
+is_gimple_cast (tree t)
+{
+ return (TREE_CODE (t) == NOP_EXPR
+ || TREE_CODE (t) == CONVERT_EXPR
+ || TREE_CODE (t) == FIX_TRUNC_EXPR
+ || TREE_CODE (t) == FIX_CEIL_EXPR
+ || TREE_CODE (t) == FIX_FLOOR_EXPR
+ || TREE_CODE (t) == FIX_ROUND_EXPR);
+}
+
+
+/* If T makes a function call, return the corresponding CALL_EXPR operand.
+ Otherwise, return NULL_TREE. */
+
+tree
+get_call_expr_in (tree t)
+{
+ if (TREE_CODE (t) == CALL_EXPR)
+ return t;
+ else if (TREE_CODE (t) == MODIFY_EXPR
+ && TREE_CODE (TREE_OPERAND (t, 1)) == CALL_EXPR)
+ return TREE_OPERAND (t, 1);
+ else if (TREE_CODE (t) == RETURN_EXPR
+ && TREE_OPERAND (t, 0)
+ && TREE_CODE (TREE_OPERAND (t, 0)) == MODIFY_EXPR
+ && TREE_CODE (TREE_OPERAND (TREE_OPERAND (t, 0), 1)) == CALL_EXPR)
+ return TREE_OPERAND (TREE_OPERAND (t, 0), 1);
+
+ return NULL_TREE;
+}
+
+
+/* Given an _EXPR TOP, reorganize all of the nested _EXPRs with the same
+ code so that they only appear as the second operand. This should only
+ be used for tree codes which are truly associative, such as
+ COMPOUND_EXPR and TRUTH_ANDIF_EXPR. Arithmetic is not associative
+ enough, due to the limited precision of arithmetic data types.
+
+ This transformation is conservative; the operand 0 of a matching tree
+ node will only change if it is also a matching node. */
+
+tree
+right_assocify_expr (tree top)
+{
+ tree *p = &top;
+ enum tree_code code = TREE_CODE (*p);
+ while (TREE_CODE (*p) == code)
+ {
+ tree cur = *p;
+ tree lhs = TREE_OPERAND (cur, 0);
+ if (TREE_CODE (lhs) == code)
+ {
+ /* There's a left-recursion. If we have ((a, (b, c)), d), we
+ want to rearrange to (a, (b, (c, d))). */
+ tree *q;
+
+ /* Replace cur with the lhs; move (a, *) up. */
+ *p = lhs;
+
+ if (code == COMPOUND_EXPR)
+ {
+ /* We need to give (b, c) the type of c; previously lhs had
+ the type of b. */
+ TREE_TYPE (lhs) = TREE_TYPE (cur);
+ if (TREE_SIDE_EFFECTS (cur))
+ TREE_SIDE_EFFECTS (lhs) = 1;
+ }
+
+ /* Walk through the op1 chain from there until we find something
+ with a different code. In this case, c. */
+ for (q = &TREE_OPERAND (lhs, 1); TREE_CODE (*q) == code;
+ q = &TREE_OPERAND (*q, 1))
+ TREE_TYPE (*q) = TREE_TYPE (cur);
+
+ /* Change (*, d) into (c, d). */
+ TREE_OPERAND (cur, 0) = *q;
+
+ /* And plug it in where c used to be. */
+ *q = cur;
+ }
+ else
+ p = &TREE_OPERAND (cur, 1);
+ }
+ return top;
+}
+
+/* Normalize the statement TOP. If it is a COMPOUND_EXPR, reorganize it so
+ that we can traverse it without recursion. If it is null, replace it
+ with a nop. */
+
+tree
+rationalize_compound_expr (tree top)
+{
+ if (top == NULL_TREE)
+ top = build_empty_stmt ();
+ else if (TREE_CODE (top) == COMPOUND_EXPR)
+ top = right_assocify_expr (top);
+
+ return top;
+}
+
+/* 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. */
+
+tree
+get_base_address (tree t)
+{
+ do
+ {
+ if (SSA_VAR_P (t)
+ || TREE_CODE (t) == INDIRECT_REF)
+ return t;
+
+ switch (TREE_CODE (t))
+ {
+ case ARRAY_REF:
+ case COMPONENT_REF:
+ case REALPART_EXPR:
+ case IMAGPART_EXPR:
+ case BIT_FIELD_REF:
+ t = TREE_OPERAND (t, 0);
+ break;
+
+ default:
+ return NULL_TREE;
+ }
+ }
+ while (t);
+
+ return t;
+}
+
+
+void
+recalculate_side_effects (tree t)
+{
+ enum tree_code code = TREE_CODE (t);
+ int fro = first_rtl_op (code);
+ int i;
+
+ switch (TREE_CODE_CLASS (code))
+ {
+ case 'e':
+ switch (code)
+ {
+ case INIT_EXPR:
+ case MODIFY_EXPR:
+ case VA_ARG_EXPR:
+ case RTL_EXPR:
+ case PREDECREMENT_EXPR:
+ case PREINCREMENT_EXPR:
+ case POSTDECREMENT_EXPR:
+ case POSTINCREMENT_EXPR:
+ /* All of these have side-effects, no matter what their
+ operands are. */
+ return;
+
+ default:
+ break;
+ }
+ /* Fall through. */
+
+ case '<': /* a comparison expression */
+ case '1': /* a unary arithmetic expression */
+ case '2': /* a binary arithmetic expression */
+ case 'r': /* a reference */
+ TREE_SIDE_EFFECTS (t) = TREE_THIS_VOLATILE (t);
+ for (i = 0; i < fro; ++i)
+ {
+ tree op = TREE_OPERAND (t, i);
+ if (op && TREE_SIDE_EFFECTS (op))
+ TREE_SIDE_EFFECTS (t) = 1;
+ }
+ break;
+ }
+}