------- Comment #4 from jakub at gcc dot gnu dot org 2007-11-04 21:35 ------- I'll be testing the following patch. It is quite simplistic, in that it will give up on bb boundaries, still it should IMHO trigger in quite a lot of cases. Each optimized out pair of __builtin_stack_save/__builtin_stack_restore will typically save one call saved register (resp. memory slot if we run out of them).
--- tree-ssa-ccp.c.jj10 2007-09-04 23:09:30.000000000 +0200 +++ tree-ssa-ccp.c 2007-11-04 22:16:03.000000000 +0100 @@ -2598,6 +2598,76 @@ fold_stmt_inplace (tree stmt) return changed; } +/* Try to optimize out __builtin_stack_restore. Optimize it out + if there is another __builtin_stack_restore in the same basic + block and no calls or ASM_EXPRs are in between, or if this block's + only outgoing edge is to EXIT_BLOCK and there are no calls or + ASM_EXPRs after this __builtin_stack_restore. */ + +static tree +optimize_stack_restore (basic_block bb, tree call, block_stmt_iterator i) +{ + tree stack_save, stmt, callee; + + if (TREE_CODE (call) != CALL_EXPR + || call_expr_nargs (call) != 1 + || TREE_CODE (CALL_EXPR_ARG (call, 0)) != SSA_NAME + || !POINTER_TYPE_P (TREE_TYPE (CALL_EXPR_ARG (call, 0)))) + return NULL_TREE; + + for (bsi_next (&i); !bsi_end_p (i); bsi_next (&i)) + { + tree stmt = bsi_stmt (i); + tree call; + + if (TREE_CODE (stmt) == ASM_EXPR) + return NULL_TREE; + call = get_call_expr_in (stmt); + if (call == NULL) + continue; + + callee = get_callee_fndecl (call); + if (!callee || DECL_BUILT_IN_CLASS (callee) != BUILT_IN_NORMAL) + return NULL_TREE; + + if (DECL_FUNCTION_CODE (callee) == BUILT_IN_STACK_RESTORE) + break; + } + + if (bsi_end_p (i) + && (! single_succ_p (bb) + || single_succ_edge (bb)->dest != EXIT_BLOCK_PTR)) + return NULL_TREE; + + stack_save = SSA_NAME_DEF_STMT (CALL_EXPR_ARG (call, 0)); + if (TREE_CODE (stack_save) != GIMPLE_MODIFY_STMT + || GIMPLE_STMT_OPERAND (stack_save, 0) != CALL_EXPR_ARG (call, 0) + || TREE_CODE (GIMPLE_STMT_OPERAND (stack_save, 1)) != CALL_EXPR + || tree_could_throw_p (stack_save) + || !has_single_use (CALL_EXPR_ARG (call, 0))) + return NULL_TREE; + + callee = get_callee_fndecl (GIMPLE_STMT_OPERAND (stack_save, 1)); + if (!callee + || DECL_BUILT_IN_CLASS (callee) != BUILT_IN_NORMAL + || DECL_FUNCTION_CODE (callee) != BUILT_IN_STACK_SAVE + || call_expr_nargs (GIMPLE_STMT_OPERAND (stack_save, 1)) != 0) + return NULL_TREE; + + stmt = stack_save; + push_stmt_changes (&stmt); + if (!set_rhs (&stmt, + build_int_cst (TREE_TYPE (CALL_EXPR_ARG (call, 0)), 0))) + { + discard_stmt_changes (&stmt); + return NULL_TREE; + } + gcc_assert (stmt == stack_save); + pop_stmt_changes (&stmt); + + return integer_zero_node; +} + /* Convert EXPR into a GIMPLE value suitable for substitution on the RHS of an assignment. Insert the necessary statements before iterator *SI_P. @@ -2682,6 +2752,12 @@ execute_fold_all_builtins (void) result = integer_zero_node; break; + case BUILT_IN_STACK_RESTORE: + result = optimize_stack_restore (bb, *stmtp, i); + if (result) + break; + /* FALLTHRU */ + default: bsi_next (&i); continue; -- http://gcc.gnu.org/bugzilla/show_bug.cgi?id=23848