diff options
author | jakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4> | 2003-07-28 15:42:24 +0000 |
---|---|---|
committer | jakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4> | 2003-07-28 15:42:24 +0000 |
commit | fc3df35715336a36e894a10f4f4992234ff26a2b (patch) | |
tree | 171abb9dcfe266e6906e8910ab7d2a2a3a72cce0 | |
parent | 9dbc39271ded1571c28b2cb7ae486dc3afea50f5 (diff) | |
download | gcc-fc3df35715336a36e894a10f4f4992234ff26a2b.tar.gz |
* configure.in (--enable-checking): Add fold category.
(ENABLE_FOLD_CHECKING): Define if requested.
* configure: Rebuilt.
* config.in: Rebuilt.
* doc/install.texi: Document it.
* fold-const.c: Include md5.h.
[ENABLE_FOLD_CHECKING] (fold): Define to fold_1.
[ENABLE_FOLD_CHECKING] (fold, fold_checksum_tree, fold_check_failed,
print_fold_checksum): New functions.
* fold-const.c (fold): Never modify argument passed to fold, instead
change a copy and return it.
* convert.c (convert_to_integer): Likewise.
testsuite/
* gcc.c-torture/compile/20030725-1.c: New test.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@69886 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | gcc/ChangeLog | 16 | ||||
-rw-r--r-- | gcc/config.in | 6 | ||||
-rwxr-xr-x | gcc/configure | 10 | ||||
-rw-r--r-- | gcc/configure.in | 9 | ||||
-rw-r--r-- | gcc/convert.c | 3 | ||||
-rw-r--r-- | gcc/doc/install.texi | 4 | ||||
-rw-r--r-- | gcc/fold-const.c | 243 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/testsuite/gcc.c-torture/compile/20030725-1.c | 9 |
9 files changed, 292 insertions, 12 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index cc7e60ae904..1bdd3fc1e94 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,19 @@ +2003-07-28 Jakub Jelinek <jakub@redhat.com> + + * configure.in (--enable-checking): Add fold category. + (ENABLE_FOLD_CHECKING): Define if requested. + * configure: Rebuilt. + * config.in: Rebuilt. + * doc/install.texi: Document it. + * fold-const.c: Include md5.h. + [ENABLE_FOLD_CHECKING] (fold): Define to fold_1. + [ENABLE_FOLD_CHECKING] (fold, fold_checksum_tree, fold_check_failed, + print_fold_checksum): New functions. + + * fold-const.c (fold): Never modify argument passed to fold, instead + change a copy and return it. + * convert.c (convert_to_integer): Likewise. + 2003-07-27 Nathanael Nerode <neroden@gcc.gnu.org> * fixinc/fixinc.svr4: Remove dead code. Remove now-unnecessary diff --git a/gcc/config.in b/gcc/config.in index cdb7c563831..e1feb70cb30 100644 --- a/gcc/config.in +++ b/gcc/config.in @@ -1,4 +1,4 @@ -/* config.in. Generated automatically from configure.in by autoheader 2.13. */ +/* config.in. Generated automatically from configure.in by autoheader. */ /* Define to the type of elements in the array set by `getgroups'. Usually this is either `int' or `gid_t'. */ @@ -236,6 +236,10 @@ every opportunity. This is extremely expensive. */ #undef ENABLE_GC_ALWAYS_COLLECT +/* Define if you want fold checked that it never destructs its argument. + This is quite expensive. */ +#undef ENABLE_FOLD_CHECKING + /* Define if you want to run subprograms and generated programs through valgrind (a memory checker). This is extremely expensive. */ #undef ENABLE_VALGRIND_CHECKING diff --git a/gcc/configure b/gcc/configure index cbb57e7bf35..c102e87ba1a 100755 --- a/gcc/configure +++ b/gcc/configure @@ -34,7 +34,7 @@ ac_help="$ac_help --enable-checking[=LIST] enable expensive run-time checks. With LIST, enable only specific categories of checks. - Categories are: misc,tree,rtl,rtlflag,gc,gcac; + Categories are: misc,tree,rtl,rtlflag,gc,gcac,fold; default is misc,tree,gc,rtlflag" ac_help="$ac_help --enable-coverage[=LEVEL] @@ -1933,6 +1933,7 @@ ac_rtl_checking= ac_rtlflag_checking= ac_gc_checking= ac_gc_always_collect= +ac_fold_checking= case "${enableval}" in yes) ac_checking=1 ; ac_tree_checking=1 ; ac_gc_checking=1 ; ac_rtlflag_checking=1 ;; @@ -1949,6 +1950,7 @@ no) ;; rtl) ac_rtl_checking=1 ;; gc) ac_gc_checking=1 ;; gcac) ac_gc_always_collect=1 ;; + fold) ac_fold_checking=1 ;; valgrind) ac_checking_valgrind=1 ;; *) { echo "configure: error: unknown check category $check" 1>&2; exit 1; } ;; esac @@ -2000,6 +2002,12 @@ if test x$ac_gc_always_collect != x ; then EOF fi +if test x$ac_fold_checking != x ; then + cat >> confdefs.h <<\EOF +#define ENABLE_FOLD_CHECKING 1 +EOF + +fi valgrind_path_defines= valgrind_command= if test x$ac_checking_valgrind != x ; then diff --git a/gcc/configure.in b/gcc/configure.in index abf2576a4fb..5f031236a30 100644 --- a/gcc/configure.in +++ b/gcc/configure.in @@ -318,7 +318,7 @@ AC_ARG_ENABLE(checking, [ --enable-checking[=LIST] enable expensive run-time checks. With LIST, enable only specific categories of checks. - Categories are: misc,tree,rtl,rtlflag,gc,gcac; + Categories are: misc,tree,rtl,rtlflag,gc,gcac,fold; default is misc,tree,gc,rtlflag], [ac_checking= ac_tree_checking= @@ -326,6 +326,7 @@ ac_rtl_checking= ac_rtlflag_checking= ac_gc_checking= ac_gc_always_collect= +ac_fold_checking= case "${enableval}" in yes) ac_checking=1 ; ac_tree_checking=1 ; ac_gc_checking=1 ; ac_rtlflag_checking=1 ;; @@ -342,6 +343,7 @@ no) ;; rtl) ac_rtl_checking=1 ;; gc) ac_gc_checking=1 ;; gcac) ac_gc_always_collect=1 ;; + fold) ac_fold_checking=1 ;; valgrind) ac_checking_valgrind=1 ;; *) AC_MSG_ERROR(unknown check category $check) ;; esac @@ -388,6 +390,11 @@ if test x$ac_gc_always_collect != x ; then paranoid mode, validating the entire heap and collecting garbage at every opportunity. This is extremely expensive.]) fi +if test x$ac_fold_checking != x ; then + AC_DEFINE(ENABLE_FOLD_CHECKING, 1, +[Define if you want fold checked that it never destructs its argument. + This is quite expensive.]) +fi valgrind_path_defines= valgrind_command= if test x$ac_checking_valgrind != x ; then diff --git a/gcc/convert.c b/gcc/convert.c index fc001b6e74e..5bab1c19d35 100644 --- a/gcc/convert.c +++ b/gcc/convert.c @@ -320,6 +320,7 @@ convert_to_integer (tree type, tree expr) if (TREE_CODE_CLASS (ex_form) == '<') { + expr = copy_node (expr); TREE_TYPE (expr) = type; return expr; } @@ -328,6 +329,7 @@ convert_to_integer (tree type, tree expr) || ex_form == TRUTH_OR_EXPR || ex_form == TRUTH_ORIF_EXPR || ex_form == TRUTH_XOR_EXPR) { + expr = copy_node (expr); TREE_OPERAND (expr, 0) = convert (type, TREE_OPERAND (expr, 0)); TREE_OPERAND (expr, 1) = convert (type, TREE_OPERAND (expr, 1)); TREE_TYPE (expr) = type; @@ -336,6 +338,7 @@ convert_to_integer (tree type, tree expr) else if (ex_form == TRUTH_NOT_EXPR) { + expr = copy_node (expr); TREE_OPERAND (expr, 0) = convert (type, TREE_OPERAND (expr, 0)); TREE_TYPE (expr) = type; return expr; diff --git a/gcc/doc/install.texi b/gcc/doc/install.texi index 1aeb50fcf79..6f3fbf1dbcb 100644 --- a/gcc/doc/install.texi +++ b/gcc/doc/install.texi @@ -1038,8 +1038,8 @@ with GCC@. This is on by default when building from CVS or snapshots, but off for releases. More control over the checks may be had by specifying @var{list}; the categories of checks available are @samp{misc}, @samp{tree}, @samp{gc}, @samp{rtl}, @samp{rtlflag}, -@samp{gcac} and @samp{valgrind}. The check @samp{valgrind} requires the -external @command{valgrind} simulator, available from +@samp{fold}, @samp{gcac} and @samp{valgrind}. The check @samp{valgrind} +requires the external @command{valgrind} simulator, available from @uref{http://developer.kde.org/~sewardj/}. The default when @var{list} is not specified is @samp{misc,tree,gc,rtlflag}; the checks @samp{rtl}, @samp{gcac} and @samp{valgrind} are very expensive. diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 114aaae44c8..58cec23773b 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -56,6 +56,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "ggc.h" #include "hashtab.h" #include "langhooks.h" +#include "md5.h" static void encode (HOST_WIDE_INT *, unsigned HOST_WIDE_INT, HOST_WIDE_INT); static void decode (HOST_WIDE_INT *, unsigned HOST_WIDE_INT *, HOST_WIDE_INT *); @@ -4921,7 +4922,7 @@ fold_single_bit_test (enum tree_code code, tree arg0, tree arg1, } return NULL_TREE; } - + /* Perform constant folding and related simplification of EXPR. The related simplifications include x*1 => x, x*0 => 0, etc., and application of the associative law. @@ -4930,10 +4931,15 @@ fold_single_bit_test (enum tree_code code, tree arg0, tree arg1, We cannot simplify through a CONVERT_EXPR, FIX_EXPR or FLOAT_EXPR, but we can constant-fold them if they have constant operands. */ +#ifdef ENABLE_FOLD_CHECKING +# define fold(x) fold_1 (x) +static tree fold_1 (tree); +static +#endif tree fold (tree expr) { - tree t = expr; + tree t = expr, orig_t; tree t1 = NULL_TREE; tree tem; tree type = TREE_TYPE (expr); @@ -4957,6 +4963,7 @@ fold (tree expr) #ifdef MAX_INTEGER_COMPUTATION_MODE check_max_integer_computation_mode (expr); #endif + orig_t = t; if (code == NOP_EXPR || code == FLOAT_EXPR || code == CONVERT_EXPR) { @@ -5028,12 +5035,15 @@ fold (tree expr) if ((code == PLUS_EXPR || code == MULT_EXPR || code == MIN_EXPR || code == MAX_EXPR || code == BIT_IOR_EXPR || code == BIT_XOR_EXPR || code == BIT_AND_EXPR) - && (TREE_CODE (arg0) == INTEGER_CST || TREE_CODE (arg0) == REAL_CST)) + && ((TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) != INTEGER_CST) + || (TREE_CODE (arg0) == REAL_CST && TREE_CODE (arg1) != REAL_CST))) { tem = arg0; arg0 = arg1; arg1 = tem; - tem = TREE_OPERAND (t, 0); TREE_OPERAND (t, 0) = TREE_OPERAND (t, 1); - TREE_OPERAND (t, 1) = tem; + if (t == orig_t) + t = copy_node (t); + TREE_OPERAND (t, 0) = arg0; + TREE_OPERAND (t, 1) = arg1; } /* Now WINS is set as described above, @@ -5282,6 +5292,8 @@ fold (tree expr) /* Don't leave an assignment inside a conversion unless assigning a bitfield. */ tree prev = TREE_OPERAND (t, 0); + if (t == orig_t) + t = copy_node (t); TREE_OPERAND (t, 0) = TREE_OPERAND (prev, 1); /* First do the assignment, then return converted constant. */ t = build (COMPOUND_EXPR, TREE_TYPE (t), prev, fold (t)); @@ -5334,7 +5346,12 @@ fold (tree expr) if (!wins) { - TREE_CONSTANT (t) = TREE_CONSTANT (arg0); + if (TREE_CONSTANT (t) != TREE_CONSTANT (arg0)) + { + if (t == orig_t) + t = copy_node (t); + TREE_CONSTANT (t) = TREE_CONSTANT (arg0); + } return t; } return fold_convert (t, arg0); @@ -5356,7 +5373,12 @@ fold (tree expr) return t; case RANGE_EXPR: - TREE_CONSTANT (t) = wins; + if (TREE_CONSTANT (t) != wins) + { + if (t == orig_t) + t = copy_node (t); + TREE_CONSTANT (t) = wins; + } return t; case NEGATE_EXPR: @@ -6379,6 +6401,8 @@ fold (tree expr) RROTATE_EXPR by a new constant. */ if (code == LROTATE_EXPR && TREE_CODE (arg1) == INTEGER_CST) { + if (t == orig_t) + t = copy_node (t); TREE_SET_CODE (t, RROTATE_EXPR); code = RROTATE_EXPR; TREE_OPERAND (t, 1) = arg1 @@ -6591,6 +6615,8 @@ fold (tree expr) || (TREE_CODE (arg0) == REAL_CST && TREE_CODE (arg0) != REAL_CST)) { + if (t == orig_t) + t = copy_node (t); TREE_OPERAND (t, 0) = arg1; TREE_OPERAND (t, 1) = arg0; arg0 = TREE_OPERAND (t, 0); @@ -6907,6 +6933,8 @@ fold (tree expr) arg0); case GE_EXPR: code = EQ_EXPR; + if (t == orig_t) + t = copy_node (t); TREE_SET_CODE (t, EQ_EXPR); break; case LE_EXPR: @@ -6915,6 +6943,8 @@ fold (tree expr) arg0); case LT_EXPR: code = NE_EXPR; + if (t == orig_t) + t = copy_node (t); TREE_SET_CODE (t, NE_EXPR); break; @@ -6951,6 +6981,8 @@ fold (tree expr) arg0); case LE_EXPR: code = EQ_EXPR; + if (t == orig_t) + t = copy_node (t); TREE_SET_CODE (t, EQ_EXPR); break; @@ -6960,6 +6992,8 @@ fold (tree expr) arg0); case GT_EXPR: code = NE_EXPR; + if (t == orig_t) + t = copy_node (t); TREE_SET_CODE (t, NE_EXPR); break; @@ -7185,6 +7219,8 @@ fold (tree expr) || ! HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0)))) return constant_boolean_node (1, type); code = EQ_EXPR; + if (t == orig_t) + t = copy_node (t); TREE_SET_CODE (t, code); break; @@ -7902,6 +7938,199 @@ fold (tree expr) } /* switch (code) */ } +#ifdef ENABLE_FOLD_CHECKING +#undef fold + +static void fold_checksum_tree (tree, struct md5_ctx *, htab_t); +static void fold_check_failed (tree, tree); +void print_fold_checksum (tree); + +/* When --enable-checking=fold, compute a digest of expr before + and after actual fold call to see if fold did not accidentally + change original expr. */ + +tree +fold (tree expr) +{ + tree ret; + struct md5_ctx ctx; + unsigned char checksum_before[16], checksum_after[16]; + htab_t ht; + + ht = htab_create (32, htab_hash_pointer, htab_eq_pointer, NULL); + md5_init_ctx (&ctx); + fold_checksum_tree (expr, &ctx, ht); + md5_finish_ctx (&ctx, checksum_before); + htab_empty (ht); + + ret = fold_1 (expr); + + md5_init_ctx (&ctx); + fold_checksum_tree (expr, &ctx, ht); + md5_finish_ctx (&ctx, checksum_after); + htab_delete (ht); + + if (memcmp (checksum_before, checksum_after, 16)) + fold_check_failed (expr, ret); + + return ret; +} + +void +print_fold_checksum (tree expr) +{ + struct md5_ctx ctx; + unsigned char checksum[16], cnt; + htab_t ht; + + ht = htab_create (32, htab_hash_pointer, htab_eq_pointer, NULL); + md5_init_ctx (&ctx); + fold_checksum_tree (expr, &ctx, ht); + md5_finish_ctx (&ctx, checksum); + htab_delete (ht); + for (cnt = 0; cnt < 16; ++cnt) + fprintf (stderr, "%02x", checksum[cnt]); + putc ('\n', stderr); +} + +static void +fold_check_failed (tree expr ATTRIBUTE_UNUSED, tree ret ATTRIBUTE_UNUSED) +{ + internal_error ("fold check: original tree changed by fold"); +} + +static void +fold_checksum_tree (tree expr, struct md5_ctx *ctx, htab_t ht) +{ + void **slot; + enum tree_code code; + char buf[sizeof (struct tree_decl)]; + int i, len; + + if (sizeof (struct tree_exp) + 5 * sizeof (tree) + > sizeof (struct tree_decl) + || sizeof (struct tree_type) > sizeof (struct tree_decl)) + abort (); + if (expr == NULL) + return; + slot = htab_find_slot (ht, expr, INSERT); + if (*slot != NULL) + return; + *slot = expr; + code = TREE_CODE (expr); + if (code == SAVE_EXPR && SAVE_EXPR_NOPLACEHOLDER (expr)) + { + /* Allow SAVE_EXPR_NOPLACEHOLDER flag to be modified. */ + memcpy (buf, expr, tree_size (expr)); + expr = (tree) buf; + SAVE_EXPR_NOPLACEHOLDER (expr) = 0; + } + else if (TREE_CODE_CLASS (code) == 'd' && DECL_ASSEMBLER_NAME_SET_P (expr)) + { + /* Allow DECL_ASSEMBLER_NAME to be modified. */ + memcpy (buf, expr, tree_size (expr)); + expr = (tree) buf; + SET_DECL_ASSEMBLER_NAME (expr, NULL); + } + else if (TREE_CODE_CLASS (code) == 't' + && (TYPE_POINTER_TO (expr) || TYPE_REFERENCE_TO (expr))) + { + /* Allow TYPE_POINTER_TO and TYPE_REFERENCE_TO to be modified. */ + memcpy (buf, expr, tree_size (expr)); + expr = (tree) buf; + TYPE_POINTER_TO (expr) = NULL; + TYPE_REFERENCE_TO (expr) = NULL; + } + md5_process_bytes (expr, tree_size (expr), ctx); + fold_checksum_tree (TREE_TYPE (expr), ctx, ht); + if (TREE_CODE_CLASS (code) != 't' && TREE_CODE_CLASS (code) != 'd') + fold_checksum_tree (TREE_CHAIN (expr), ctx, ht); + len = TREE_CODE_LENGTH (code); + switch (TREE_CODE_CLASS (code)) + { + case 'c': + switch (code) + { + case STRING_CST: + md5_process_bytes (TREE_STRING_POINTER (expr), + TREE_STRING_LENGTH (expr), ctx); + break; + case COMPLEX_CST: + fold_checksum_tree (TREE_REALPART (expr), ctx, ht); + fold_checksum_tree (TREE_IMAGPART (expr), ctx, ht); + break; + case VECTOR_CST: + fold_checksum_tree (TREE_VECTOR_CST_ELTS (expr), ctx, ht); + break; + default: + break; + } + break; + case 'x': + switch (code) + { + case TREE_LIST: + fold_checksum_tree (TREE_PURPOSE (expr), ctx, ht); + fold_checksum_tree (TREE_VALUE (expr), ctx, ht); + break; + case TREE_VEC: + for (i = 0; i < TREE_VEC_LENGTH (expr); ++i) + fold_checksum_tree (TREE_VEC_ELT (expr, i), ctx, ht); + break; + default: + break; + } + break; + case 'e': + switch (code) + { + case SAVE_EXPR: len = 2; break; + case GOTO_SUBROUTINE_EXPR: len = 0; break; + case RTL_EXPR: len = 0; break; + case WITH_CLEANUP_EXPR: len = 2; break; + default: break; + } + /* FALLTHROUGH */ + case 'r': + case '<': + case '1': + case '2': + case 's': + for (i = 0; i < len; ++i) + fold_checksum_tree (TREE_OPERAND (expr, i), ctx, ht); + break; + case 'd': + fold_checksum_tree (DECL_SIZE (expr), ctx, ht); + fold_checksum_tree (DECL_SIZE_UNIT (expr), ctx, ht); + fold_checksum_tree (DECL_NAME (expr), ctx, ht); + fold_checksum_tree (DECL_CONTEXT (expr), ctx, ht); + fold_checksum_tree (DECL_ARGUMENTS (expr), ctx, ht); + fold_checksum_tree (DECL_RESULT_FLD (expr), ctx, ht); + fold_checksum_tree (DECL_INITIAL (expr), ctx, ht); + fold_checksum_tree (DECL_ABSTRACT_ORIGIN (expr), ctx, ht); + fold_checksum_tree (DECL_SECTION_NAME (expr), ctx, ht); + fold_checksum_tree (DECL_ATTRIBUTES (expr), ctx, ht); + fold_checksum_tree (DECL_VINDEX (expr), ctx, ht); + break; + case 't': + fold_checksum_tree (TYPE_VALUES (expr), ctx, ht); + fold_checksum_tree (TYPE_SIZE (expr), ctx, ht); + fold_checksum_tree (TYPE_SIZE_UNIT (expr), ctx, ht); + fold_checksum_tree (TYPE_ATTRIBUTES (expr), ctx, ht); + fold_checksum_tree (TYPE_NAME (expr), ctx, ht); + fold_checksum_tree (TYPE_MIN_VALUE (expr), ctx, ht); + fold_checksum_tree (TYPE_MAX_VALUE (expr), ctx, ht); + fold_checksum_tree (TYPE_MAIN_VARIANT (expr), ctx, ht); + fold_checksum_tree (TYPE_BINFO (expr), ctx, ht); + fold_checksum_tree (TYPE_CONTEXT (expr), ctx, ht); + break; + default: + break; + } +} + +#endif + /* Perform constant folding and related simplification of intializer expression EXPR. This behaves identically to "fold" but ignores potential run-time traps and exceptions that fold must preserve. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index ee4a57f5ecc..cd4eb7dc0e2 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2003-07-28 Jakub Jelinek <jakub@redhat.com> + + * gcc.c-torture/compile/20030725-1.c: New test. + 2003-07-28 Aldy Hernandez <aldyh@redhat.com> * gcc.dg/20030505.c: Only run for SPE. diff --git a/gcc/testsuite/gcc.c-torture/compile/20030725-1.c b/gcc/testsuite/gcc.c-torture/compile/20030725-1.c new file mode 100644 index 00000000000..26f2714010e --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/20030725-1.c @@ -0,0 +1,9 @@ +/* This testcase caused ICE on any 64-bit arch at -O2/-O3 due to + fold/extract_muldiv/convert destroying its argument. */ +int x, *y, z, *p; + +void +foo (void) +{ + p = y + (8 * (x == 1 || x == 3) + z); +} |