This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [tree-ssa] verify cond_expr condition type
> > On Sat, 17 Jan 2004 23:53:32 +0100, Jan Hubicka <hubicka@ucw.cz> wrote:
> >
> > >> As discussed re one of law's dominator changes. Fortunately my fears
> > >> were unfounded and bootstrap and check passes with this installed.
> > >
> > > Nice, but would be perhaps better to go for my verify_gimple_grammar
> > > patch? That should be place for such a checks to go
> > > (it don't do this check in current incarnation)
> >
> > It makes sense for me to keep the logic about what is or is not fully
> > simplified all in the same place, i.e. the gimplifier. I've had a patch to
> > add a speculative mode to the gimplifier in the works for a while now;
> > sorry I haven't finished it yet. I'll definitely finish it up this week.
>
> How this is different from verify_gimple_grammar idea? It basically
> implements what the grammar specify in separate function.
To be more specific, there is my patch.
I didn't updated it for current tree and re-tested but unless you have
something better to replace it, I will do so today.
Index: tree-simple.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-simple.c,v
retrieving revision 1.1.4.63
diff -c -3 -p -r1.1.4.63 tree-simple.c
*** tree-simple.c 4 Dec 2003 02:22:01 -0000 1.1.4.63
--- tree-simple.c 12 Dec 2003 01:26:52 -0000
*************** Boston, MA 02111-1307, USA. */
*** 29,34 ****
--- 29,35 ----
#include "output.h"
#include "rtl.h"
#include "expr.h"
+ #include "toplev.h"
/* GCC GIMPLE structure
*************** is_gimple_stmt (tree t)
*** 371,383 ****
}
}
/* 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);
}
--- 372,732 ----
}
}
+ /* Verify that T is valid arugment of addr_expr. */
+ static bool
+ verify_addr_expr_arg (tree t)
+ {
+ enum tree_code code;
+ bool found = false;
+ bool min_lval = false;
+
+ code = TREE_CODE (t);
+ while (code == ARRAY_REF
+ || code == COMPONENT_REF
+ || code == REALPART_EXPR
+ || code == IMAGPART_EXPR)
+ {
+ if (code == ARRAY_REF
+ && !is_gimple_val (TREE_OPERAND (t, 1)))
+ {
+ error ("called function is not ID nor &ID");
+ found = true;
+ }
+ if (code == ARRAY_REF || code == COMPONENT_REF)
+ min_lval = true;
+ else
+ min_lval = false;
+ t = TREE_OPERAND (t, 0);
+ code = TREE_CODE (t);
+ }
+ if (min_lval)
+ {
+ if (!is_gimple_min_lval (t))
+ {
+ error ("COMPONENT_REF/ARRAY_REF arg is not min_lval");
+ found = true;
+ }
+ }
+ else
+ {
+ if (!is_gimple_min_lval (t))
+ {
+ error ("addr-expr arg is not ID");
+ found = true;
+ }
+ }
+ return found;
+ }
+
+ /* Verify that T is valid gimple call_expr. */
+ static bool
+ verify_call_expr (tree t)
+ {
+ bool found = false;
+ tree op;
+ int i = 1;
+
+ if (TREE_CODE (t) != CALL_EXPR)
+ abort ();
+
+ if (!is_gimple_id (TREE_OPERAND (t, 0))
+ && TREE_CODE (TREE_OPERAND (t, 0)) != INTEGER_CST
+ && (TREE_CODE (TREE_OPERAND (t, 0)) != ADDR_EXPR
+ || !is_gimple_id (TREE_OPERAND (TREE_OPERAND (t, 0), 0))))
+ {
+ error ("called function is not ID nor &ID");
+ found = true;
+ }
+ for (op = TREE_OPERAND (t, 1); op; op = TREE_CHAIN (op), i++)
+ {
+ if (!is_gimple_val (TREE_VALUE (op))
+ /* A hack to get mark_decls_volatile_r hack working.
+ Once mark_decls_volatile_r goes out, this should go too. */
+ && ((TREE_CODE (TREE_VALUE (op)) != PARM_DECL
+ && TREE_CODE (TREE_VALUE (op)) != VAR_DECL)
+ || !TREE_THIS_VOLATILE (TREE_VALUE (op))))
+ {
+ error ("Operand %i is not val", i);
+ found = true;
+ }
+ }
+ return found;
+ }
+
+ /* Verify that T is valid gimple modify_expr. */
+ static bool
+ verify_modify_expr (tree t)
+ {
+ bool found = false;
+ tree lhs = TREE_OPERAND (t, 0);
+ tree rhs = TREE_OPERAND (t, 1);
+ if (TREE_CODE (t) != MODIFY_EXPR)
+ abort ();
+ if (!is_gimple_rhs (rhs))
+ {
+ error ("right hand side of modify_expr is not rhs");
+ found = true;
+ }
+ if (!is_gimple_min_lval (lhs)
+ && verify_addr_expr_arg (lhs))
+ {
+ error ("left hand side of modify_expr is not gimple lval");
+ found = true;
+ }
+
+ if (is_gimple_min_invariant (rhs))
+ return found;
+
+ /* ??? Probably not valid. We are producing real/imag part exprs containing
+ array refs and similar. */
+ if (TREE_CODE (rhs) == REALPART_EXPR
+ || TREE_CODE (rhs) == IMAGPART_EXPR)
+ return found;
+
+ switch (TREE_CODE_CLASS (TREE_CODE (rhs)))
+ {
+ case '1':
+ if (!is_gimple_val (TREE_OPERAND (rhs, 0)))
+ {
+ error ("operand of unary expression is not val");
+ found = true;
+ }
+ break;
+ case '2':
+ case '<':
+ if (!is_gimple_val (TREE_OPERAND (rhs, 0)))
+ {
+ error ("operand of binary expression is not val");
+ found = true;
+ }
+ if (!is_gimple_val (TREE_OPERAND (rhs, 1)))
+ {
+ error ("operand of binarry expression is not val");
+ found = true;
+ }
+ break;
+
+ default:
+ break;
+ }
+ switch (TREE_CODE (rhs))
+ {
+ case CALL_EXPR:
+ found |= verify_call_expr (rhs);
+ break;
+ case COND_EXPR:
+ /* These are only valid if they're void. */
+ if (VOID_TYPE_P (TREE_TYPE (rhs)))
+ {
+ error ("left hand side cond_expr must not be VOIDmode");
+ found = true;
+ }
+ if (TREE_CODE (COND_EXPR_THEN (rhs)) == GOTO_EXPR
+ || TREE_CODE (COND_EXPR_ELSE (rhs)) == GOTO_EXPR)
+ {
+ error ("left hand side cond_expr must contain not goto_expr.");
+ found = true;
+ }
+ if (!is_gimple_condexpr (TREE_OPERAND (rhs, 0)))
+ {
+ error ("cond_expr condition is not condexpr");
+ found = true;
+ }
+ break;
+ case VA_ARG_EXPR:
+ /* FIXME refuse later. */
+ break;
+ /* ??? More expression codes to refuse? */
+ case TRUTH_NOT_EXPR:
+ case TRUTH_AND_EXPR:
+ case TRUTH_OR_EXPR:
+ case TRUTH_XOR_EXPR:
+ if (!is_gimple_val (TREE_OPERAND (rhs, 0)))
+ {
+ error ("Non-gimple truth_* expression");
+ found = true;
+ }
+ break;
+ case ADDR_EXPR:
+ found |= verify_addr_expr_arg (TREE_OPERAND (rhs, 0));
+ break;
+ default:
+ break;
+ }
+ return found;
+ }
+
+ /* Verify that T is valid gimple statement according to the grammar specified
+ above. */
+ bool
+ verify_gimple_grammar_in_stmt (tree t)
+ {
+ enum tree_code code = TREE_CODE (t);
+ bool found = false;
+
+ if (IS_EMPTY_STMT (t))
+ return false;
+
+ switch (code)
+ {
+ case BIND_EXPR:
+ /* These are only valid if they're void. */
+ if (!VOID_TYPE_P (TREE_TYPE (t)))
+ {
+ error ("bind_expr shall not appear in low level gimple");
+ found = true;
+ }
+ break;
+ case COND_EXPR:
+ /* These are only valid if they're void. */
+ if (!VOID_TYPE_P (TREE_TYPE (t)))
+ {
+ error ("statement level cond_expr must be VOIDmode");
+ found = true;
+ }
+ if (TREE_CODE (COND_EXPR_THEN (t)) != GOTO_EXPR
+ || TREE_CODE (COND_EXPR_ELSE (t)) != GOTO_EXPR)
+ {
+ error ("statement level cond_expr must contain goto_expr in both arms.");
+ found = true;
+ }
+ if (!is_gimple_condexpr (TREE_OPERAND (t, 0)))
+ {
+ error ("cond_expr condition is not condexpr");
+ found = true;
+ }
+ /* Verify goto expr to have label operand? */
+ break;
+
+ case SWITCH_EXPR:
+ {
+ tree op = TREE_OPERAND (t, 0);
+
+ /* ??? As a hack in gimplifier we allow nop to get warnings right.
+ Fix this. */
+ if (TREE_CODE (op) == NOP_EXPR)
+ op = TREE_OPERAND (op, 0);
+ if (!is_gimple_val (op))
+ {
+ error ("switch_expr oprand is not value");
+ found = true;
+ }
+ }
+ if (TREE_OPERAND (t, 1))
+ {
+ error ("switch_expr statement list is nonempty");
+ found = true;
+ }
+ /* Verify label list? */
+ break;
+ case GOTO_EXPR:
+ if (TREE_CODE (TREE_OPERAND (t, 0)) != LABEL_DECL
+ && !is_gimple_val (TREE_OPERAND (t, 0)))
+ {
+ error ("goto_expr is not label nor value");
+ found = true;
+ }
+ break;
+ case RETURN_EXPR:
+ if (TREE_OPERAND (t, 0))
+ {
+ if (TREE_CODE (TREE_OPERAND (t, 0)) == MODIFY_EXPR)
+ found |= verify_modify_expr (TREE_OPERAND (t, 0));
+ else
+ {
+ error ("return_expr operand is not gimple value nor modify_expr");
+ found = true;
+ }
+ }
+ break;
+ case LABEL_EXPR:
+ case CASE_LABEL_EXPR:
+ break;
+ case PHI_NODE:
+ /* Phi nodes are sanity checked by verify_ssa. */
+ break;
+ case TRY_CATCH_EXPR:
+ case TRY_FINALLY_EXPR:
+ case EH_FILTER_EXPR:
+ case CATCH_EXPR:
+ case RESX_EXPR:
+ case VA_ARG_EXPR:
+ /* ??? What shall be here? */
+ break;
+ case STATEMENT_LIST:
+ /* There should be no need to verify statement_list ad we are always
+ called to inner operands only. */
+ abort ();
+ break;
+ case ASM_EXPR:
+ {
+ int i;
+ tree link;
+ bool allows_mem, allows_reg, is_inout;
+ const char *constraint;
+ int noutputs = list_length (ASM_OUTPUTS (t));
+ const char **oconstraints
+ = (const char **) alloca ((noutputs) * sizeof (const char *));
+
+ for (i=0, link = ASM_OUTPUTS (t); link;
+ ++i, link = TREE_CHAIN (link))
+ {
+ noutputs++;
+ oconstraints[i] = constraint
+ = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
+ parse_output_constraint (&constraint, i, 0, 0,
+ &allows_mem, &allows_reg, &is_inout);
+ if ((allows_reg && !is_gimple_min_lval (TREE_VALUE (link)))
+ && (allows_mem && verify_addr_expr_arg (TREE_VALUE (link))))
+ {
+ error ("output operand %i is not gimple lval", i);
+ found = true;
+ }
+ }
+ for (i=0, link = ASM_INPUTS (t); link;
+ ++i, link = TREE_CHAIN (link))
+ {
+ constraint
+ = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
+ parse_input_constraint (&constraint, 0, 0, noutputs, 0,
+ oconstraints, &allows_mem, &allows_reg);
+ if ((allows_reg && !is_gimple_val (TREE_VALUE (link)))
+ && (allows_mem && verify_addr_expr_arg (TREE_VALUE (link))))
+ {
+ error ("output operand %i is not gimple val", i);
+ found = true;
+ }
+ }
+ }
+ break;
+
+ case CALL_EXPR:
+ found |= verify_call_expr (t);
+ break;
+ case MODIFY_EXPR:
+ found |= verify_modify_expr (t);
+ break;
+
+ default:
+ error ("Invalid statement expression");
+ found = true;
+ break;
+ }
+ return found;
+ }
+
/* Return nonzero if T is a variable. */
bool
is_gimple_variable (tree t)
{
+ /* Disqualify arguments passed by invisible reference. These are de-facto
+ INDIRECT_REFs. */
+ if (TREE_CODE (t) == PARM_DECL)
+ return (DECL_ARG_TYPE (t) == TREE_TYPE (t)
+ || !POINTER_TYPE_P (DECL_ARG_TYPE (t))
+ || TREE_TYPE (DECL_ARG_TYPE (t)) != TREE_TYPE (t));
return (TREE_CODE (t) == VAR_DECL
|| TREE_CODE (t) == RESULT_DECL
|| TREE_CODE (t) == SSA_NAME);
}