In gcc 4.0, the restrict qualifier became less useful than in gcc 3.4. One of the main uses of the restrict qualifier is in scheduling. The scheduler currently uses only RTL level aliasing information--we currently have no mechanism for letting the RTL level query the alias information at the tree level. The RTL level aliasing analysis can only handle restrict when the RTL level can determine whether a memory reference is made through a restricted pointer. In gcc 3.4, that mostly worked. In gcc 4.0, it often fails. It fails because the gimplification process introduces temporary variables, and those variables do not carry the restrict qualifier.
I mentioned on IRC that I had a simple patch to let the RTL level aliasing analysis see the underlying decl, the one with the restrict qualifier. My original patch was for the 4.0 branch. This is a version updated for the 4.1 branch. I'm not proposing to install it yet. I would like to hear from people with access to some standard benchmarks whether it makes any difference. This patch isn't quite right, because it doesn't record underlying declarations for FIELD_DECLs. I wrote it that way because of concerns about the different decl structs. Actually I now suspect that that was a mistake, and that the patch could handle FIELD_DECLs more or less as written. But, whatever. If the patch helps on benchmarks I will clean it up and check it in. If it does not help, I will discard it. Obviously it is only going to help for benchmarks which use the restrict qualifier. And it is obviously a short-term fix: the correct long-term fix is to implement full support for the restrict qualifier at the tree level and to expose the tree level alias analysis at RTL level. I know that both are being worked on, but that this work is unlikely to be in the 4.1 release. This patch passes a bootstrap and testsuite run on i686-pc-linux-gnu. Any comments are appreciated. Ian Index: alias.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/alias.c,v retrieving revision 1.254 diff -p -u -r1.254 alias.c --- alias.c 21 Jul 2005 22:34:33 -0000 1.254 +++ alias.c 25 Sep 2005 09:00:23 -0000 @@ -395,9 +395,12 @@ find_base_decl (tree t) if (t == 0 || t == error_mark_node || ! POINTER_TYPE_P (TREE_TYPE (t))) return 0; - /* If this is a declaration, return it. */ + /* If this is a declaration, return the underlying decl. */ if (DECL_P (t)) - return t; + { + tree u = DECL_UNDERLYING_NONSCALAR_DECL (t); + return u ? u : t; + } /* Handle general expressions. It would be nice to deal with COMPONENT_REFs here. If we could tell that `a' and `b' were the Index: gimplify.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/gimplify.c,v retrieving revision 2.154 diff -p -u -r2.154 gimplify.c --- gimplify.c 24 Sep 2005 16:21:43 -0000 2.154 +++ gimplify.c 25 Sep 2005 09:00:23 -0000 @@ -298,6 +298,57 @@ create_artificial_label (void) return lab; } +/* Subroutine for find_single_nonscalar_decl. */ + +struct find_decl +{ + int c; + tree decl; +}; + +static tree +find_single_nonscalar_decl_1 (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, + void *data) +{ + struct find_decl *pfd = (struct find_decl *) data; + + if (DECL_P (*tp) + && !INTEGRAL_TYPE_P (TREE_TYPE (*tp)) + && !SCALAR_FLOAT_TYPE_P (TREE_TYPE (*tp))) + { + ++pfd->c; + pfd->decl = *tp; + } + + return NULL_TREE; +} + +/* Find the single DECL of non-scalar type in the tree T and return + it. If there are zero or more than one such DECLs, return + NULL. */ + +static tree +find_single_nonscalar_decl (tree t) +{ + struct find_decl fd; + + fd.c = 0; + fd.decl = NULL_TREE; + walk_tree (&t, find_single_nonscalar_decl_1, &fd, NULL); + + /* We are only interestd in variables. FIXME: We should probably + accept FIELD_DECL here, but it doesn't have the right decl + structure. */ + if (fd.c != 1 + || TREE_CODE (fd.decl) == FUNCTION_DECL + || TREE_CODE (fd.decl) == LABEL_DECL + || TREE_CODE (fd.decl) == FIELD_DECL + || TREE_CODE (fd.decl) == TYPE_DECL) + return NULL_TREE; + + return fd.decl; +} + /* Create a new temporary name with PREFIX. Returns an identifier. */ static GTY(()) unsigned int tmp_var_id_num; @@ -470,6 +521,18 @@ internal_get_tmp_var (tree val, tree *pr t = lookup_tmp_var (val, is_formal); + if (is_formal) + { + tree u = find_single_nonscalar_decl (val); + + if (u && DECL_UNDERLYING_NONSCALAR_DECL (u)) + u = DECL_UNDERLYING_NONSCALAR_DECL (u); + gcc_assert (!DECL_UNDERLYING_NONSCALAR_DECL (t) + || DECL_UNDERLYING_NONSCALAR_DECL (t) == u); + if (u && lang_hooks.types_compatible_p (TREE_TYPE (u), TREE_TYPE (t))) + DECL_UNDERLYING_NONSCALAR_DECL (t) = u; + } + if (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE) DECL_COMPLEX_GIMPLE_REG_P (t) = 1; Index: tree.h =================================================================== RCS file: /cvs/gcc/gcc/gcc/tree.h,v retrieving revision 1.756 diff -p -u -r1.756 tree.h --- tree.h 19 Sep 2005 14:54:28 -0000 1.756 +++ tree.h 25 Sep 2005 09:00:24 -0000 @@ -2280,10 +2280,16 @@ extern void decl_value_expr_insert (tree /* In VAR_DECL and PARM_DECL nodes, nonzero means declared `register'. */ #define DECL_REGISTER(NODE) (DECL_WRTL_CHECK (NODE)->decl_common.decl_flag_0) +/* For a DECL which represents a temporary variable, this is the + underlying DECL of nonscalar type, if there is one. */ +#define DECL_UNDERLYING_NONSCALAR_DECL(NODE) \ + (DECL_WRTL_CHECK (NODE)->decl_with_rtl.underlying_nonscalar_decl) + struct tree_decl_with_rtl GTY(()) { struct tree_decl_common common; rtx rtl; + tree underlying_nonscalar_decl; }; /* In a FIELD_DECL, this is the field position, counting in bytes, of the