1*e4b17023SJohn Marino /* Pass computing data for optimizing stdarg functions. 2*e4b17023SJohn Marino Copyright (C) 2004, 2005, 2007, 2008, 2009, 2010, 2011 3*e4b17023SJohn Marino Free Software Foundation, Inc. 4*e4b17023SJohn Marino Contributed by Jakub Jelinek <jakub@redhat.com> 5*e4b17023SJohn Marino 6*e4b17023SJohn Marino This file is part of GCC. 7*e4b17023SJohn Marino 8*e4b17023SJohn Marino GCC is free software; you can redistribute it and/or modify 9*e4b17023SJohn Marino it under the terms of the GNU General Public License as published by 10*e4b17023SJohn Marino the Free Software Foundation; either version 3, or (at your option) 11*e4b17023SJohn Marino any later version. 12*e4b17023SJohn Marino 13*e4b17023SJohn Marino GCC is distributed in the hope that it will be useful, 14*e4b17023SJohn Marino but WITHOUT ANY WARRANTY; without even the implied warranty of 15*e4b17023SJohn Marino MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16*e4b17023SJohn Marino GNU General Public License for more details. 17*e4b17023SJohn Marino 18*e4b17023SJohn Marino You should have received a copy of the GNU General Public License 19*e4b17023SJohn Marino along with GCC; see the file COPYING3. If not see 20*e4b17023SJohn Marino <http://www.gnu.org/licenses/>. */ 21*e4b17023SJohn Marino 22*e4b17023SJohn Marino #include "config.h" 23*e4b17023SJohn Marino #include "system.h" 24*e4b17023SJohn Marino #include "coretypes.h" 25*e4b17023SJohn Marino #include "tm.h" 26*e4b17023SJohn Marino #include "tree.h" 27*e4b17023SJohn Marino #include "function.h" 28*e4b17023SJohn Marino #include "langhooks.h" 29*e4b17023SJohn Marino #include "gimple-pretty-print.h" 30*e4b17023SJohn Marino #include "target.h" 31*e4b17023SJohn Marino #include "tree-flow.h" 32*e4b17023SJohn Marino #include "tree-pass.h" 33*e4b17023SJohn Marino #include "tree-stdarg.h" 34*e4b17023SJohn Marino 35*e4b17023SJohn Marino /* A simple pass that attempts to optimize stdarg functions on architectures 36*e4b17023SJohn Marino that need to save register arguments to stack on entry to stdarg functions. 37*e4b17023SJohn Marino If the function doesn't use any va_start macros, no registers need to 38*e4b17023SJohn Marino be saved. If va_start macros are used, the va_list variables don't escape 39*e4b17023SJohn Marino the function, it is only necessary to save registers that will be used 40*e4b17023SJohn Marino in va_arg macros. E.g. if va_arg is only used with integral types 41*e4b17023SJohn Marino in the function, floating point registers don't need to be saved, etc. */ 42*e4b17023SJohn Marino 43*e4b17023SJohn Marino 44*e4b17023SJohn Marino /* Return true if basic block VA_ARG_BB is dominated by VA_START_BB and 45*e4b17023SJohn Marino is executed at most as many times as VA_START_BB. */ 46*e4b17023SJohn Marino 47*e4b17023SJohn Marino static bool 48*e4b17023SJohn Marino reachable_at_most_once (basic_block va_arg_bb, basic_block va_start_bb) 49*e4b17023SJohn Marino { 50*e4b17023SJohn Marino VEC (edge, heap) *stack = NULL; 51*e4b17023SJohn Marino edge e; 52*e4b17023SJohn Marino edge_iterator ei; 53*e4b17023SJohn Marino sbitmap visited; 54*e4b17023SJohn Marino bool ret; 55*e4b17023SJohn Marino 56*e4b17023SJohn Marino if (va_arg_bb == va_start_bb) 57*e4b17023SJohn Marino return true; 58*e4b17023SJohn Marino 59*e4b17023SJohn Marino if (! dominated_by_p (CDI_DOMINATORS, va_arg_bb, va_start_bb)) 60*e4b17023SJohn Marino return false; 61*e4b17023SJohn Marino 62*e4b17023SJohn Marino visited = sbitmap_alloc (last_basic_block); 63*e4b17023SJohn Marino sbitmap_zero (visited); 64*e4b17023SJohn Marino ret = true; 65*e4b17023SJohn Marino 66*e4b17023SJohn Marino FOR_EACH_EDGE (e, ei, va_arg_bb->preds) 67*e4b17023SJohn Marino VEC_safe_push (edge, heap, stack, e); 68*e4b17023SJohn Marino 69*e4b17023SJohn Marino while (! VEC_empty (edge, stack)) 70*e4b17023SJohn Marino { 71*e4b17023SJohn Marino basic_block src; 72*e4b17023SJohn Marino 73*e4b17023SJohn Marino e = VEC_pop (edge, stack); 74*e4b17023SJohn Marino src = e->src; 75*e4b17023SJohn Marino 76*e4b17023SJohn Marino if (e->flags & EDGE_COMPLEX) 77*e4b17023SJohn Marino { 78*e4b17023SJohn Marino ret = false; 79*e4b17023SJohn Marino break; 80*e4b17023SJohn Marino } 81*e4b17023SJohn Marino 82*e4b17023SJohn Marino if (src == va_start_bb) 83*e4b17023SJohn Marino continue; 84*e4b17023SJohn Marino 85*e4b17023SJohn Marino /* va_arg_bb can be executed more times than va_start_bb. */ 86*e4b17023SJohn Marino if (src == va_arg_bb) 87*e4b17023SJohn Marino { 88*e4b17023SJohn Marino ret = false; 89*e4b17023SJohn Marino break; 90*e4b17023SJohn Marino } 91*e4b17023SJohn Marino 92*e4b17023SJohn Marino gcc_assert (src != ENTRY_BLOCK_PTR); 93*e4b17023SJohn Marino 94*e4b17023SJohn Marino if (! TEST_BIT (visited, src->index)) 95*e4b17023SJohn Marino { 96*e4b17023SJohn Marino SET_BIT (visited, src->index); 97*e4b17023SJohn Marino FOR_EACH_EDGE (e, ei, src->preds) 98*e4b17023SJohn Marino VEC_safe_push (edge, heap, stack, e); 99*e4b17023SJohn Marino } 100*e4b17023SJohn Marino } 101*e4b17023SJohn Marino 102*e4b17023SJohn Marino VEC_free (edge, heap, stack); 103*e4b17023SJohn Marino sbitmap_free (visited); 104*e4b17023SJohn Marino return ret; 105*e4b17023SJohn Marino } 106*e4b17023SJohn Marino 107*e4b17023SJohn Marino 108*e4b17023SJohn Marino /* For statement COUNTER = RHS, if RHS is COUNTER + constant, 109*e4b17023SJohn Marino return constant, otherwise return (unsigned HOST_WIDE_INT) -1. 110*e4b17023SJohn Marino GPR_P is true if this is GPR counter. */ 111*e4b17023SJohn Marino 112*e4b17023SJohn Marino static unsigned HOST_WIDE_INT 113*e4b17023SJohn Marino va_list_counter_bump (struct stdarg_info *si, tree counter, tree rhs, 114*e4b17023SJohn Marino bool gpr_p) 115*e4b17023SJohn Marino { 116*e4b17023SJohn Marino tree lhs, orig_lhs; 117*e4b17023SJohn Marino gimple stmt; 118*e4b17023SJohn Marino unsigned HOST_WIDE_INT ret = 0, val, counter_val; 119*e4b17023SJohn Marino unsigned int max_size; 120*e4b17023SJohn Marino 121*e4b17023SJohn Marino if (si->offsets == NULL) 122*e4b17023SJohn Marino { 123*e4b17023SJohn Marino unsigned int i; 124*e4b17023SJohn Marino 125*e4b17023SJohn Marino si->offsets = XNEWVEC (int, num_ssa_names); 126*e4b17023SJohn Marino for (i = 0; i < num_ssa_names; ++i) 127*e4b17023SJohn Marino si->offsets[i] = -1; 128*e4b17023SJohn Marino } 129*e4b17023SJohn Marino 130*e4b17023SJohn Marino counter_val = gpr_p ? cfun->va_list_gpr_size : cfun->va_list_fpr_size; 131*e4b17023SJohn Marino max_size = gpr_p ? VA_LIST_MAX_GPR_SIZE : VA_LIST_MAX_FPR_SIZE; 132*e4b17023SJohn Marino orig_lhs = lhs = rhs; 133*e4b17023SJohn Marino while (lhs) 134*e4b17023SJohn Marino { 135*e4b17023SJohn Marino enum tree_code rhs_code; 136*e4b17023SJohn Marino tree rhs1; 137*e4b17023SJohn Marino 138*e4b17023SJohn Marino if (si->offsets[SSA_NAME_VERSION (lhs)] != -1) 139*e4b17023SJohn Marino { 140*e4b17023SJohn Marino if (counter_val >= max_size) 141*e4b17023SJohn Marino { 142*e4b17023SJohn Marino ret = max_size; 143*e4b17023SJohn Marino break; 144*e4b17023SJohn Marino } 145*e4b17023SJohn Marino 146*e4b17023SJohn Marino ret -= counter_val - si->offsets[SSA_NAME_VERSION (lhs)]; 147*e4b17023SJohn Marino break; 148*e4b17023SJohn Marino } 149*e4b17023SJohn Marino 150*e4b17023SJohn Marino stmt = SSA_NAME_DEF_STMT (lhs); 151*e4b17023SJohn Marino 152*e4b17023SJohn Marino if (!is_gimple_assign (stmt) || gimple_assign_lhs (stmt) != lhs) 153*e4b17023SJohn Marino return (unsigned HOST_WIDE_INT) -1; 154*e4b17023SJohn Marino 155*e4b17023SJohn Marino rhs_code = gimple_assign_rhs_code (stmt); 156*e4b17023SJohn Marino rhs1 = gimple_assign_rhs1 (stmt); 157*e4b17023SJohn Marino if ((get_gimple_rhs_class (rhs_code) == GIMPLE_SINGLE_RHS 158*e4b17023SJohn Marino || gimple_assign_cast_p (stmt)) 159*e4b17023SJohn Marino && TREE_CODE (rhs1) == SSA_NAME) 160*e4b17023SJohn Marino { 161*e4b17023SJohn Marino lhs = rhs1; 162*e4b17023SJohn Marino continue; 163*e4b17023SJohn Marino } 164*e4b17023SJohn Marino 165*e4b17023SJohn Marino if ((rhs_code == POINTER_PLUS_EXPR 166*e4b17023SJohn Marino || rhs_code == PLUS_EXPR) 167*e4b17023SJohn Marino && TREE_CODE (rhs1) == SSA_NAME 168*e4b17023SJohn Marino && host_integerp (gimple_assign_rhs2 (stmt), 1)) 169*e4b17023SJohn Marino { 170*e4b17023SJohn Marino ret += tree_low_cst (gimple_assign_rhs2 (stmt), 1); 171*e4b17023SJohn Marino lhs = rhs1; 172*e4b17023SJohn Marino continue; 173*e4b17023SJohn Marino } 174*e4b17023SJohn Marino 175*e4b17023SJohn Marino if (rhs_code == ADDR_EXPR 176*e4b17023SJohn Marino && TREE_CODE (TREE_OPERAND (rhs1, 0)) == MEM_REF 177*e4b17023SJohn Marino && TREE_CODE (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 0)) == SSA_NAME 178*e4b17023SJohn Marino && host_integerp (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 1), 1)) 179*e4b17023SJohn Marino { 180*e4b17023SJohn Marino ret += tree_low_cst (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 1), 1); 181*e4b17023SJohn Marino lhs = TREE_OPERAND (TREE_OPERAND (rhs1, 0), 0); 182*e4b17023SJohn Marino continue; 183*e4b17023SJohn Marino } 184*e4b17023SJohn Marino 185*e4b17023SJohn Marino if (get_gimple_rhs_class (rhs_code) != GIMPLE_SINGLE_RHS) 186*e4b17023SJohn Marino return (unsigned HOST_WIDE_INT) -1; 187*e4b17023SJohn Marino 188*e4b17023SJohn Marino rhs = gimple_assign_rhs1 (stmt); 189*e4b17023SJohn Marino if (TREE_CODE (counter) != TREE_CODE (rhs)) 190*e4b17023SJohn Marino return (unsigned HOST_WIDE_INT) -1; 191*e4b17023SJohn Marino 192*e4b17023SJohn Marino if (TREE_CODE (counter) == COMPONENT_REF) 193*e4b17023SJohn Marino { 194*e4b17023SJohn Marino if (get_base_address (counter) != get_base_address (rhs) 195*e4b17023SJohn Marino || TREE_CODE (TREE_OPERAND (rhs, 1)) != FIELD_DECL 196*e4b17023SJohn Marino || TREE_OPERAND (counter, 1) != TREE_OPERAND (rhs, 1)) 197*e4b17023SJohn Marino return (unsigned HOST_WIDE_INT) -1; 198*e4b17023SJohn Marino } 199*e4b17023SJohn Marino else if (counter != rhs) 200*e4b17023SJohn Marino return (unsigned HOST_WIDE_INT) -1; 201*e4b17023SJohn Marino 202*e4b17023SJohn Marino lhs = NULL; 203*e4b17023SJohn Marino } 204*e4b17023SJohn Marino 205*e4b17023SJohn Marino lhs = orig_lhs; 206*e4b17023SJohn Marino val = ret + counter_val; 207*e4b17023SJohn Marino while (lhs) 208*e4b17023SJohn Marino { 209*e4b17023SJohn Marino enum tree_code rhs_code; 210*e4b17023SJohn Marino tree rhs1; 211*e4b17023SJohn Marino 212*e4b17023SJohn Marino if (si->offsets[SSA_NAME_VERSION (lhs)] != -1) 213*e4b17023SJohn Marino break; 214*e4b17023SJohn Marino 215*e4b17023SJohn Marino if (val >= max_size) 216*e4b17023SJohn Marino si->offsets[SSA_NAME_VERSION (lhs)] = max_size; 217*e4b17023SJohn Marino else 218*e4b17023SJohn Marino si->offsets[SSA_NAME_VERSION (lhs)] = val; 219*e4b17023SJohn Marino 220*e4b17023SJohn Marino stmt = SSA_NAME_DEF_STMT (lhs); 221*e4b17023SJohn Marino 222*e4b17023SJohn Marino rhs_code = gimple_assign_rhs_code (stmt); 223*e4b17023SJohn Marino rhs1 = gimple_assign_rhs1 (stmt); 224*e4b17023SJohn Marino if ((get_gimple_rhs_class (rhs_code) == GIMPLE_SINGLE_RHS 225*e4b17023SJohn Marino || gimple_assign_cast_p (stmt)) 226*e4b17023SJohn Marino && TREE_CODE (rhs1) == SSA_NAME) 227*e4b17023SJohn Marino { 228*e4b17023SJohn Marino lhs = rhs1; 229*e4b17023SJohn Marino continue; 230*e4b17023SJohn Marino } 231*e4b17023SJohn Marino 232*e4b17023SJohn Marino if ((rhs_code == POINTER_PLUS_EXPR 233*e4b17023SJohn Marino || rhs_code == PLUS_EXPR) 234*e4b17023SJohn Marino && TREE_CODE (rhs1) == SSA_NAME 235*e4b17023SJohn Marino && host_integerp (gimple_assign_rhs2 (stmt), 1)) 236*e4b17023SJohn Marino { 237*e4b17023SJohn Marino val -= tree_low_cst (gimple_assign_rhs2 (stmt), 1); 238*e4b17023SJohn Marino lhs = rhs1; 239*e4b17023SJohn Marino continue; 240*e4b17023SJohn Marino } 241*e4b17023SJohn Marino 242*e4b17023SJohn Marino if (rhs_code == ADDR_EXPR 243*e4b17023SJohn Marino && TREE_CODE (TREE_OPERAND (rhs1, 0)) == MEM_REF 244*e4b17023SJohn Marino && TREE_CODE (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 0)) == SSA_NAME 245*e4b17023SJohn Marino && host_integerp (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 1), 1)) 246*e4b17023SJohn Marino { 247*e4b17023SJohn Marino val -= tree_low_cst (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 1), 1); 248*e4b17023SJohn Marino lhs = TREE_OPERAND (TREE_OPERAND (rhs1, 0), 0); 249*e4b17023SJohn Marino continue; 250*e4b17023SJohn Marino } 251*e4b17023SJohn Marino 252*e4b17023SJohn Marino lhs = NULL; 253*e4b17023SJohn Marino } 254*e4b17023SJohn Marino 255*e4b17023SJohn Marino return ret; 256*e4b17023SJohn Marino } 257*e4b17023SJohn Marino 258*e4b17023SJohn Marino 259*e4b17023SJohn Marino /* Called by walk_tree to look for references to va_list variables. */ 260*e4b17023SJohn Marino 261*e4b17023SJohn Marino static tree 262*e4b17023SJohn Marino find_va_list_reference (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, 263*e4b17023SJohn Marino void *data) 264*e4b17023SJohn Marino { 265*e4b17023SJohn Marino bitmap va_list_vars = (bitmap) ((struct walk_stmt_info *) data)->info; 266*e4b17023SJohn Marino tree var = *tp; 267*e4b17023SJohn Marino 268*e4b17023SJohn Marino if (TREE_CODE (var) == SSA_NAME) 269*e4b17023SJohn Marino var = SSA_NAME_VAR (var); 270*e4b17023SJohn Marino 271*e4b17023SJohn Marino if (TREE_CODE (var) == VAR_DECL 272*e4b17023SJohn Marino && bitmap_bit_p (va_list_vars, DECL_UID (var))) 273*e4b17023SJohn Marino return var; 274*e4b17023SJohn Marino 275*e4b17023SJohn Marino return NULL_TREE; 276*e4b17023SJohn Marino } 277*e4b17023SJohn Marino 278*e4b17023SJohn Marino 279*e4b17023SJohn Marino /* Helper function of va_list_counter_struct_op. Compute 280*e4b17023SJohn Marino cfun->va_list_{g,f}pr_size. AP is a va_list GPR/FPR counter, 281*e4b17023SJohn Marino if WRITE_P is true, seen in AP = VAR, otherwise seen in VAR = AP 282*e4b17023SJohn Marino statement. GPR_P is true if AP is a GPR counter, false if it is 283*e4b17023SJohn Marino a FPR counter. */ 284*e4b17023SJohn Marino 285*e4b17023SJohn Marino static void 286*e4b17023SJohn Marino va_list_counter_op (struct stdarg_info *si, tree ap, tree var, bool gpr_p, 287*e4b17023SJohn Marino bool write_p) 288*e4b17023SJohn Marino { 289*e4b17023SJohn Marino unsigned HOST_WIDE_INT increment; 290*e4b17023SJohn Marino 291*e4b17023SJohn Marino if (si->compute_sizes < 0) 292*e4b17023SJohn Marino { 293*e4b17023SJohn Marino si->compute_sizes = 0; 294*e4b17023SJohn Marino if (si->va_start_count == 1 295*e4b17023SJohn Marino && reachable_at_most_once (si->bb, si->va_start_bb)) 296*e4b17023SJohn Marino si->compute_sizes = 1; 297*e4b17023SJohn Marino 298*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS)) 299*e4b17023SJohn Marino fprintf (dump_file, 300*e4b17023SJohn Marino "bb%d will %sbe executed at most once for each va_start " 301*e4b17023SJohn Marino "in bb%d\n", si->bb->index, si->compute_sizes ? "" : "not ", 302*e4b17023SJohn Marino si->va_start_bb->index); 303*e4b17023SJohn Marino } 304*e4b17023SJohn Marino 305*e4b17023SJohn Marino if (write_p 306*e4b17023SJohn Marino && si->compute_sizes 307*e4b17023SJohn Marino && (increment = va_list_counter_bump (si, ap, var, gpr_p)) + 1 > 1) 308*e4b17023SJohn Marino { 309*e4b17023SJohn Marino if (gpr_p && cfun->va_list_gpr_size + increment < VA_LIST_MAX_GPR_SIZE) 310*e4b17023SJohn Marino { 311*e4b17023SJohn Marino cfun->va_list_gpr_size += increment; 312*e4b17023SJohn Marino return; 313*e4b17023SJohn Marino } 314*e4b17023SJohn Marino 315*e4b17023SJohn Marino if (!gpr_p && cfun->va_list_fpr_size + increment < VA_LIST_MAX_FPR_SIZE) 316*e4b17023SJohn Marino { 317*e4b17023SJohn Marino cfun->va_list_fpr_size += increment; 318*e4b17023SJohn Marino return; 319*e4b17023SJohn Marino } 320*e4b17023SJohn Marino } 321*e4b17023SJohn Marino 322*e4b17023SJohn Marino if (write_p || !si->compute_sizes) 323*e4b17023SJohn Marino { 324*e4b17023SJohn Marino if (gpr_p) 325*e4b17023SJohn Marino cfun->va_list_gpr_size = VA_LIST_MAX_GPR_SIZE; 326*e4b17023SJohn Marino else 327*e4b17023SJohn Marino cfun->va_list_fpr_size = VA_LIST_MAX_FPR_SIZE; 328*e4b17023SJohn Marino } 329*e4b17023SJohn Marino } 330*e4b17023SJohn Marino 331*e4b17023SJohn Marino 332*e4b17023SJohn Marino /* If AP is a va_list GPR/FPR counter, compute cfun->va_list_{g,f}pr_size. 333*e4b17023SJohn Marino If WRITE_P is true, AP has been seen in AP = VAR assignment, if WRITE_P 334*e4b17023SJohn Marino is false, AP has been seen in VAR = AP assignment. 335*e4b17023SJohn Marino Return true if the AP = VAR (resp. VAR = AP) statement is a recognized 336*e4b17023SJohn Marino va_arg operation that doesn't cause the va_list variable to escape 337*e4b17023SJohn Marino current function. */ 338*e4b17023SJohn Marino 339*e4b17023SJohn Marino static bool 340*e4b17023SJohn Marino va_list_counter_struct_op (struct stdarg_info *si, tree ap, tree var, 341*e4b17023SJohn Marino bool write_p) 342*e4b17023SJohn Marino { 343*e4b17023SJohn Marino tree base; 344*e4b17023SJohn Marino 345*e4b17023SJohn Marino if (TREE_CODE (ap) != COMPONENT_REF 346*e4b17023SJohn Marino || TREE_CODE (TREE_OPERAND (ap, 1)) != FIELD_DECL) 347*e4b17023SJohn Marino return false; 348*e4b17023SJohn Marino 349*e4b17023SJohn Marino if (TREE_CODE (var) != SSA_NAME 350*e4b17023SJohn Marino || bitmap_bit_p (si->va_list_vars, DECL_UID (SSA_NAME_VAR (var)))) 351*e4b17023SJohn Marino return false; 352*e4b17023SJohn Marino 353*e4b17023SJohn Marino base = get_base_address (ap); 354*e4b17023SJohn Marino if (TREE_CODE (base) != VAR_DECL 355*e4b17023SJohn Marino || !bitmap_bit_p (si->va_list_vars, DECL_UID (base))) 356*e4b17023SJohn Marino return false; 357*e4b17023SJohn Marino 358*e4b17023SJohn Marino if (TREE_OPERAND (ap, 1) == va_list_gpr_counter_field) 359*e4b17023SJohn Marino va_list_counter_op (si, ap, var, true, write_p); 360*e4b17023SJohn Marino else if (TREE_OPERAND (ap, 1) == va_list_fpr_counter_field) 361*e4b17023SJohn Marino va_list_counter_op (si, ap, var, false, write_p); 362*e4b17023SJohn Marino 363*e4b17023SJohn Marino return true; 364*e4b17023SJohn Marino } 365*e4b17023SJohn Marino 366*e4b17023SJohn Marino 367*e4b17023SJohn Marino /* Check for TEM = AP. Return true if found and the caller shouldn't 368*e4b17023SJohn Marino search for va_list references in the statement. */ 369*e4b17023SJohn Marino 370*e4b17023SJohn Marino static bool 371*e4b17023SJohn Marino va_list_ptr_read (struct stdarg_info *si, tree ap, tree tem) 372*e4b17023SJohn Marino { 373*e4b17023SJohn Marino if (TREE_CODE (ap) != VAR_DECL 374*e4b17023SJohn Marino || !bitmap_bit_p (si->va_list_vars, DECL_UID (ap))) 375*e4b17023SJohn Marino return false; 376*e4b17023SJohn Marino 377*e4b17023SJohn Marino if (TREE_CODE (tem) != SSA_NAME 378*e4b17023SJohn Marino || bitmap_bit_p (si->va_list_vars, 379*e4b17023SJohn Marino DECL_UID (SSA_NAME_VAR (tem))) 380*e4b17023SJohn Marino || is_global_var (SSA_NAME_VAR (tem))) 381*e4b17023SJohn Marino return false; 382*e4b17023SJohn Marino 383*e4b17023SJohn Marino if (si->compute_sizes < 0) 384*e4b17023SJohn Marino { 385*e4b17023SJohn Marino si->compute_sizes = 0; 386*e4b17023SJohn Marino if (si->va_start_count == 1 387*e4b17023SJohn Marino && reachable_at_most_once (si->bb, si->va_start_bb)) 388*e4b17023SJohn Marino si->compute_sizes = 1; 389*e4b17023SJohn Marino 390*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS)) 391*e4b17023SJohn Marino fprintf (dump_file, 392*e4b17023SJohn Marino "bb%d will %sbe executed at most once for each va_start " 393*e4b17023SJohn Marino "in bb%d\n", si->bb->index, si->compute_sizes ? "" : "not ", 394*e4b17023SJohn Marino si->va_start_bb->index); 395*e4b17023SJohn Marino } 396*e4b17023SJohn Marino 397*e4b17023SJohn Marino /* For void * or char * va_list types, there is just one counter. 398*e4b17023SJohn Marino If va_arg is used in a loop, we don't know how many registers need 399*e4b17023SJohn Marino saving. */ 400*e4b17023SJohn Marino if (! si->compute_sizes) 401*e4b17023SJohn Marino return false; 402*e4b17023SJohn Marino 403*e4b17023SJohn Marino if (va_list_counter_bump (si, ap, tem, true) == (unsigned HOST_WIDE_INT) -1) 404*e4b17023SJohn Marino return false; 405*e4b17023SJohn Marino 406*e4b17023SJohn Marino /* Note the temporary, as we need to track whether it doesn't escape 407*e4b17023SJohn Marino the current function. */ 408*e4b17023SJohn Marino bitmap_set_bit (si->va_list_escape_vars, 409*e4b17023SJohn Marino DECL_UID (SSA_NAME_VAR (tem))); 410*e4b17023SJohn Marino return true; 411*e4b17023SJohn Marino } 412*e4b17023SJohn Marino 413*e4b17023SJohn Marino 414*e4b17023SJohn Marino /* Check for: 415*e4b17023SJohn Marino tem1 = AP; 416*e4b17023SJohn Marino TEM2 = tem1 + CST; 417*e4b17023SJohn Marino AP = TEM2; 418*e4b17023SJohn Marino sequence and update cfun->va_list_gpr_size. Return true if found. */ 419*e4b17023SJohn Marino 420*e4b17023SJohn Marino static bool 421*e4b17023SJohn Marino va_list_ptr_write (struct stdarg_info *si, tree ap, tree tem2) 422*e4b17023SJohn Marino { 423*e4b17023SJohn Marino unsigned HOST_WIDE_INT increment; 424*e4b17023SJohn Marino 425*e4b17023SJohn Marino if (TREE_CODE (ap) != VAR_DECL 426*e4b17023SJohn Marino || !bitmap_bit_p (si->va_list_vars, DECL_UID (ap))) 427*e4b17023SJohn Marino return false; 428*e4b17023SJohn Marino 429*e4b17023SJohn Marino if (TREE_CODE (tem2) != SSA_NAME 430*e4b17023SJohn Marino || bitmap_bit_p (si->va_list_vars, DECL_UID (SSA_NAME_VAR (tem2)))) 431*e4b17023SJohn Marino return false; 432*e4b17023SJohn Marino 433*e4b17023SJohn Marino if (si->compute_sizes <= 0) 434*e4b17023SJohn Marino return false; 435*e4b17023SJohn Marino 436*e4b17023SJohn Marino increment = va_list_counter_bump (si, ap, tem2, true); 437*e4b17023SJohn Marino if (increment + 1 <= 1) 438*e4b17023SJohn Marino return false; 439*e4b17023SJohn Marino 440*e4b17023SJohn Marino if (cfun->va_list_gpr_size + increment < VA_LIST_MAX_GPR_SIZE) 441*e4b17023SJohn Marino cfun->va_list_gpr_size += increment; 442*e4b17023SJohn Marino else 443*e4b17023SJohn Marino cfun->va_list_gpr_size = VA_LIST_MAX_GPR_SIZE; 444*e4b17023SJohn Marino 445*e4b17023SJohn Marino return true; 446*e4b17023SJohn Marino } 447*e4b17023SJohn Marino 448*e4b17023SJohn Marino 449*e4b17023SJohn Marino /* If RHS is X, (some type *) X or X + CST for X a temporary variable 450*e4b17023SJohn Marino containing value of some va_list variable plus optionally some constant, 451*e4b17023SJohn Marino either set si->va_list_escapes or add LHS to si->va_list_escape_vars, 452*e4b17023SJohn Marino depending whether LHS is a function local temporary. */ 453*e4b17023SJohn Marino 454*e4b17023SJohn Marino static void 455*e4b17023SJohn Marino check_va_list_escapes (struct stdarg_info *si, tree lhs, tree rhs) 456*e4b17023SJohn Marino { 457*e4b17023SJohn Marino if (! POINTER_TYPE_P (TREE_TYPE (rhs))) 458*e4b17023SJohn Marino return; 459*e4b17023SJohn Marino 460*e4b17023SJohn Marino if (TREE_CODE (rhs) == SSA_NAME) 461*e4b17023SJohn Marino { 462*e4b17023SJohn Marino if (! bitmap_bit_p (si->va_list_escape_vars, 463*e4b17023SJohn Marino DECL_UID (SSA_NAME_VAR (rhs)))) 464*e4b17023SJohn Marino return; 465*e4b17023SJohn Marino } 466*e4b17023SJohn Marino else if (TREE_CODE (rhs) == ADDR_EXPR 467*e4b17023SJohn Marino && TREE_CODE (TREE_OPERAND (rhs, 0)) == MEM_REF 468*e4b17023SJohn Marino && TREE_CODE (TREE_OPERAND (TREE_OPERAND (rhs, 0), 0)) == SSA_NAME) 469*e4b17023SJohn Marino { 470*e4b17023SJohn Marino if (! bitmap_bit_p (si->va_list_escape_vars, 471*e4b17023SJohn Marino DECL_UID (SSA_NAME_VAR (TREE_OPERAND 472*e4b17023SJohn Marino (TREE_OPERAND (rhs, 0), 0))))) 473*e4b17023SJohn Marino return; 474*e4b17023SJohn Marino } 475*e4b17023SJohn Marino else 476*e4b17023SJohn Marino return; 477*e4b17023SJohn Marino 478*e4b17023SJohn Marino if (TREE_CODE (lhs) != SSA_NAME || is_global_var (SSA_NAME_VAR (lhs))) 479*e4b17023SJohn Marino { 480*e4b17023SJohn Marino si->va_list_escapes = true; 481*e4b17023SJohn Marino return; 482*e4b17023SJohn Marino } 483*e4b17023SJohn Marino 484*e4b17023SJohn Marino if (si->compute_sizes < 0) 485*e4b17023SJohn Marino { 486*e4b17023SJohn Marino si->compute_sizes = 0; 487*e4b17023SJohn Marino if (si->va_start_count == 1 488*e4b17023SJohn Marino && reachable_at_most_once (si->bb, si->va_start_bb)) 489*e4b17023SJohn Marino si->compute_sizes = 1; 490*e4b17023SJohn Marino 491*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS)) 492*e4b17023SJohn Marino fprintf (dump_file, 493*e4b17023SJohn Marino "bb%d will %sbe executed at most once for each va_start " 494*e4b17023SJohn Marino "in bb%d\n", si->bb->index, si->compute_sizes ? "" : "not ", 495*e4b17023SJohn Marino si->va_start_bb->index); 496*e4b17023SJohn Marino } 497*e4b17023SJohn Marino 498*e4b17023SJohn Marino /* For void * or char * va_list types, there is just one counter. 499*e4b17023SJohn Marino If va_arg is used in a loop, we don't know how many registers need 500*e4b17023SJohn Marino saving. */ 501*e4b17023SJohn Marino if (! si->compute_sizes) 502*e4b17023SJohn Marino { 503*e4b17023SJohn Marino si->va_list_escapes = true; 504*e4b17023SJohn Marino return; 505*e4b17023SJohn Marino } 506*e4b17023SJohn Marino 507*e4b17023SJohn Marino if (va_list_counter_bump (si, si->va_start_ap, lhs, true) 508*e4b17023SJohn Marino == (unsigned HOST_WIDE_INT) -1) 509*e4b17023SJohn Marino { 510*e4b17023SJohn Marino si->va_list_escapes = true; 511*e4b17023SJohn Marino return; 512*e4b17023SJohn Marino } 513*e4b17023SJohn Marino 514*e4b17023SJohn Marino bitmap_set_bit (si->va_list_escape_vars, 515*e4b17023SJohn Marino DECL_UID (SSA_NAME_VAR (lhs))); 516*e4b17023SJohn Marino } 517*e4b17023SJohn Marino 518*e4b17023SJohn Marino 519*e4b17023SJohn Marino /* Check all uses of temporaries from si->va_list_escape_vars bitmap. 520*e4b17023SJohn Marino Return true if va_list might be escaping. */ 521*e4b17023SJohn Marino 522*e4b17023SJohn Marino static bool 523*e4b17023SJohn Marino check_all_va_list_escapes (struct stdarg_info *si) 524*e4b17023SJohn Marino { 525*e4b17023SJohn Marino basic_block bb; 526*e4b17023SJohn Marino 527*e4b17023SJohn Marino FOR_EACH_BB (bb) 528*e4b17023SJohn Marino { 529*e4b17023SJohn Marino gimple_stmt_iterator i; 530*e4b17023SJohn Marino 531*e4b17023SJohn Marino for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i)) 532*e4b17023SJohn Marino { 533*e4b17023SJohn Marino gimple stmt = gsi_stmt (i); 534*e4b17023SJohn Marino tree use; 535*e4b17023SJohn Marino ssa_op_iter iter; 536*e4b17023SJohn Marino 537*e4b17023SJohn Marino if (is_gimple_debug (stmt)) 538*e4b17023SJohn Marino continue; 539*e4b17023SJohn Marino 540*e4b17023SJohn Marino FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_ALL_USES) 541*e4b17023SJohn Marino { 542*e4b17023SJohn Marino if (! bitmap_bit_p (si->va_list_escape_vars, 543*e4b17023SJohn Marino DECL_UID (SSA_NAME_VAR (use)))) 544*e4b17023SJohn Marino continue; 545*e4b17023SJohn Marino 546*e4b17023SJohn Marino if (is_gimple_assign (stmt)) 547*e4b17023SJohn Marino { 548*e4b17023SJohn Marino tree rhs = gimple_assign_rhs1 (stmt); 549*e4b17023SJohn Marino enum tree_code rhs_code = gimple_assign_rhs_code (stmt); 550*e4b17023SJohn Marino 551*e4b17023SJohn Marino /* x = *ap_temp; */ 552*e4b17023SJohn Marino if (rhs_code == MEM_REF 553*e4b17023SJohn Marino && TREE_OPERAND (rhs, 0) == use 554*e4b17023SJohn Marino && TYPE_SIZE_UNIT (TREE_TYPE (rhs)) 555*e4b17023SJohn Marino && host_integerp (TYPE_SIZE_UNIT (TREE_TYPE (rhs)), 1) 556*e4b17023SJohn Marino && si->offsets[SSA_NAME_VERSION (use)] != -1) 557*e4b17023SJohn Marino { 558*e4b17023SJohn Marino unsigned HOST_WIDE_INT gpr_size; 559*e4b17023SJohn Marino tree access_size = TYPE_SIZE_UNIT (TREE_TYPE (rhs)); 560*e4b17023SJohn Marino 561*e4b17023SJohn Marino gpr_size = si->offsets[SSA_NAME_VERSION (use)] 562*e4b17023SJohn Marino + tree_low_cst (TREE_OPERAND (rhs, 1), 0) 563*e4b17023SJohn Marino + tree_low_cst (access_size, 1); 564*e4b17023SJohn Marino if (gpr_size >= VA_LIST_MAX_GPR_SIZE) 565*e4b17023SJohn Marino cfun->va_list_gpr_size = VA_LIST_MAX_GPR_SIZE; 566*e4b17023SJohn Marino else if (gpr_size > cfun->va_list_gpr_size) 567*e4b17023SJohn Marino cfun->va_list_gpr_size = gpr_size; 568*e4b17023SJohn Marino continue; 569*e4b17023SJohn Marino } 570*e4b17023SJohn Marino 571*e4b17023SJohn Marino /* va_arg sequences may contain 572*e4b17023SJohn Marino other_ap_temp = ap_temp; 573*e4b17023SJohn Marino other_ap_temp = ap_temp + constant; 574*e4b17023SJohn Marino other_ap_temp = (some_type *) ap_temp; 575*e4b17023SJohn Marino ap = ap_temp; 576*e4b17023SJohn Marino statements. */ 577*e4b17023SJohn Marino if (rhs == use 578*e4b17023SJohn Marino && ((rhs_code == POINTER_PLUS_EXPR 579*e4b17023SJohn Marino && (TREE_CODE (gimple_assign_rhs2 (stmt)) 580*e4b17023SJohn Marino == INTEGER_CST)) 581*e4b17023SJohn Marino || gimple_assign_cast_p (stmt) 582*e4b17023SJohn Marino || (get_gimple_rhs_class (rhs_code) 583*e4b17023SJohn Marino == GIMPLE_SINGLE_RHS))) 584*e4b17023SJohn Marino { 585*e4b17023SJohn Marino tree lhs = gimple_assign_lhs (stmt); 586*e4b17023SJohn Marino 587*e4b17023SJohn Marino if (TREE_CODE (lhs) == SSA_NAME 588*e4b17023SJohn Marino && bitmap_bit_p (si->va_list_escape_vars, 589*e4b17023SJohn Marino DECL_UID (SSA_NAME_VAR (lhs)))) 590*e4b17023SJohn Marino continue; 591*e4b17023SJohn Marino 592*e4b17023SJohn Marino if (TREE_CODE (lhs) == VAR_DECL 593*e4b17023SJohn Marino && bitmap_bit_p (si->va_list_vars, 594*e4b17023SJohn Marino DECL_UID (lhs))) 595*e4b17023SJohn Marino continue; 596*e4b17023SJohn Marino } 597*e4b17023SJohn Marino else if (rhs_code == ADDR_EXPR 598*e4b17023SJohn Marino && TREE_CODE (TREE_OPERAND (rhs, 0)) == MEM_REF 599*e4b17023SJohn Marino && TREE_OPERAND (TREE_OPERAND (rhs, 0), 0) == use) 600*e4b17023SJohn Marino { 601*e4b17023SJohn Marino tree lhs = gimple_assign_lhs (stmt); 602*e4b17023SJohn Marino 603*e4b17023SJohn Marino if (bitmap_bit_p (si->va_list_escape_vars, 604*e4b17023SJohn Marino DECL_UID (SSA_NAME_VAR (lhs)))) 605*e4b17023SJohn Marino continue; 606*e4b17023SJohn Marino } 607*e4b17023SJohn Marino } 608*e4b17023SJohn Marino 609*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS)) 610*e4b17023SJohn Marino { 611*e4b17023SJohn Marino fputs ("va_list escapes in ", dump_file); 612*e4b17023SJohn Marino print_gimple_stmt (dump_file, stmt, 0, dump_flags); 613*e4b17023SJohn Marino fputc ('\n', dump_file); 614*e4b17023SJohn Marino } 615*e4b17023SJohn Marino return true; 616*e4b17023SJohn Marino } 617*e4b17023SJohn Marino } 618*e4b17023SJohn Marino } 619*e4b17023SJohn Marino 620*e4b17023SJohn Marino return false; 621*e4b17023SJohn Marino } 622*e4b17023SJohn Marino 623*e4b17023SJohn Marino 624*e4b17023SJohn Marino /* Return true if this optimization pass should be done. 625*e4b17023SJohn Marino It makes only sense for stdarg functions. */ 626*e4b17023SJohn Marino 627*e4b17023SJohn Marino static bool 628*e4b17023SJohn Marino gate_optimize_stdarg (void) 629*e4b17023SJohn Marino { 630*e4b17023SJohn Marino /* This optimization is only for stdarg functions. */ 631*e4b17023SJohn Marino return cfun->stdarg != 0; 632*e4b17023SJohn Marino } 633*e4b17023SJohn Marino 634*e4b17023SJohn Marino 635*e4b17023SJohn Marino /* Entry point to the stdarg optimization pass. */ 636*e4b17023SJohn Marino 637*e4b17023SJohn Marino static unsigned int 638*e4b17023SJohn Marino execute_optimize_stdarg (void) 639*e4b17023SJohn Marino { 640*e4b17023SJohn Marino basic_block bb; 641*e4b17023SJohn Marino bool va_list_escapes = false; 642*e4b17023SJohn Marino bool va_list_simple_ptr; 643*e4b17023SJohn Marino struct stdarg_info si; 644*e4b17023SJohn Marino struct walk_stmt_info wi; 645*e4b17023SJohn Marino const char *funcname = NULL; 646*e4b17023SJohn Marino tree cfun_va_list; 647*e4b17023SJohn Marino 648*e4b17023SJohn Marino cfun->va_list_gpr_size = 0; 649*e4b17023SJohn Marino cfun->va_list_fpr_size = 0; 650*e4b17023SJohn Marino memset (&si, 0, sizeof (si)); 651*e4b17023SJohn Marino si.va_list_vars = BITMAP_ALLOC (NULL); 652*e4b17023SJohn Marino si.va_list_escape_vars = BITMAP_ALLOC (NULL); 653*e4b17023SJohn Marino 654*e4b17023SJohn Marino if (dump_file) 655*e4b17023SJohn Marino funcname = lang_hooks.decl_printable_name (current_function_decl, 2); 656*e4b17023SJohn Marino 657*e4b17023SJohn Marino cfun_va_list = targetm.fn_abi_va_list (cfun->decl); 658*e4b17023SJohn Marino va_list_simple_ptr = POINTER_TYPE_P (cfun_va_list) 659*e4b17023SJohn Marino && (TREE_TYPE (cfun_va_list) == void_type_node 660*e4b17023SJohn Marino || TREE_TYPE (cfun_va_list) == char_type_node); 661*e4b17023SJohn Marino gcc_assert (is_gimple_reg_type (cfun_va_list) == va_list_simple_ptr); 662*e4b17023SJohn Marino 663*e4b17023SJohn Marino FOR_EACH_BB (bb) 664*e4b17023SJohn Marino { 665*e4b17023SJohn Marino gimple_stmt_iterator i; 666*e4b17023SJohn Marino 667*e4b17023SJohn Marino for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i)) 668*e4b17023SJohn Marino { 669*e4b17023SJohn Marino gimple stmt = gsi_stmt (i); 670*e4b17023SJohn Marino tree callee, ap; 671*e4b17023SJohn Marino 672*e4b17023SJohn Marino if (!is_gimple_call (stmt)) 673*e4b17023SJohn Marino continue; 674*e4b17023SJohn Marino 675*e4b17023SJohn Marino callee = gimple_call_fndecl (stmt); 676*e4b17023SJohn Marino if (!callee 677*e4b17023SJohn Marino || DECL_BUILT_IN_CLASS (callee) != BUILT_IN_NORMAL) 678*e4b17023SJohn Marino continue; 679*e4b17023SJohn Marino 680*e4b17023SJohn Marino switch (DECL_FUNCTION_CODE (callee)) 681*e4b17023SJohn Marino { 682*e4b17023SJohn Marino case BUILT_IN_VA_START: 683*e4b17023SJohn Marino break; 684*e4b17023SJohn Marino /* If old style builtins are used, don't optimize anything. */ 685*e4b17023SJohn Marino case BUILT_IN_SAVEREGS: 686*e4b17023SJohn Marino case BUILT_IN_NEXT_ARG: 687*e4b17023SJohn Marino va_list_escapes = true; 688*e4b17023SJohn Marino continue; 689*e4b17023SJohn Marino default: 690*e4b17023SJohn Marino continue; 691*e4b17023SJohn Marino } 692*e4b17023SJohn Marino 693*e4b17023SJohn Marino si.va_start_count++; 694*e4b17023SJohn Marino ap = gimple_call_arg (stmt, 0); 695*e4b17023SJohn Marino 696*e4b17023SJohn Marino if (TREE_CODE (ap) != ADDR_EXPR) 697*e4b17023SJohn Marino { 698*e4b17023SJohn Marino va_list_escapes = true; 699*e4b17023SJohn Marino break; 700*e4b17023SJohn Marino } 701*e4b17023SJohn Marino ap = TREE_OPERAND (ap, 0); 702*e4b17023SJohn Marino if (TREE_CODE (ap) == ARRAY_REF) 703*e4b17023SJohn Marino { 704*e4b17023SJohn Marino if (! integer_zerop (TREE_OPERAND (ap, 1))) 705*e4b17023SJohn Marino { 706*e4b17023SJohn Marino va_list_escapes = true; 707*e4b17023SJohn Marino break; 708*e4b17023SJohn Marino } 709*e4b17023SJohn Marino ap = TREE_OPERAND (ap, 0); 710*e4b17023SJohn Marino } 711*e4b17023SJohn Marino if (TYPE_MAIN_VARIANT (TREE_TYPE (ap)) 712*e4b17023SJohn Marino != TYPE_MAIN_VARIANT (targetm.fn_abi_va_list (cfun->decl)) 713*e4b17023SJohn Marino || TREE_CODE (ap) != VAR_DECL) 714*e4b17023SJohn Marino { 715*e4b17023SJohn Marino va_list_escapes = true; 716*e4b17023SJohn Marino break; 717*e4b17023SJohn Marino } 718*e4b17023SJohn Marino 719*e4b17023SJohn Marino if (is_global_var (ap)) 720*e4b17023SJohn Marino { 721*e4b17023SJohn Marino va_list_escapes = true; 722*e4b17023SJohn Marino break; 723*e4b17023SJohn Marino } 724*e4b17023SJohn Marino 725*e4b17023SJohn Marino bitmap_set_bit (si.va_list_vars, DECL_UID (ap)); 726*e4b17023SJohn Marino 727*e4b17023SJohn Marino /* VA_START_BB and VA_START_AP will be only used if there is just 728*e4b17023SJohn Marino one va_start in the function. */ 729*e4b17023SJohn Marino si.va_start_bb = bb; 730*e4b17023SJohn Marino si.va_start_ap = ap; 731*e4b17023SJohn Marino } 732*e4b17023SJohn Marino 733*e4b17023SJohn Marino if (va_list_escapes) 734*e4b17023SJohn Marino break; 735*e4b17023SJohn Marino } 736*e4b17023SJohn Marino 737*e4b17023SJohn Marino /* If there were no va_start uses in the function, there is no need to 738*e4b17023SJohn Marino save anything. */ 739*e4b17023SJohn Marino if (si.va_start_count == 0) 740*e4b17023SJohn Marino goto finish; 741*e4b17023SJohn Marino 742*e4b17023SJohn Marino /* If some va_list arguments weren't local, we can't optimize. */ 743*e4b17023SJohn Marino if (va_list_escapes) 744*e4b17023SJohn Marino goto finish; 745*e4b17023SJohn Marino 746*e4b17023SJohn Marino /* For void * or char * va_list, something useful can be done only 747*e4b17023SJohn Marino if there is just one va_start. */ 748*e4b17023SJohn Marino if (va_list_simple_ptr && si.va_start_count > 1) 749*e4b17023SJohn Marino { 750*e4b17023SJohn Marino va_list_escapes = true; 751*e4b17023SJohn Marino goto finish; 752*e4b17023SJohn Marino } 753*e4b17023SJohn Marino 754*e4b17023SJohn Marino /* For struct * va_list, if the backend didn't tell us what the counter fields 755*e4b17023SJohn Marino are, there is nothing more we can do. */ 756*e4b17023SJohn Marino if (!va_list_simple_ptr 757*e4b17023SJohn Marino && va_list_gpr_counter_field == NULL_TREE 758*e4b17023SJohn Marino && va_list_fpr_counter_field == NULL_TREE) 759*e4b17023SJohn Marino { 760*e4b17023SJohn Marino va_list_escapes = true; 761*e4b17023SJohn Marino goto finish; 762*e4b17023SJohn Marino } 763*e4b17023SJohn Marino 764*e4b17023SJohn Marino /* For void * or char * va_list there is just one counter 765*e4b17023SJohn Marino (va_list itself). Use VA_LIST_GPR_SIZE for it. */ 766*e4b17023SJohn Marino if (va_list_simple_ptr) 767*e4b17023SJohn Marino cfun->va_list_fpr_size = VA_LIST_MAX_FPR_SIZE; 768*e4b17023SJohn Marino 769*e4b17023SJohn Marino calculate_dominance_info (CDI_DOMINATORS); 770*e4b17023SJohn Marino memset (&wi, 0, sizeof (wi)); 771*e4b17023SJohn Marino wi.info = si.va_list_vars; 772*e4b17023SJohn Marino 773*e4b17023SJohn Marino FOR_EACH_BB (bb) 774*e4b17023SJohn Marino { 775*e4b17023SJohn Marino gimple_stmt_iterator i; 776*e4b17023SJohn Marino 777*e4b17023SJohn Marino si.compute_sizes = -1; 778*e4b17023SJohn Marino si.bb = bb; 779*e4b17023SJohn Marino 780*e4b17023SJohn Marino /* For va_list_simple_ptr, we have to check PHI nodes too. We treat 781*e4b17023SJohn Marino them as assignments for the purpose of escape analysis. This is 782*e4b17023SJohn Marino not needed for non-simple va_list because virtual phis don't perform 783*e4b17023SJohn Marino any real data movement. */ 784*e4b17023SJohn Marino if (va_list_simple_ptr) 785*e4b17023SJohn Marino { 786*e4b17023SJohn Marino tree lhs, rhs; 787*e4b17023SJohn Marino use_operand_p uop; 788*e4b17023SJohn Marino ssa_op_iter soi; 789*e4b17023SJohn Marino 790*e4b17023SJohn Marino for (i = gsi_start_phis (bb); !gsi_end_p (i); gsi_next (&i)) 791*e4b17023SJohn Marino { 792*e4b17023SJohn Marino gimple phi = gsi_stmt (i); 793*e4b17023SJohn Marino lhs = PHI_RESULT (phi); 794*e4b17023SJohn Marino 795*e4b17023SJohn Marino if (!is_gimple_reg (lhs)) 796*e4b17023SJohn Marino continue; 797*e4b17023SJohn Marino 798*e4b17023SJohn Marino FOR_EACH_PHI_ARG (uop, phi, soi, SSA_OP_USE) 799*e4b17023SJohn Marino { 800*e4b17023SJohn Marino rhs = USE_FROM_PTR (uop); 801*e4b17023SJohn Marino if (va_list_ptr_read (&si, rhs, lhs)) 802*e4b17023SJohn Marino continue; 803*e4b17023SJohn Marino else if (va_list_ptr_write (&si, lhs, rhs)) 804*e4b17023SJohn Marino continue; 805*e4b17023SJohn Marino else 806*e4b17023SJohn Marino check_va_list_escapes (&si, lhs, rhs); 807*e4b17023SJohn Marino 808*e4b17023SJohn Marino if (si.va_list_escapes) 809*e4b17023SJohn Marino { 810*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS)) 811*e4b17023SJohn Marino { 812*e4b17023SJohn Marino fputs ("va_list escapes in ", dump_file); 813*e4b17023SJohn Marino print_gimple_stmt (dump_file, phi, 0, dump_flags); 814*e4b17023SJohn Marino fputc ('\n', dump_file); 815*e4b17023SJohn Marino } 816*e4b17023SJohn Marino va_list_escapes = true; 817*e4b17023SJohn Marino } 818*e4b17023SJohn Marino } 819*e4b17023SJohn Marino } 820*e4b17023SJohn Marino } 821*e4b17023SJohn Marino 822*e4b17023SJohn Marino for (i = gsi_start_bb (bb); 823*e4b17023SJohn Marino !gsi_end_p (i) && !va_list_escapes; 824*e4b17023SJohn Marino gsi_next (&i)) 825*e4b17023SJohn Marino { 826*e4b17023SJohn Marino gimple stmt = gsi_stmt (i); 827*e4b17023SJohn Marino 828*e4b17023SJohn Marino /* Don't look at __builtin_va_{start,end}, they are ok. */ 829*e4b17023SJohn Marino if (is_gimple_call (stmt)) 830*e4b17023SJohn Marino { 831*e4b17023SJohn Marino tree callee = gimple_call_fndecl (stmt); 832*e4b17023SJohn Marino 833*e4b17023SJohn Marino if (callee 834*e4b17023SJohn Marino && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL 835*e4b17023SJohn Marino && (DECL_FUNCTION_CODE (callee) == BUILT_IN_VA_START 836*e4b17023SJohn Marino || DECL_FUNCTION_CODE (callee) == BUILT_IN_VA_END)) 837*e4b17023SJohn Marino continue; 838*e4b17023SJohn Marino } 839*e4b17023SJohn Marino 840*e4b17023SJohn Marino if (is_gimple_assign (stmt)) 841*e4b17023SJohn Marino { 842*e4b17023SJohn Marino tree lhs = gimple_assign_lhs (stmt); 843*e4b17023SJohn Marino tree rhs = gimple_assign_rhs1 (stmt); 844*e4b17023SJohn Marino 845*e4b17023SJohn Marino if (va_list_simple_ptr) 846*e4b17023SJohn Marino { 847*e4b17023SJohn Marino if (get_gimple_rhs_class (gimple_assign_rhs_code (stmt)) 848*e4b17023SJohn Marino == GIMPLE_SINGLE_RHS) 849*e4b17023SJohn Marino { 850*e4b17023SJohn Marino /* Check for ap ={v} {}. */ 851*e4b17023SJohn Marino if (TREE_CLOBBER_P (rhs)) 852*e4b17023SJohn Marino continue; 853*e4b17023SJohn Marino 854*e4b17023SJohn Marino /* Check for tem = ap. */ 855*e4b17023SJohn Marino else if (va_list_ptr_read (&si, rhs, lhs)) 856*e4b17023SJohn Marino continue; 857*e4b17023SJohn Marino 858*e4b17023SJohn Marino /* Check for the last insn in: 859*e4b17023SJohn Marino tem1 = ap; 860*e4b17023SJohn Marino tem2 = tem1 + CST; 861*e4b17023SJohn Marino ap = tem2; 862*e4b17023SJohn Marino sequence. */ 863*e4b17023SJohn Marino else if (va_list_ptr_write (&si, lhs, rhs)) 864*e4b17023SJohn Marino continue; 865*e4b17023SJohn Marino } 866*e4b17023SJohn Marino 867*e4b17023SJohn Marino if ((gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR 868*e4b17023SJohn Marino && TREE_CODE (gimple_assign_rhs2 (stmt)) == INTEGER_CST) 869*e4b17023SJohn Marino || CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (stmt)) 870*e4b17023SJohn Marino || (get_gimple_rhs_class (gimple_assign_rhs_code (stmt)) 871*e4b17023SJohn Marino == GIMPLE_SINGLE_RHS)) 872*e4b17023SJohn Marino check_va_list_escapes (&si, lhs, rhs); 873*e4b17023SJohn Marino } 874*e4b17023SJohn Marino else 875*e4b17023SJohn Marino { 876*e4b17023SJohn Marino if (get_gimple_rhs_class (gimple_assign_rhs_code (stmt)) 877*e4b17023SJohn Marino == GIMPLE_SINGLE_RHS) 878*e4b17023SJohn Marino { 879*e4b17023SJohn Marino /* Check for ap ={v} {}. */ 880*e4b17023SJohn Marino if (TREE_CLOBBER_P (rhs)) 881*e4b17023SJohn Marino continue; 882*e4b17023SJohn Marino 883*e4b17023SJohn Marino /* Check for ap[0].field = temp. */ 884*e4b17023SJohn Marino else if (va_list_counter_struct_op (&si, lhs, rhs, true)) 885*e4b17023SJohn Marino continue; 886*e4b17023SJohn Marino 887*e4b17023SJohn Marino /* Check for temp = ap[0].field. */ 888*e4b17023SJohn Marino else if (va_list_counter_struct_op (&si, rhs, lhs, 889*e4b17023SJohn Marino false)) 890*e4b17023SJohn Marino continue; 891*e4b17023SJohn Marino } 892*e4b17023SJohn Marino 893*e4b17023SJohn Marino /* Do any architecture specific checking. */ 894*e4b17023SJohn Marino if (targetm.stdarg_optimize_hook 895*e4b17023SJohn Marino && targetm.stdarg_optimize_hook (&si, stmt)) 896*e4b17023SJohn Marino continue; 897*e4b17023SJohn Marino } 898*e4b17023SJohn Marino } 899*e4b17023SJohn Marino else if (is_gimple_debug (stmt)) 900*e4b17023SJohn Marino continue; 901*e4b17023SJohn Marino 902*e4b17023SJohn Marino /* All other uses of va_list are either va_copy (that is not handled 903*e4b17023SJohn Marino in this optimization), taking address of va_list variable or 904*e4b17023SJohn Marino passing va_list to other functions (in that case va_list might 905*e4b17023SJohn Marino escape the function and therefore va_start needs to set it up 906*e4b17023SJohn Marino fully), or some unexpected use of va_list. None of these should 907*e4b17023SJohn Marino happen in a gimplified VA_ARG_EXPR. */ 908*e4b17023SJohn Marino if (si.va_list_escapes 909*e4b17023SJohn Marino || walk_gimple_op (stmt, find_va_list_reference, &wi)) 910*e4b17023SJohn Marino { 911*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS)) 912*e4b17023SJohn Marino { 913*e4b17023SJohn Marino fputs ("va_list escapes in ", dump_file); 914*e4b17023SJohn Marino print_gimple_stmt (dump_file, stmt, 0, dump_flags); 915*e4b17023SJohn Marino fputc ('\n', dump_file); 916*e4b17023SJohn Marino } 917*e4b17023SJohn Marino va_list_escapes = true; 918*e4b17023SJohn Marino } 919*e4b17023SJohn Marino } 920*e4b17023SJohn Marino 921*e4b17023SJohn Marino if (va_list_escapes) 922*e4b17023SJohn Marino break; 923*e4b17023SJohn Marino } 924*e4b17023SJohn Marino 925*e4b17023SJohn Marino if (! va_list_escapes 926*e4b17023SJohn Marino && va_list_simple_ptr 927*e4b17023SJohn Marino && ! bitmap_empty_p (si.va_list_escape_vars) 928*e4b17023SJohn Marino && check_all_va_list_escapes (&si)) 929*e4b17023SJohn Marino va_list_escapes = true; 930*e4b17023SJohn Marino 931*e4b17023SJohn Marino finish: 932*e4b17023SJohn Marino if (va_list_escapes) 933*e4b17023SJohn Marino { 934*e4b17023SJohn Marino cfun->va_list_gpr_size = VA_LIST_MAX_GPR_SIZE; 935*e4b17023SJohn Marino cfun->va_list_fpr_size = VA_LIST_MAX_FPR_SIZE; 936*e4b17023SJohn Marino } 937*e4b17023SJohn Marino BITMAP_FREE (si.va_list_vars); 938*e4b17023SJohn Marino BITMAP_FREE (si.va_list_escape_vars); 939*e4b17023SJohn Marino free (si.offsets); 940*e4b17023SJohn Marino if (dump_file) 941*e4b17023SJohn Marino { 942*e4b17023SJohn Marino fprintf (dump_file, "%s: va_list escapes %d, needs to save ", 943*e4b17023SJohn Marino funcname, (int) va_list_escapes); 944*e4b17023SJohn Marino if (cfun->va_list_gpr_size >= VA_LIST_MAX_GPR_SIZE) 945*e4b17023SJohn Marino fputs ("all", dump_file); 946*e4b17023SJohn Marino else 947*e4b17023SJohn Marino fprintf (dump_file, "%d", cfun->va_list_gpr_size); 948*e4b17023SJohn Marino fputs (" GPR units and ", dump_file); 949*e4b17023SJohn Marino if (cfun->va_list_fpr_size >= VA_LIST_MAX_FPR_SIZE) 950*e4b17023SJohn Marino fputs ("all", dump_file); 951*e4b17023SJohn Marino else 952*e4b17023SJohn Marino fprintf (dump_file, "%d", cfun->va_list_fpr_size); 953*e4b17023SJohn Marino fputs (" FPR units.\n", dump_file); 954*e4b17023SJohn Marino } 955*e4b17023SJohn Marino return 0; 956*e4b17023SJohn Marino } 957*e4b17023SJohn Marino 958*e4b17023SJohn Marino 959*e4b17023SJohn Marino struct gimple_opt_pass pass_stdarg = 960*e4b17023SJohn Marino { 961*e4b17023SJohn Marino { 962*e4b17023SJohn Marino GIMPLE_PASS, 963*e4b17023SJohn Marino "stdarg", /* name */ 964*e4b17023SJohn Marino gate_optimize_stdarg, /* gate */ 965*e4b17023SJohn Marino execute_optimize_stdarg, /* execute */ 966*e4b17023SJohn Marino NULL, /* sub */ 967*e4b17023SJohn Marino NULL, /* next */ 968*e4b17023SJohn Marino 0, /* static_pass_number */ 969*e4b17023SJohn Marino TV_NONE, /* tv_id */ 970*e4b17023SJohn Marino PROP_cfg | PROP_ssa, /* properties_required */ 971*e4b17023SJohn Marino 0, /* properties_provided */ 972*e4b17023SJohn Marino 0, /* properties_destroyed */ 973*e4b17023SJohn Marino 0, /* todo_flags_start */ 974*e4b17023SJohn Marino 0 /* todo_flags_finish */ 975*e4b17023SJohn Marino } 976*e4b17023SJohn Marino }; 977