This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[stree-ssa] Gimple grammar checking
- From: Jan Hubicka <jh at suse dot cz>
- To: gcc-patches at gcc dot gnu dot org, dnovillo at redhat dot com
- Date: Sat, 13 Dec 2003 16:21:13 +0100
- Subject: [stree-ssa] Gimple grammar checking
Hi,
this patch implement gimple grammar checking. At the moment it causes
bootstrap failure in libjava, after fixing the inliner problem I sent
RFC patch about it still causes failure in stringopt-1.c in C testsuite
(I also sent question about this by separate mail).
Except these two, there are some exceptions allowed in the checker
itself for problems that seemed as temporary workarounds to me. I would
welcome any comments especially where the checker can be made more
strict.
Honza
2003-12-13 Jan Hubicka <jh@suse.cz>
* tree-cfg.c (verify_stmt): Call verify_gimple_grammer_in_stmt.
* tree-simple.c: Inlude toplev.h
(verify_addr_expr_arg, verify_call_expr, verify_modify_expr): New
static functions.
(verify_gimple_grammar_in_stmt): New global function.
(is_gimple_id): Acccept FILTER_EXPR and EXC_PTR_EXPR
* tree-simple.h (verify_gimple_grammer_in_stmt): Declare.
Index: tree-cfg.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-cfg.c,v
retrieving revision 1.1.4.235
diff -c -3 -p -r1.1.4.235 tree-cfg.c
*** tree-cfg.c 11 Dec 2003 01:29:50 -0000 1.1.4.235
--- tree-cfg.c 13 Dec 2003 15:02:11 -0000
*************** verify_stmt (tree stmt)
*** 2786,2794 ****
{
tree addr;
! if (!is_gimple_stmt (stmt))
{
- error ("Is not valid gimple statement.");
debug_generic_stmt (stmt);
return true;
}
--- 2786,2793 ----
{
tree addr;
! if (verify_gimple_grammar_in_stmt (stmt))
{
debug_generic_stmt (stmt);
return true;
}
Index: tree-simple.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-simple.c,v
retrieving revision 1.1.4.65
diff -c -3 -p -r1.1.4.65 tree-simple.c
*** tree-simple.c 10 Dec 2003 21:43:52 -0000 1.1.4.65
--- tree-simple.c 13 Dec 2003 15:02:12 -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,376 ****
--- 372,723 ----
}
}
+ /* 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_id (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
+ || verify_addr_expr_arg (TREE_OPERAND (TREE_OPERAND (t, 0), 0)))
+ || !is_gimple_id (TREE_OPERAND (TREE_OPERAND (t, 0), 0))))
+ {
+ error ("called function is not ID nor &addr-expr-arg");
+ 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)) == RESULT_DECL)
+ ;
+ else 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_id (tree t)
*** 390,395 ****
--- 737,744 ----
return (is_gimple_variable (t)
|| TREE_CODE (t) == FUNCTION_DECL
|| TREE_CODE (t) == LABEL_DECL
+ || TREE_CODE (t) == EXC_PTR_EXPR
+ || TREE_CODE (t) == FILTER_EXPR
/* Allow string constants, since they are addressable. */
|| TREE_CODE (t) == STRING_CST);
}
Index: tree-simple.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-simple.h,v
retrieving revision 1.1.4.44
diff -c -3 -p -r1.1.4.44 tree-simple.h
*** tree-simple.h 7 Dec 2003 10:07:45 -0000 1.1.4.44
--- tree-simple.h 13 Dec 2003 15:02:12 -0000
*************** tree build_and_jump (tree *);
*** 120,123 ****
--- 120,125 ----
tree alloc_stmt_list (void);
void free_stmt_list (tree);
+ bool verify_gimple_grammar_in_stmt (tree);
+
#endif /* _TREE_SIMPLE_H */