From: Richard Guenther Date: Mon, 17 Jan 2011 11:31:10 +0000 (+0000) Subject: backport: re PR tree-optimization/47286 (Invalid code when using register ... asm) X-Git-Tag: releases/gcc-4.5.3~297 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=be93bc5838626626f54130675bb24d6c8538c173;p=thirdparty%2Fgcc.git backport: re PR tree-optimization/47286 (Invalid code when using register ... asm) 2011-01-17 Richard Guenther Backport from mainline PR tree-optimization/47286 * tree-ssa-structalias.c (new_var_info): Register variables are global. * gcc.dg/tree-ssa/pr47286.c: New testcase. PR tree-optimization/44592 * tree-ssa-ccp.c (gimplify_and_update_call_from_tree): Copy from trunk. * gfortran.dg/pr44592.f90: New testcase. From-SVN: r168894 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 86e15db5cd91..3d4c6eb7b99b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,14 @@ +2011-01-17 Richard Guenther + + Backport from mainline + PR tree-optimization/47286 + * tree-ssa-structalias.c (new_var_info): Register variables + are global. + + PR tree-optimization/44592 + * tree-ssa-ccp.c (gimplify_and_update_call_from_tree): Copy + from trunk. + 2011-01-16 Jakub Jelinek Backport from mainline diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 3e9e0a06b81f..ad808a8735a6 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,12 @@ +2011-01-17 Richard Guenther + + Backport from mainline + PR tree-optimization/47286 + * gcc.dg/tree-ssa/pr47286.c: New testcase. + + PR tree-optimization/44592 + * gfortran.dg/pr44592.f90: New testcase. + 2011-01-16 Jakub Jelinek Backport from mainline diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr47286.c b/gcc/testsuite/gcc.dg/tree-ssa/pr47286.c new file mode 100644 index 000000000000..b03c59b832b7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr47286.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-skip-if "" { ! { i?86-*-* x86_64-*-* } } { "*" } { "" } } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ + +struct thread_info { int preempt_count; }; +static inline struct thread_info *current_thread_info(void) +{ + register struct thread_info *sp asm("esp"); + return sp; +} +void testcase(void) +{ + current_thread_info()->preempt_count += 1; +} + +/* We have to make sure that alias analysis treats sp as pointing + to globals and thus the store not optimized away. */ + +/* { dg-final { scan-tree-dump "->preempt_count =" "optimized" } } */ +/* { dg-final { cleanup-tree-dump "optimized" } } */ diff --git a/gcc/testsuite/gfortran.dg/pr44592.f90 b/gcc/testsuite/gfortran.dg/pr44592.f90 new file mode 100644 index 000000000000..8b043ba33ed3 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pr44592.f90 @@ -0,0 +1,20 @@ +! { dg-do run } +! { dg-options "-O3" } +! From forall_12.f90 +! Fails with loop reversal at -O3 +! + character(len=1) :: b(4) = (/"1","2","3","4"/), c(4) + c = b + i = 1 + ! This statement must be here for the abort below + b(1:3)(i:i) = b(2:4)(i:i) + + b = c + b(4:2:-1)(i:i) = b(3:1:-1)(i:i) + + ! This fails. If the condition is printed, the result is F F F F + if (any (b .ne. (/"1","1","2","3"/))) i = 2 + print *, b + print *, b .ne. (/"1","1","2","3"/) + if (i == 2) call abort +end diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c index 2056da82d8e4..b570548d55aa 100644 --- a/gcc/tree-ssa-ccp.c +++ b/gcc/tree-ssa-ccp.c @@ -3355,7 +3355,9 @@ optimize_stdarg_builtin (gimple call) is replaced. If the call is expected to produces a result, then it is replaced by an assignment of the new RHS to the result variable. If the result is to be ignored, then the call is replaced by a - GIMPLE_NOP. */ + GIMPLE_NOP. A proper VDEF chain is retained by making the first + VUSE and the last VDEF of the whole sequence be the same as the replaced + statement and using new SSA names for stores in between. */ static void gimplify_and_update_call_from_tree (gimple_stmt_iterator *si_p, tree expr) @@ -3366,17 +3368,36 @@ gimplify_and_update_call_from_tree (gimple_stmt_iterator *si_p, tree expr) gimple_stmt_iterator i; gimple_seq stmts = gimple_seq_alloc(); struct gimplify_ctx gctx; + gimple last = NULL; + gimple laststore = NULL; + tree reaching_vuse; stmt = gsi_stmt (*si_p); gcc_assert (is_gimple_call (stmt)); lhs = gimple_call_lhs (stmt); + reaching_vuse = gimple_vuse (stmt); push_gimplify_context (&gctx); if (lhs == NULL_TREE) - gimplify_and_add (expr, &stmts); + { + gimplify_and_add (expr, &stmts); + /* We can end up with folding a memcpy of an empty class assignment + which gets optimized away by C++ gimplification. */ + if (gimple_seq_empty_p (stmts)) + { + pop_gimplify_context (NULL); + if (gimple_in_ssa_p (cfun)) + { + unlink_stmt_vdef (stmt); + release_defs (stmt); + } + gsi_remove (si_p, true); + return; + } + } else tmp = get_initialized_tmp_var (expr, &stmts, NULL); @@ -3387,26 +3408,95 @@ gimplify_and_update_call_from_tree (gimple_stmt_iterator *si_p, tree expr) /* The replacement can expose previously unreferenced variables. */ for (i = gsi_start (stmts); !gsi_end_p (i); gsi_next (&i)) - { - new_stmt = gsi_stmt (i); - find_new_referenced_vars (new_stmt); - gsi_insert_before (si_p, new_stmt, GSI_NEW_STMT); - mark_symbols_for_renaming (new_stmt); - gsi_next (si_p); - } + { + if (last) + { + gsi_insert_before (si_p, last, GSI_NEW_STMT); + gsi_next (si_p); + } + new_stmt = gsi_stmt (i); + if (gimple_in_ssa_p (cfun)) + { + find_new_referenced_vars (new_stmt); + mark_symbols_for_renaming (new_stmt); + } + /* If the new statement has a VUSE, update it with exact SSA name we + know will reach this one. */ + if (gimple_vuse (new_stmt)) + { + /* If we've also seen a previous store create a new VDEF for + the latter one, and make that the new reaching VUSE. */ + if (laststore) + { + reaching_vuse = make_ssa_name (gimple_vop (cfun), laststore); + gimple_set_vdef (laststore, reaching_vuse); + update_stmt (laststore); + laststore = NULL; + } + gimple_set_vuse (new_stmt, reaching_vuse); + gimple_set_modified (new_stmt, true); + } + if (gimple_assign_single_p (new_stmt) + && !is_gimple_reg (gimple_assign_lhs (new_stmt))) + { + laststore = new_stmt; + } + last = new_stmt; + } if (lhs == NULL_TREE) { - new_stmt = gimple_build_nop (); - unlink_stmt_vdef (stmt); - release_defs (stmt); + /* If we replace a call without LHS that has a VDEF and our new + sequence ends with a store we must make that store have the same + vdef in order not to break the sequencing. This can happen + for instance when folding memcpy calls into assignments. */ + if (gimple_vdef (stmt) && laststore) + { + gimple_set_vdef (laststore, gimple_vdef (stmt)); + if (TREE_CODE (gimple_vdef (stmt)) == SSA_NAME) + SSA_NAME_DEF_STMT (gimple_vdef (stmt)) = laststore; + update_stmt (laststore); + } + else if (gimple_in_ssa_p (cfun)) + { + unlink_stmt_vdef (stmt); + release_defs (stmt); + } + new_stmt = last; } else { + if (last) + { + gsi_insert_before (si_p, last, GSI_NEW_STMT); + gsi_next (si_p); + } + if (laststore && is_gimple_reg (lhs)) + { + gimple_set_vdef (laststore, gimple_vdef (stmt)); + update_stmt (laststore); + if (TREE_CODE (gimple_vdef (stmt)) == SSA_NAME) + SSA_NAME_DEF_STMT (gimple_vdef (stmt)) = laststore; + laststore = NULL; + } + else if (laststore) + { + reaching_vuse = make_ssa_name (gimple_vop (cfun), laststore); + gimple_set_vdef (laststore, reaching_vuse); + update_stmt (laststore); + laststore = NULL; + } new_stmt = gimple_build_assign (lhs, tmp); - gimple_set_vuse (new_stmt, gimple_vuse (stmt)); - gimple_set_vdef (new_stmt, gimple_vdef (stmt)); - move_ssa_defining_stmt_for_defs (new_stmt, stmt); + if (!is_gimple_reg (tmp)) + gimple_set_vuse (new_stmt, reaching_vuse); + if (!is_gimple_reg (lhs)) + { + gimple_set_vdef (new_stmt, gimple_vdef (stmt)); + if (TREE_CODE (gimple_vdef (stmt)) == SSA_NAME) + SSA_NAME_DEF_STMT (gimple_vdef (stmt)) = new_stmt; + } + else if (reaching_vuse == gimple_vuse (stmt)) + unlink_stmt_vdef (stmt); } gimple_set_location (new_stmt, gimple_location (stmt)); diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c index aa3b7018f47a..314705ccbfd1 100644 --- a/gcc/tree-ssa-structalias.c +++ b/gcc/tree-ssa-structalias.c @@ -369,7 +369,11 @@ new_var_info (tree t, const char *name) ret->may_have_pointers = true; ret->is_global_var = (t == NULL_TREE); if (t && DECL_P (t)) - ret->is_global_var = is_global_var (t); + ret->is_global_var = (is_global_var (t) + /* We have to treat even local register variables + as escape points. */ + || (TREE_CODE (t) == VAR_DECL + && DECL_HARD_REGISTER (t))); ret->solution = BITMAP_ALLOC (&pta_obstack); ret->oldsolution = BITMAP_ALLOC (&oldpta_obstack); ret->next = NULL;