Example #1
0
void
gimple_gen_ic_profiler (histogram_value value, unsigned tag, unsigned base)
{
  tree tmp1;
  gassign *stmt1, *stmt2, *stmt3;
  gimple stmt = value->hvalue.stmt;
  gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
  tree ref_ptr = tree_coverage_counter_addr (tag, base);

  if ( (PARAM_VALUE (PARAM_INDIR_CALL_TOPN_PROFILE) &&
        tag == GCOV_COUNTER_V_INDIR) ||
       (!PARAM_VALUE (PARAM_INDIR_CALL_TOPN_PROFILE) &&
        tag == GCOV_COUNTER_ICALL_TOPNV))
    return;

  ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr,
				      true, NULL_TREE, true, GSI_SAME_STMT);

  /* Insert code:

    stmt1: __gcov_indirect_call_counters = get_relevant_counter_ptr ();
    stmt2: tmp1 = (void *) (indirect call argument value)
    stmt3: __gcov_indirect_call_callee = tmp1;
   */

  stmt1 = gimple_build_assign (ic_gcov_type_ptr_var, ref_ptr);
  tmp1 = make_temp_ssa_name (ptr_void, NULL, "PROF");
  stmt2 = gimple_build_assign (tmp1, unshare_expr (value->hvalue.value));
  stmt3 = gimple_build_assign (ic_void_ptr_var, gimple_assign_lhs (stmt2));

  gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT);
  gsi_insert_before (&gsi, stmt2, GSI_SAME_STMT);
  gsi_insert_before (&gsi, stmt3, GSI_SAME_STMT);
}
Example #2
0
static unsigned
determine_unroll_factor (struct loop *loop, struct mem_ref_group *refs,
                         unsigned ahead, unsigned ninsns,
                         struct tree_niter_desc *desc)
{
    unsigned upper_bound, size_factor, constraint_factor;
    unsigned factor, max_mod_constraint, ahead_factor;
    struct mem_ref_group *agp;
    struct mem_ref *ref;

    upper_bound = PARAM_VALUE (PARAM_MAX_UNROLL_TIMES);

    /* First check whether the loop is not too large to unroll.  */
    size_factor = PARAM_VALUE (PARAM_MAX_UNROLLED_INSNS) / ninsns;
    if (size_factor <= 1)
        return 1;

    if (size_factor < upper_bound)
        upper_bound = size_factor;

    max_mod_constraint = 1;
    for (agp = refs; agp; agp = agp->next)
        for (ref = agp->refs; ref; ref = ref->next)
            if (should_issue_prefetch_p (ref)
                    && ref->prefetch_mod > max_mod_constraint)
                max_mod_constraint = ref->prefetch_mod;

    /* Set constraint_factor as large as needed to be able to satisfy the
       largest modulo constraint.  */
    constraint_factor = max_mod_constraint;

    /* If ahead is too large in comparison with the number of available
       prefetches, unroll the loop as much as needed to be able to prefetch
       at least partially some of the references in the loop.  */
    ahead_factor = ((ahead + SIMULTANEOUS_PREFETCHES - 1)
                    / SIMULTANEOUS_PREFETCHES);

    /* Unroll as much as useful, but bound the code size growth.  */
    if (constraint_factor < ahead_factor)
        factor = ahead_factor;
    else
        factor = constraint_factor;
    if (factor > upper_bound)
        factor = upper_bound;

    if (!should_unroll_loop_p (loop, desc, factor))
        return 1;

    return factor;
}
Example #3
0
static bool
lst_do_strip_mine (lst_p lst, int stride)
{
  int i;
  lst_p l;
  bool res = false;
  int depth;

  if (!stride)
    stride = PARAM_VALUE (PARAM_LOOP_BLOCK_TILE_SIZE);

  if (!lst
      || !LST_LOOP_P (lst))
    return false;

  FOR_EACH_VEC_ELT (lst_p, LST_SEQ (lst), i, l)
    res |= lst_do_strip_mine (l, stride);

  depth = lst_depth (lst);
  if (depth >= 0
      && lst_strip_mine_profitable_p (lst, stride))
    {
      res |= lst_do_strip_mine_loop (lst, lst_depth (lst), stride);
      lst_add_loop_under_loop (lst);
    }

  return res;
}
Example #4
0
static bool
graphite_initialize (isl_ctx *ctx)
{
  if (number_of_loops (cfun) <= 1
      /* FIXME: This limit on the number of basic blocks of a function
	 should be removed when the SCOP detection is faster.  */
      || n_basic_blocks > PARAM_VALUE (PARAM_GRAPHITE_MAX_BBS_PER_FUNCTION))
    {
      if (dump_file && (dump_flags & TDF_DETAILS))
	print_global_statistics (dump_file);

      isl_ctx_free (ctx);
      return false;
    }

  scev_reset ();
  recompute_all_dominators ();
  initialize_original_copy_tables ();

  cloog_state = cloog_isl_state_malloc (ctx);

  if (dump_file && dump_flags)
    dump_function_to_file (current_function_decl, dump_file, dump_flags);

  return true;
}
Example #5
0
/* Add code:
   __thread gcov*	__gcov_indirect_call_counters; // pointer to actual counter
   __thread void*	__gcov_indirect_call_callee; // actual callee address
   __thread int __gcov_function_counter; // time profiler function counter
*/
static void
init_ic_make_global_vars (void)
{
  tree  gcov_type_ptr;

  ptr_void = build_pointer_type (void_type_node);

  ic_void_ptr_var
    = build_decl (UNKNOWN_LOCATION, VAR_DECL,
		  get_identifier (
			  (PARAM_VALUE (PARAM_INDIR_CALL_TOPN_PROFILE) ?
			   "__gcov_indirect_call_topn_callee" :
			   "__gcov_indirect_call_callee")),
		  ptr_void);
  TREE_PUBLIC (ic_void_ptr_var) = 1;
  DECL_EXTERNAL (ic_void_ptr_var) = 1;
  TREE_STATIC (ic_void_ptr_var) = 1;
  DECL_ARTIFICIAL (ic_void_ptr_var) = 1;
  DECL_INITIAL (ic_void_ptr_var) = NULL;
  if (targetm.have_tls)
    set_decl_tls_model (ic_void_ptr_var, decl_default_tls_model (ic_void_ptr_var));

  varpool_node::finalize_decl (ic_void_ptr_var);

  gcov_type_ptr = build_pointer_type (get_gcov_type ());

  ic_gcov_type_ptr_var
    = build_decl (UNKNOWN_LOCATION, VAR_DECL,
		  get_identifier (
			  (PARAM_VALUE (PARAM_INDIR_CALL_TOPN_PROFILE) ?
			   "__gcov_indirect_call_topn_counters" :
			   "__gcov_indirect_call_counters")),
		  gcov_type_ptr);
  TREE_PUBLIC (ic_gcov_type_ptr_var) = 1;
  DECL_EXTERNAL (ic_gcov_type_ptr_var) = 1;
  TREE_STATIC (ic_gcov_type_ptr_var) = 1;
  DECL_ARTIFICIAL (ic_gcov_type_ptr_var) = 1;
  DECL_INITIAL (ic_gcov_type_ptr_var) = NULL;
  if (targetm.have_tls)
    set_decl_tls_model (ic_gcov_type_ptr_var, decl_default_tls_model (ic_gcov_type_ptr_var));

  varpool_node::finalize_decl (ic_gcov_type_ptr_var);
}
Example #6
0
static bool
tail_duplicate (void)
{
  auto_vec<fibonacci_node<long, basic_block_def>*> blocks;
  blocks.safe_grow_cleared (last_basic_block_for_fn (cfun));

  basic_block *trace = XNEWVEC (basic_block, n_basic_blocks_for_fn (cfun));
  int *counts = XNEWVEC (int, last_basic_block_for_fn (cfun));
  int ninsns = 0, nduplicated = 0;
  gcov_type weighted_insns = 0, traced_insns = 0;
  fibonacci_heap<long, basic_block_def> heap (LONG_MIN);
  gcov_type cover_insns;
  int max_dup_insns;
  basic_block bb;
  bool changed = false;

  /* Create an oversized sbitmap to reduce the chance that we need to
     resize it.  */
  bb_seen = sbitmap_alloc (last_basic_block_for_fn (cfun) * 2);
  bitmap_clear (bb_seen);
  initialize_original_copy_tables ();

  if (profile_info && flag_branch_probabilities)
    probability_cutoff = PARAM_VALUE (TRACER_MIN_BRANCH_PROBABILITY_FEEDBACK);
  else
    probability_cutoff = PARAM_VALUE (TRACER_MIN_BRANCH_PROBABILITY);
  probability_cutoff = REG_BR_PROB_BASE / 100 * probability_cutoff;

  branch_ratio_cutoff =
    (REG_BR_PROB_BASE / 100 * PARAM_VALUE (TRACER_MIN_BRANCH_RATIO));

  FOR_EACH_BB_FN (bb, cfun)
    {
      int n = count_insns (bb);
      if (!ignore_bb_p (bb))
	blocks[bb->index] = heap.insert (-bb->frequency, bb);

      counts [bb->index] = n;
      ninsns += n;
      weighted_insns += n * bb->frequency;
    }
Example #7
0
	void testParseRFC2231()
	{
		// Extended parameter with charset specified in more than one
		// section (this is forbidden by RFC, but is should not fail)
		parameterizedHeaderField p1;
		p1.parse("X; param1*0*=charset1'language1'value1;\r\n"
			   "   param1*1*=charset2'language2'value2;");

		VASSERT_EQ("1.1", 1, p1.getParameterCount());
		VASSERT_EQ("1.2", "param1", PARAM_NAME(p1, 0));
		VASSERT_EQ("1.3", "charset1", PARAM_CHARSET(p1, 0));
		VASSERT_EQ("1.4", "value1charset2'language2'value2", PARAM_BUFFER(p1, 0));

		// Charset not specified in the first section (that is not encoded),
		// but specified in the second one (legal)
		parameterizedHeaderField p2;
		p2.parse("X; param1*0=value1;\r\n"
			   "   param1*1*=charset'language'value2;");

		VASSERT_EQ("2.1", 1, p2.getParameterCount());
		VASSERT_EQ("2.2", "param1", PARAM_NAME(p2, 0));
		VASSERT_EQ("2.3", "charset", PARAM_CHARSET(p2, 0));
		VASSERT_EQ("2.4", "value1value2", PARAM_BUFFER(p2, 0));

		// Characters prefixed with '%' in a simple (not extended) section
		// should not be decoded
		parameterizedHeaderField p3;
		p3.parse("X; param1=val%20ue1");

		VASSERT_EQ("3.1", 1, p3.getParameterCount());
		VASSERT_EQ("3.2", "param1", PARAM_NAME(p3, 0));
		VASSERT_EQ("3.3", "val%20ue1", PARAM_VALUE(p3, 0));

		// Multiple sections + charset specified and encoding
		parameterizedHeaderField p4;
		p4.parse("X; param1*0*=charset'language'value1a%20;"
			   "   param1*1*=value1b%20;"
			   "   param1*2=value1c");

		VASSERT_EQ("4.1", 1, p4.getParameterCount());
		VASSERT_EQ("4.2", "param1", PARAM_NAME(p4, 0));
		VASSERT_EQ("4.3", "charset", PARAM_CHARSET(p4, 0));
		VASSERT_EQ("4.4", "value1a value1b value1c", PARAM_BUFFER(p4, 0));

		// No charset specified: defaults to US-ASCII
		parameterizedHeaderField p5;
		p5.parse("X; param1*='language'value1");

		VASSERT_EQ("5.1", 1, p5.getParameterCount());
		VASSERT_EQ("5.2", "param1", PARAM_NAME(p5, 0));
		VASSERT_EQ("5.3", "us-ascii", PARAM_CHARSET(p5, 0));
		VASSERT_EQ("5.4", "value1", PARAM_BUFFER(p5, 0));
	}
Example #8
0
	void testNonStandardEncodedParam()
	{
		// This syntax is non-standard (expressly prohibited
		// by RFC-2047), but is used by Mozilla:
		//
    		// Content-Type: image/png;
		//    name="=?us-ascii?Q?Logo_VMime=2Epng?="

		parameterizedHeaderField p1;
		p1.parse("image/png; name=\"=?us-ascii?Q?Logo_VMime=2Epng?=\"");

		VASSERT_EQ("1.1", 1, p1.getParameterCount());
		VASSERT_EQ("1.2", "name", PARAM_NAME(p1, 0));
		VASSERT_EQ("1.3", "Logo VMime.png", PARAM_VALUE(p1, 0));

		parameterizedHeaderField p2;
		p2.parse("image/png; name=\"Logo =?us-ascii?Q?VMime=2Epng?=\"");

		VASSERT_EQ("2.1", 1, p2.getParameterCount());
		VASSERT_EQ("2.2", "name", PARAM_NAME(p2, 0));
		VASSERT_EQ("2.3", "Logo VMime.png", PARAM_VALUE(p2, 0));
	}
Example #9
0
	// Parse parameters with non-significant whitespaces
	void testParseNonSignificantWS()
	{
		parameterizedHeaderField p1;
		p1.parse(" \t X   \r\n");

		VASSERT_EQ("1.1", "X", FIELD_VALUE(p1));

		parameterizedHeaderField p2;
		p2.parse(" X  ; param1 =  value1 \r\n");

		VASSERT_EQ("2.1", 1, p2.getParameterCount());
		VASSERT_EQ("2.2", "X", FIELD_VALUE(p2));
		VASSERT_EQ("2.3", "param1", PARAM_NAME(p2, 0));
		VASSERT_EQ("2.4", "value1", PARAM_VALUE(p2, 0));
	}
Example #10
0
unsigned int
tree_ssa_unswitch_loops (void)
{
    loop_iterator li;
    struct loop *loop;
    bool changed = false;
    HOST_WIDE_INT iterations;

    /* Go through inner loops (only original ones).  */
    FOR_EACH_LOOP (li, loop, LI_ONLY_INNERMOST)
    {
        if (dump_file && (dump_flags & TDF_DETAILS))
            fprintf (dump_file, ";; Considering loop %d\n", loop->num);

        /* Do not unswitch in cold regions. */
        if (optimize_loop_for_size_p (loop))
        {
            if (dump_file && (dump_flags & TDF_DETAILS))
                fprintf (dump_file, ";; Not unswitching cold loops\n");
            continue;
        }

        /* The loop should not be too large, to limit code growth. */
        if (tree_num_loop_insns (loop, &eni_size_weights)
                > (unsigned) PARAM_VALUE (PARAM_MAX_UNSWITCH_INSNS))
        {
            if (dump_file && (dump_flags & TDF_DETAILS))
                fprintf (dump_file, ";; Not unswitching, loop too big\n");
            continue;
        }

        /* If the loop is not expected to iterate, there is no need
        for unswitching.  */
        iterations = estimated_loop_iterations_int (loop);
        if (iterations >= 0 && iterations <= 1)
        {
            if (dump_file && (dump_flags & TDF_DETAILS))
                fprintf (dump_file, ";; Not unswitching, loop is not expected to iterate\n");
            continue;
        }

        changed |= tree_unswitch_single_loop (loop, 0);
    }

    if (changed)
        return TODO_cleanup_cfg;
    return 0;
}
Example #11
0
static void *
vuse_eq (ao_ref *, tree vuse1, unsigned int cnt, void *data)
{
  tree vuse2 = (tree) data;
  if (vuse1 == vuse2)
    return data;

  /* This bounds the stmt walks we perform on reference lookups
     to O(1) instead of O(N) where N is the number of dominating
     stores leading to a candidate.  We re-use the SCCVN param
     for this as it is basically the same complexity.  */
  if (cnt > (unsigned) PARAM_VALUE (PARAM_SCCVN_MAX_ALIAS_QUERIES_PER_ACCESS))
    return (void *)-1;

  return NULL;
}
Example #12
0
static unsigned
determine_unroll_factor (struct loop *loop, struct mem_ref_group *refs,
			 unsigned ninsns, struct tree_niter_desc *desc,
			 HOST_WIDE_INT est_niter)
{
  unsigned upper_bound;
  unsigned nfactor, factor, mod_constraint;
  struct mem_ref_group *agp;
  struct mem_ref *ref;

  /* First check whether the loop is not too large to unroll.  We ignore
     PARAM_MAX_UNROLL_TIMES, because for small loops, it prevented us
     from unrolling them enough to make exactly one cache line covered by each
     iteration.  Also, the goal of PARAM_MAX_UNROLL_TIMES is to prevent
     us from unrolling the loops too many times in cases where we only expect
     gains from better scheduling and decreasing loop overhead, which is not
     the case here.  */
  upper_bound = PARAM_VALUE (PARAM_MAX_UNROLLED_INSNS) / ninsns;

  /* If we unrolled the loop more times than it iterates, the unrolled version
     of the loop would be never entered.  */
  if (est_niter >= 0 && est_niter < (HOST_WIDE_INT) upper_bound)
    upper_bound = est_niter;

  if (upper_bound <= 1)
    return 1;

  /* Choose the factor so that we may prefetch each cache just once,
     but bound the unrolling by UPPER_BOUND.  */
  factor = 1;
  for (agp = refs; agp; agp = agp->next)
    for (ref = agp->refs; ref; ref = ref->next)
      if (should_issue_prefetch_p (ref))
	{
	  mod_constraint = ref->prefetch_mod;
	  nfactor = least_common_multiple (mod_constraint, factor);
	  if (nfactor <= upper_bound)
	    factor = nfactor;
	}

  if (!should_unroll_loop_p (loop, desc, factor))
    return 1;

  return factor;
}
Example #13
0
static bool
ipcp_add_param_type (struct ipa_node_params *callee_info, int i, tree binfo)
{
  int j, count;

  if (ipa_param_cannot_devirtualize_p (callee_info, i))
    return false;

  if (callee_info->params[i].types)
    {
      count = VEC_length (tree, callee_info->params[i].types);
      for (j = 0; j < count; j++)
	if (VEC_index (tree, callee_info->params[i].types, j) == binfo)
	  return false;
    }

  if (VEC_length (tree, callee_info->params[i].types)
      == (unsigned) PARAM_VALUE (PARAM_DEVIRT_TYPE_LIST_SIZE))
    return !ipa_set_param_cannot_devirtualize (callee_info, i);

  VEC_safe_push (tree, heap, callee_info->params[i].types, binfo);
  return true;
}
	void testParse()
	{
		// Simple parameter
		parameterizedHeaderField p1;
		p1.parse("X; param1=value1;\r\n");

		VASSERT_EQ("1.1", 1, p1.getParameterCount());
		VASSERT_EQ("1.2", "param1", PARAM_NAME(p1, 0));
		VASSERT_EQ("1.3", "value1", PARAM_VALUE(p1, 0));

		// Multi-section parameters (1/2)
		parameterizedHeaderField p2a;
		p2a.parse("X; param1=value1;\r\n"
			  "  param2*0=\"val\";\r\n"
			  "  param2*1=\"ue2\";");

		VASSERT_EQ("2a.1", 2, p2a.getParameterCount());
		VASSERT_EQ("2a.2", "param1", PARAM_NAME(p2a, 0));
		VASSERT_EQ("2a.3", "value1", PARAM_VALUE(p2a, 0));
		VASSERT_EQ("2a.4", "param2", PARAM_NAME(p2a, 1));
		VASSERT_EQ("2a.5", "value2", PARAM_VALUE(p2a, 1));

		// Multi-section parameters (2/2)
		parameterizedHeaderField p2b;
		p2b.parse("X; param1=value1;\r\n"
			  "  param2=\"should be ignored\";\r\n"
			  "  param2*0=\"val\";\r\n"
			  "  param2*1=\"ue2\";");

		VASSERT_EQ("2b.1", 2, p2b.getParameterCount());
		VASSERT_EQ("2b.2", "param1", PARAM_NAME(p2b, 0));
		VASSERT_EQ("2b.3", "value1", PARAM_VALUE(p2b, 0));
		VASSERT_EQ("2b.4", "param2", PARAM_NAME(p2b, 1));
		VASSERT_EQ("2b.5", "value2", PARAM_VALUE(p2b, 1));

		// Extended parameter (charset and language information)
		parameterizedHeaderField p3;
		p3.parse("X; param1*=charset'language'value1;\r\n");

		VASSERT_EQ("3.1", 1, p3.getParameterCount());
		VASSERT_EQ("3.2", "param1", PARAM_NAME(p3, 0));
		VASSERT_EQ("3.3", "charset", PARAM_CHARSET(p3, 0));
		VASSERT_EQ("3.4", "value1", PARAM_BUFFER(p3, 0));

		// Encoded characters in extended parameter values
		parameterizedHeaderField p4;
		p4.parse("X; param1*=a%20value%20with%20multiple%20word%73");  // 0x73 = 's'

		VASSERT_EQ("4.1", 1, p4.getParameterCount());
		VASSERT_EQ("4.2", "param1", PARAM_NAME(p4, 0));
		VASSERT_EQ("4.3", "a value with multiple words", PARAM_VALUE(p4, 0));

		// Invalid encoded character
		parameterizedHeaderField p5;
		p5.parse("X; param1*=test%20value%");

		VASSERT_EQ("5.1", 1, p5.getParameterCount());
		VASSERT_EQ("5.2", "param1", PARAM_NAME(p5, 0));
		VASSERT_EQ("5.3", "test value%", PARAM_VALUE(p5, 0));

		// Spaces before and after '='
		parameterizedHeaderField p6;
		p6.parse("X; param1\t=  \"value1\"");

		VASSERT_EQ("6.1", 1, p6.getParameterCount());
		VASSERT_EQ("6.2", "param1", PARAM_NAME(p6, 0));
		VASSERT_EQ("6.3", "value1", PARAM_VALUE(p6, 0));

		// Quoted strings and escaped chars
		parameterizedHeaderField p7;
		p7.parse("X; param1=\"this is a slash: \\\"\\\\\\\"\"");  // \"\\\"

		VASSERT_EQ("7.1", 1, p7.getParameterCount());
		VASSERT_EQ("7.2", "param1", PARAM_NAME(p7, 0));
		VASSERT_EQ("7.3", "this is a slash: \"\\\"", PARAM_VALUE(p7, 0));

		// Extended parameter with charset specified in more than one
		// section (this is forbidden by RFC, but is should not fail)
		parameterizedHeaderField p8;
		p8.parse("X; param1*0*=charset1'language1'value1;\r\n"
			 "   param1*1*=charset2'language2'value2;");

		VASSERT_EQ("8.1", 1, p8.getParameterCount());
		VASSERT_EQ("8.2", "param1", PARAM_NAME(p8, 0));
		VASSERT_EQ("8.3", "charset1", PARAM_CHARSET(p8, 0));
		VASSERT_EQ("8.4", "value1charset2'language2'value2", PARAM_BUFFER(p8, 0));

		// Charset not specified in the first section (that is not encoded),
		// but specified in the second one (legal)
		parameterizedHeaderField p9;
		p9.parse("X; param1*0=value1;\r\n"
			 "   param1*1*=charset'language'value2;");

		VASSERT_EQ("9.1", 1, p9.getParameterCount());
		VASSERT_EQ("9.2", "param1", PARAM_NAME(p9, 0));
		VASSERT_EQ("9.3", "charset", PARAM_CHARSET(p9, 0));
		VASSERT_EQ("9.4", "value1value2", PARAM_BUFFER(p9, 0));

		// Characters prefixed with '%' in a simple (not extended) section
		// should not be decoded
		parameterizedHeaderField p10;
		p10.parse("X; param1=val%20ue1");

		VASSERT_EQ("10.1", 1, p10.getParameterCount());
		VASSERT_EQ("10.2", "param1", PARAM_NAME(p10, 0));
		VASSERT_EQ("10.3", "val%20ue1", PARAM_VALUE(p10, 0));

		// Multiple sections + charset specified and encoding
		parameterizedHeaderField p11;
		p11.parse("X; param1*0*=charset'language'value1a%20;"
			  "   param1*1*=value1b%20;"
			  "   param1*2=value1c");

		VASSERT_EQ("11.1", 1, p11.getParameterCount());
		VASSERT_EQ("11.2", "param1", PARAM_NAME(p11, 0));
		VASSERT_EQ("11.3", "charset", PARAM_CHARSET(p11, 0));
		VASSERT_EQ("11.4", "value1a value1b value1c", PARAM_BUFFER(p11, 0));

		// No charset specified: defaults to US-ASCII
		parameterizedHeaderField p12;
		p12.parse("X; param1*='language'value1");

		VASSERT_EQ("12.1", 1, p12.getParameterCount());
		VASSERT_EQ("12.2", "param1", PARAM_NAME(p12, 0));
		VASSERT_EQ("12.3", "us-ascii", PARAM_CHARSET(p12, 0));
		VASSERT_EQ("12.4", "value1", PARAM_BUFFER(p12, 0));
	}
Example #15
0
static tree
chrec_fold_plus_1 (enum tree_code code, 
		   tree type, 
		   tree op0,
		   tree op1)
{
  if (automatically_generated_chrec_p (op0)
      || automatically_generated_chrec_p (op1))
    return chrec_fold_automatically_generated_operands (op0, op1);
  
  switch (TREE_CODE (op0))
    {
    case POLYNOMIAL_CHREC:
      switch (TREE_CODE (op1))
	{
	case POLYNOMIAL_CHREC:
	  return chrec_fold_plus_poly_poly (code, type, op0, op1);

	default:
	  if (code == PLUS_EXPR)
	    return build_polynomial_chrec 
	      (CHREC_VARIABLE (op0), 
	       chrec_fold_plus (type, CHREC_LEFT (op0), op1),
	       CHREC_RIGHT (op0));
	  else
	    return build_polynomial_chrec 
	      (CHREC_VARIABLE (op0), 
	       chrec_fold_minus (type, CHREC_LEFT (op0), op1),
	       CHREC_RIGHT (op0));
	}

    default:
      switch (TREE_CODE (op1))
	{
	case POLYNOMIAL_CHREC:
	  if (code == PLUS_EXPR)
	    return build_polynomial_chrec 
	      (CHREC_VARIABLE (op1), 
	       chrec_fold_plus (type, op0, CHREC_LEFT (op1)),
	       CHREC_RIGHT (op1));
	  else
	    return build_polynomial_chrec 
	      (CHREC_VARIABLE (op1), 
	       chrec_fold_minus (type, op0, CHREC_LEFT (op1)),
	       chrec_fold_multiply (type, CHREC_RIGHT (op1),
				    build_int_cst_type (type, -1)));

	default:
	  {
	    int size = 0;
	    if ((tree_contains_chrecs (op0, &size)
		 || tree_contains_chrecs (op1, &size))
		&& size < PARAM_VALUE (PARAM_SCEV_MAX_EXPR_SIZE))
	      return build2 (code, type, op0, op1);
	    else if (size < PARAM_VALUE (PARAM_SCEV_MAX_EXPR_SIZE))
	      return fold (build2 (code, type, op0, op1));
	    else
	      return chrec_dont_know;
	  }
	}
    }
}
Example #16
0
void
gimple_init_edge_profiler (void)
{
  tree interval_profiler_fn_type;
  tree pow2_profiler_fn_type;
  tree one_value_profiler_fn_type;
  tree gcov_type_ptr;
  tree ic_profiler_fn_type;
  tree average_profiler_fn_type;
  tree time_profiler_fn_type;

  if (!gcov_type_node)
    {
      gcov_type_node = get_gcov_type ();
      gcov_type_ptr = build_pointer_type (gcov_type_node);

      /* void (*) (gcov_type *, gcov_type, int, unsigned)  */
      interval_profiler_fn_type
	      = build_function_type_list (void_type_node,
					  gcov_type_ptr, gcov_type_node,
					  integer_type_node,
					  unsigned_type_node, NULL_TREE);
      tree_interval_profiler_fn
	      = build_fn_decl ("__gcov_interval_profiler",
				     interval_profiler_fn_type);
      TREE_NOTHROW (tree_interval_profiler_fn) = 1;
      DECL_ATTRIBUTES (tree_interval_profiler_fn)
	= tree_cons (get_identifier ("leaf"), NULL,
		     DECL_ATTRIBUTES (tree_interval_profiler_fn));

      /* void (*) (gcov_type *, gcov_type)  */
      pow2_profiler_fn_type
	      = build_function_type_list (void_type_node,
					  gcov_type_ptr, gcov_type_node,
					  NULL_TREE);
      tree_pow2_profiler_fn = build_fn_decl ("__gcov_pow2_profiler",
						   pow2_profiler_fn_type);
      TREE_NOTHROW (tree_pow2_profiler_fn) = 1;
      DECL_ATTRIBUTES (tree_pow2_profiler_fn)
	= tree_cons (get_identifier ("leaf"), NULL,
		     DECL_ATTRIBUTES (tree_pow2_profiler_fn));

      /* void (*) (gcov_type *, gcov_type)  */
      one_value_profiler_fn_type
	      = build_function_type_list (void_type_node,
					  gcov_type_ptr, gcov_type_node,
					  NULL_TREE);
      tree_one_value_profiler_fn
	      = build_fn_decl ("__gcov_one_value_profiler",
				     one_value_profiler_fn_type);
      TREE_NOTHROW (tree_one_value_profiler_fn) = 1;
      DECL_ATTRIBUTES (tree_one_value_profiler_fn)
	= tree_cons (get_identifier ("leaf"), NULL,
		     DECL_ATTRIBUTES (tree_one_value_profiler_fn));

      init_ic_make_global_vars ();

      /* void (*) (gcov_type, void *)  */
      ic_profiler_fn_type
	       = build_function_type_list (void_type_node,
					  gcov_type_node,
					  ptr_void,
					  NULL_TREE);
      tree_indirect_call_profiler_fn
	      = build_fn_decl ( (PARAM_VALUE (PARAM_INDIR_CALL_TOPN_PROFILE) ?
				 "__gcov_indirect_call_topn_profiler":
				 "__gcov_indirect_call_profiler_v2"),
			       ic_profiler_fn_type);

      TREE_NOTHROW (tree_indirect_call_profiler_fn) = 1;
      DECL_ATTRIBUTES (tree_indirect_call_profiler_fn)
	= tree_cons (get_identifier ("leaf"), NULL,
		     DECL_ATTRIBUTES (tree_indirect_call_profiler_fn));

      /* void (*) (gcov_type *, gcov_type, void *)  */
      time_profiler_fn_type
	       = build_function_type_list (void_type_node,
					  gcov_type_ptr, NULL_TREE);
      tree_time_profiler_fn
	      = build_fn_decl ("__gcov_time_profiler",
				     time_profiler_fn_type);
      TREE_NOTHROW (tree_time_profiler_fn) = 1;
      DECL_ATTRIBUTES (tree_time_profiler_fn)
	= tree_cons (get_identifier ("leaf"), NULL,
		     DECL_ATTRIBUTES (tree_time_profiler_fn));

      /* void (*) (gcov_type *, gcov_type)  */
      average_profiler_fn_type
	      = build_function_type_list (void_type_node,
					  gcov_type_ptr, gcov_type_node, NULL_TREE);
      tree_average_profiler_fn
	      = build_fn_decl ("__gcov_average_profiler",
				     average_profiler_fn_type);
      TREE_NOTHROW (tree_average_profiler_fn) = 1;
      DECL_ATTRIBUTES (tree_average_profiler_fn)
	= tree_cons (get_identifier ("leaf"), NULL,
		     DECL_ATTRIBUTES (tree_average_profiler_fn));
      tree_ior_profiler_fn
	      = build_fn_decl ("__gcov_ior_profiler",
				     average_profiler_fn_type);
      TREE_NOTHROW (tree_ior_profiler_fn) = 1;
      DECL_ATTRIBUTES (tree_ior_profiler_fn)
	= tree_cons (get_identifier ("leaf"), NULL,
		     DECL_ATTRIBUTES (tree_ior_profiler_fn));

      /* LTO streamer needs assembler names.  Because we create these decls
         late, we need to initialize them by hand.  */
      DECL_ASSEMBLER_NAME (tree_interval_profiler_fn);
      DECL_ASSEMBLER_NAME (tree_pow2_profiler_fn);
      DECL_ASSEMBLER_NAME (tree_one_value_profiler_fn);
      DECL_ASSEMBLER_NAME (tree_indirect_call_profiler_fn);
      DECL_ASSEMBLER_NAME (tree_time_profiler_fn);
      DECL_ASSEMBLER_NAME (tree_average_profiler_fn);
      DECL_ASSEMBLER_NAME (tree_ior_profiler_fn);
    }
}
/* Unswitch single LOOP.  COND_CHECKED holds list of conditions we already
   unswitched on and are therefore known to be true in this LOOP.  NUM is
   number of unswitchings done; do not allow it to grow too much, it is too
   easy to create example on that the code would grow exponentially.
   Returns true LOOP was unswitched.  */
static bool 
unswitch_single_loop (struct loop *loop, rtx cond_checked, int num)
{
  basic_block *bbs;
  struct loop *nloop;
  unsigned i;
  rtx cond, rcond = NULL_RTX, conds, rconds, acond, cinsn;
  int repeat;
  edge e;
  HOST_WIDE_INT iterations;

  /* Do not unswitch too much.  */
  if (num > PARAM_VALUE (PARAM_MAX_UNSWITCH_LEVEL))
    {
      if (dump_file)
	fprintf (dump_file, ";; Not unswitching anymore, hit max level\n");
      return false;
    }

  /* Only unswitch innermost loops.  */
  if (loop->inner)
    {
      if (dump_file)
	fprintf (dump_file, ";; Not unswitching, not innermost loop\n");
      return false;
    }

  /* We must be able to duplicate loop body.  */
  if (!can_duplicate_loop_p (loop))
    {
      if (dump_file)
	fprintf (dump_file, ";; Not unswitching, can't duplicate loop\n");
      return false;
    }

  /* The loop should not be too large, to limit code growth.  */
  if (num_loop_insns (loop) > PARAM_VALUE (PARAM_MAX_UNSWITCH_INSNS))
    {
      if (dump_file)
	fprintf (dump_file, ";; Not unswitching, loop too big\n");
      return false;
    }

  /* Do not unswitch in cold areas.  */
  if (optimize_loop_for_size_p (loop))
    {
      if (dump_file)
	fprintf (dump_file, ";; Not unswitching, not hot area\n");
      return false;
    }

  /* Nor if the loop usually does not roll.  */
  iterations = estimated_loop_iterations_int (loop);
  if (iterations >= 0 && iterations <= 1)
    {
      if (dump_file)
	fprintf (dump_file, ";; Not unswitching, loop iterations < 1\n");
      return false;
    }

  do
    {
      repeat = 0;
      cinsn = NULL_RTX;

      /* Find a bb to unswitch on.  */
      bbs = get_loop_body (loop);
      iv_analysis_loop_init (loop);
      for (i = 0; i < loop->num_nodes; i++)
	if ((cond = may_unswitch_on (bbs[i], loop, &cinsn)))
	  break;

      if (i == loop->num_nodes)
	{
	  free (bbs);
	  return false;
	}

      if (cond != const0_rtx
	  && cond != const_true_rtx)
	{
	  rcond = reversed_condition (cond);
	  if (rcond)
	    rcond = canon_condition (rcond);

	  /* Check whether the result can be predicted.  */
	  for (acond = cond_checked; acond; acond = XEXP (acond, 1))
	    simplify_using_condition (XEXP (acond, 0), &cond, NULL);
	}

      if (cond == const_true_rtx)
	{
	  /* Remove false path.  */
	  e = FALLTHRU_EDGE (bbs[i]);
	  remove_path (e);
	  free (bbs);
	  repeat = 1;
	}
      else if (cond == const0_rtx)
	{
	  /* Remove true path.  */
	  e = BRANCH_EDGE (bbs[i]);
	  remove_path (e);
	  free (bbs);
	  repeat = 1;
	}
    } while (repeat);

  /* We found the condition we can unswitch on.  */
  conds = alloc_EXPR_LIST (0, cond, cond_checked);
  if (rcond)
    rconds = alloc_EXPR_LIST (0, rcond, cond_checked);
  else
    rconds = cond_checked;

  if (dump_file)
    fprintf (dump_file, ";; Unswitching loop\n");

  /* Unswitch the loop on this condition.  */
  nloop = unswitch_loop (loop, bbs[i], copy_rtx_if_shared (cond), cinsn);
  gcc_assert (nloop);

  /* Invoke itself on modified loops.  */
  unswitch_single_loop (nloop, rconds, num + 1);
  unswitch_single_loop (loop, conds, num + 1);

  free_EXPR_LIST_node (conds);
  if (rcond)
    free_EXPR_LIST_node (rconds);

  free (bbs);

  return true;
}
Example #18
0
static bool
tail_duplicate (void)
{
  fibnode_t *blocks = XCNEWVEC (fibnode_t, last_basic_block);
  basic_block *trace = XNEWVEC (basic_block, n_basic_blocks);
  int *counts = XNEWVEC (int, last_basic_block);
  int ninsns = 0, nduplicated = 0;
  gcov_type weighted_insns = 0, traced_insns = 0;
  fibheap_t heap = fibheap_new ();
  gcov_type cover_insns;
  int max_dup_insns;
  basic_block bb;
  bool changed = false;

  /* Create an oversized sbitmap to reduce the chance that we need to
     resize it.  */
  bb_seen = sbitmap_alloc (last_basic_block * 2);
  bitmap_clear (bb_seen);
  initialize_original_copy_tables ();

  if (profile_info && flag_branch_probabilities)
    probability_cutoff = PARAM_VALUE (TRACER_MIN_BRANCH_PROBABILITY_FEEDBACK);
  else
    probability_cutoff = PARAM_VALUE (TRACER_MIN_BRANCH_PROBABILITY);
  probability_cutoff = REG_BR_PROB_BASE / 100 * probability_cutoff;

  branch_ratio_cutoff =
    (REG_BR_PROB_BASE / 100 * PARAM_VALUE (TRACER_MIN_BRANCH_RATIO));

  FOR_EACH_BB (bb)
    {
      int n = count_insns (bb);
      if (!ignore_bb_p (bb))
	blocks[bb->index] = fibheap_insert (heap, -bb->frequency,
					    bb);

      counts [bb->index] = n;
      ninsns += n;
      weighted_insns += n * bb->frequency;
    }

  if (profile_info && flag_branch_probabilities)
    cover_insns = PARAM_VALUE (TRACER_DYNAMIC_COVERAGE_FEEDBACK);
  else
    cover_insns = PARAM_VALUE (TRACER_DYNAMIC_COVERAGE);
  cover_insns = (weighted_insns * cover_insns + 50) / 100;
  max_dup_insns = (ninsns * PARAM_VALUE (TRACER_MAX_CODE_GROWTH) + 50) / 100;

  while (traced_insns < cover_insns && nduplicated < max_dup_insns
         && !fibheap_empty (heap))
    {
      basic_block bb = (basic_block) fibheap_extract_min (heap);
      int n, pos;

      if (!bb)
	break;

      blocks[bb->index] = NULL;

      if (ignore_bb_p (bb))
	continue;
      gcc_assert (!bb_seen_p (bb));

      n = find_trace (bb, trace);

      bb = trace[0];
      traced_insns += bb->frequency * counts [bb->index];
      if (blocks[bb->index])
	{
	  fibheap_delete_node (heap, blocks[bb->index]);
	  blocks[bb->index] = NULL;
	}

      for (pos = 1; pos < n; pos++)
	{
	  basic_block bb2 = trace[pos];

	  if (blocks[bb2->index])
	    {
	      fibheap_delete_node (heap, blocks[bb2->index]);
	      blocks[bb2->index] = NULL;
	    }
	  traced_insns += bb2->frequency * counts [bb2->index];
	  if (EDGE_COUNT (bb2->preds) > 1
	      && can_duplicate_block_p (bb2)
	      /* We have the tendency to duplicate the loop header
	         of all do { } while loops.  Do not do that - it is
		 not profitable and it might create a loop with multiple
		 entries or at least rotate the loop.  */
	      && (!current_loops
		  || bb2->loop_father->header != bb2))
	    {
	      edge e;
	      basic_block copy;

	      nduplicated += counts [bb2->index];

	      e = find_edge (bb, bb2);

	      copy = duplicate_block (bb2, e, bb);
	      flush_pending_stmts (e);

	      add_phi_args_after_copy (&copy, 1, NULL);

	      /* Reconsider the original copy of block we've duplicated.
	         Removing the most common predecessor may make it to be
	         head.  */
	      blocks[bb2->index] =
		fibheap_insert (heap, -bb2->frequency, bb2);

	      if (dump_file)
		fprintf (dump_file, "Duplicated %i as %i [%i]\n",
			 bb2->index, copy->index, copy->frequency);

	      bb2 = copy;
	      changed = true;
	    }
	  mark_bb_seen (bb2);
	  bb = bb2;
	  /* In case the trace became infrequent, stop duplicating.  */
	  if (ignore_bb_p (bb))
	    break;
	}
      if (dump_file)
	fprintf (dump_file, " covered now %.1f\n\n",
		 traced_insns * 100.0 / weighted_insns);
    }
  if (dump_file)
    fprintf (dump_file, "Duplicated %i insns (%i%%)\n", nduplicated,
	     nduplicated * 100 / ninsns);

  free_original_copy_tables ();
  sbitmap_free (bb_seen);
  free (blocks);
  free (trace);
  free (counts);
  fibheap_delete (heap);

  return changed;
}
Example #19
0
static void
tail_duplicate (void)
{
  fibnode_t *blocks = XCNEWVEC (fibnode_t, last_basic_block);
  basic_block *trace = XNEWVEC (basic_block, n_basic_blocks);
  int *counts = XNEWVEC (int, last_basic_block);
  int ninsns = 0, nduplicated = 0;
  gcov_type weighted_insns = 0, traced_insns = 0;
  fibheap_t heap = fibheap_new ();
  gcov_type cover_insns;
  int max_dup_insns;
  basic_block bb;

  if (profile_info && flag_branch_probabilities)
    probability_cutoff = PARAM_VALUE (TRACER_MIN_BRANCH_PROBABILITY_FEEDBACK);
  else
    probability_cutoff = PARAM_VALUE (TRACER_MIN_BRANCH_PROBABILITY);
  probability_cutoff = REG_BR_PROB_BASE / 100 * probability_cutoff;

  branch_ratio_cutoff =
    (REG_BR_PROB_BASE / 100 * PARAM_VALUE (TRACER_MIN_BRANCH_RATIO));

  FOR_EACH_BB (bb)
    {
      int n = count_insns (bb);
      if (!ignore_bb_p (bb))
	blocks[bb->index] = fibheap_insert (heap, -bb->frequency,
					    bb);

      counts [bb->index] = n;
      ninsns += n;
      weighted_insns += n * bb->frequency;
    }

  if (profile_info && flag_branch_probabilities)
    cover_insns = PARAM_VALUE (TRACER_DYNAMIC_COVERAGE_FEEDBACK);
  else
    cover_insns = PARAM_VALUE (TRACER_DYNAMIC_COVERAGE);
  cover_insns = (weighted_insns * cover_insns + 50) / 100;
  max_dup_insns = (ninsns * PARAM_VALUE (TRACER_MAX_CODE_GROWTH) + 50) / 100;

  while (traced_insns < cover_insns && nduplicated < max_dup_insns
         && !fibheap_empty (heap))
    {
      basic_block bb = fibheap_extract_min (heap);
      int n, pos;

      if (!bb)
	break;

      blocks[bb->index] = NULL;

      if (ignore_bb_p (bb))
	continue;
      gcc_assert (!seen (bb));

      n = find_trace (bb, trace);

      bb = trace[0];
      traced_insns += bb->frequency * counts [bb->index];
      if (blocks[bb->index])
	{
	  fibheap_delete_node (heap, blocks[bb->index]);
	  blocks[bb->index] = NULL;
	}

      for (pos = 1; pos < n; pos++)
	{
	  basic_block bb2 = trace[pos];

	  if (blocks[bb2->index])
	    {
	      fibheap_delete_node (heap, blocks[bb2->index]);
	      blocks[bb2->index] = NULL;
	    }
	  traced_insns += bb2->frequency * counts [bb2->index];
	  if (EDGE_COUNT (bb2->preds) > 1
	      && can_duplicate_block_p (bb2))
	    {
	      edge e;
	      basic_block old = bb2;

	      e = find_edge (bb, bb2);

	      nduplicated += counts [bb2->index];
	      bb2 = duplicate_block (bb2, e, bb);

	      /* Reconsider the original copy of block we've duplicated.
	         Removing the most common predecessor may make it to be
	         head.  */
	      blocks[old->index] =
		fibheap_insert (heap, -old->frequency, old);

	      if (dump_file)
		fprintf (dump_file, "Duplicated %i as %i [%i]\n",
			 old->index, bb2->index, bb2->frequency);
	    }
	  bb->aux = bb2;
	  bb2->il.rtl->visited = 1;
	  bb = bb2;
	  /* In case the trace became infrequent, stop duplicating.  */
	  if (ignore_bb_p (bb))
	    break;
	}
      if (dump_file)
	fprintf (dump_file, " covered now %.1f\n\n",
		 traced_insns * 100.0 / weighted_insns);
    }
  if (dump_file)
    fprintf (dump_file, "Duplicated %i insns (%i%%)\n", nduplicated,
	     nduplicated * 100 / ninsns);

  free (blocks);
  free (trace);
  free (counts);
  fibheap_delete (heap);
}
Example #20
0
	void testParse()
	{
		// Simple parameter
		parameterizedHeaderField p1;
		p1.parse("X; param1=value1;\r\n");

		VASSERT_EQ("1.1", 1, p1.getParameterCount());
		VASSERT_EQ("1.2", "param1", PARAM_NAME(p1, 0));
		VASSERT_EQ("1.3", "value1", PARAM_VALUE(p1, 0));

		// Multi-section parameters (1/2)
		parameterizedHeaderField p2a;
		p2a.parse("X; param1=value1;\r\n"
			  "  param2*0=\"val\";\r\n"
			  "  param2*1=\"ue2\";");

		VASSERT_EQ("2a.1", 2, p2a.getParameterCount());
		VASSERT_EQ("2a.2", "param1", PARAM_NAME(p2a, 0));
		VASSERT_EQ("2a.3", "value1", PARAM_VALUE(p2a, 0));
		VASSERT_EQ("2a.4", "param2", PARAM_NAME(p2a, 1));
		VASSERT_EQ("2a.5", "value2", PARAM_VALUE(p2a, 1));

		// Multi-section parameters (2/2)
		parameterizedHeaderField p2b;
		p2b.parse("X; param1=value1;\r\n"
			  "  param2=\"should be ignored\";\r\n"
			  "  param2*0=\"val\";\r\n"
			  "  param2*1=\"ue2\";");

		VASSERT_EQ("2b.1", 2, p2b.getParameterCount());
		VASSERT_EQ("2b.2", "param1", PARAM_NAME(p2b, 0));
		VASSERT_EQ("2b.3", "value1", PARAM_VALUE(p2b, 0));
		VASSERT_EQ("2b.4", "param2", PARAM_NAME(p2b, 1));
		VASSERT_EQ("2b.5", "value2", PARAM_VALUE(p2b, 1));

		// Extended parameter (charset and language information)
		parameterizedHeaderField p3;
		p3.parse("X; param1*=charset'language'value1;\r\n");

		VASSERT_EQ("3.1", 1, p3.getParameterCount());
		VASSERT_EQ("3.2", "param1", PARAM_NAME(p3, 0));
		VASSERT_EQ("3.3", "charset", PARAM_CHARSET(p3, 0));
		VASSERT_EQ("3.4", "value1", PARAM_BUFFER(p3, 0));

		// Encoded characters in extended parameter values
		parameterizedHeaderField p4;
		p4.parse("X; param1*=a%20value%20with%20multiple%20word%73");  // 0x73 = 's'

		VASSERT_EQ("4.1", 1, p4.getParameterCount());
		VASSERT_EQ("4.2", "param1", PARAM_NAME(p4, 0));
		VASSERT_EQ("4.3", "a value with multiple words", PARAM_VALUE(p4, 0));

		// Invalid encoded character
		parameterizedHeaderField p5;
		p5.parse("X; param1*=test%20value%");

		VASSERT_EQ("5.1", 1, p5.getParameterCount());
		VASSERT_EQ("5.2", "param1", PARAM_NAME(p5, 0));
		VASSERT_EQ("5.3", "test value%", PARAM_VALUE(p5, 0));

		// Spaces before and after '='
		parameterizedHeaderField p6;
		p6.parse("X; param1\t=  \"value1\"");

		VASSERT_EQ("6.1", 1, p6.getParameterCount());
		VASSERT_EQ("6.2", "param1", PARAM_NAME(p6, 0));
		VASSERT_EQ("6.3", "value1", PARAM_VALUE(p6, 0));

		// Quoted strings and escaped chars
		parameterizedHeaderField p7;
		p7.parse("X; param1=\"this is a slash: \\\"\\\\\\\"\"");  // \"\\\"

		VASSERT_EQ("7.1", 1, p7.getParameterCount());
		VASSERT_EQ("7.2", "param1", PARAM_NAME(p7, 0));
		VASSERT_EQ("7.3", "this is a slash: \"\\\"", PARAM_VALUE(p7, 0));
	}
Example #21
0
static bool
doloop_optimize (struct loop *loop)
{
    enum machine_mode mode;
    rtx doloop_seq, doloop_pat, doloop_reg;
    rtx iterations, count;
    rtx iterations_max;
    rtx start_label;
    rtx condition;
    unsigned level, est_niter;
    struct niter_desc *desc;
    unsigned word_mode_size;
    unsigned HOST_WIDE_INT word_mode_max;

    if (dump_file)
        fprintf (dump_file, "Doloop: Processing loop %d.\n", loop->num);

    /* APPLE LOCAL begin lno */
    /* Ignore large loops.  */
    if (loop->ninsns > (unsigned) PARAM_VALUE (PARAM_MAX_DOLOOP_INSNS))
    {
        if (dump_file)
            fprintf (dump_file,
                     "Doloop: The loop is too large.\n");
        return false;
    }
    /* APPLE LOCAL end lno */

    iv_analysis_loop_init (loop);

    /* Find the simple exit of a LOOP.  */
    desc = get_simple_loop_desc (loop);

    /* Check that loop is a candidate for a low-overhead looping insn.  */
    if (!doloop_valid_p (loop, desc))
    {
        if (dump_file)
            fprintf (dump_file,
                     "Doloop: The loop is not suitable.\n");
        return false;
    }
    mode = desc->mode;

    est_niter = 3;
    if (desc->const_iter)
        est_niter = desc->niter;
    /* If the estimate on number of iterations is reliable (comes from profile
       feedback), use it.  Do not use it normally, since the expected number
       of iterations of an unrolled loop is 2.  */
    if (loop->header->count)
        est_niter = expected_loop_iterations (loop);

    if (est_niter < 3)
    {
        if (dump_file)
            fprintf (dump_file,
                     "Doloop: Too few iterations (%u) to be profitable.\n",
                     est_niter);
        return false;
    }

    count = copy_rtx (desc->niter_expr);
    iterations = desc->const_iter ? desc->niter_expr : const0_rtx;
    iterations_max = GEN_INT (desc->niter_max);
    level = get_loop_level (loop) + 1;

    /* Generate looping insn.  If the pattern FAILs then give up trying
       to modify the loop since there is some aspect the back-end does
       not like.  */
    start_label = block_label (desc->in_edge->dest);
    doloop_reg = gen_reg_rtx (mode);
    doloop_seq = gen_doloop_end (doloop_reg, iterations, iterations_max,
                                 GEN_INT (level), start_label);

    word_mode_size = GET_MODE_BITSIZE (word_mode);
    word_mode_max
        = ((unsigned HOST_WIDE_INT) 1 << (word_mode_size - 1) << 1) - 1;
    if (! doloop_seq
            && mode != word_mode
            /* Before trying mode different from the one in that # of iterations is
            computed, we must be sure that the number of iterations fits into
             the new mode.  */
            && (word_mode_size >= GET_MODE_BITSIZE (mode)
                || desc->niter_max <= word_mode_max))
    {
        if (word_mode_size > GET_MODE_BITSIZE (mode))
        {
            count = simplify_gen_unary (ZERO_EXTEND, word_mode,
                                        count, mode);
            iterations = simplify_gen_unary (ZERO_EXTEND, word_mode,
                                             iterations, mode);
            iterations_max = simplify_gen_unary (ZERO_EXTEND, word_mode,
                                                 iterations_max, mode);
        }
        else
        {
            count = lowpart_subreg (word_mode, count, mode);
            iterations = lowpart_subreg (word_mode, iterations, mode);
            iterations_max = lowpart_subreg (word_mode, iterations_max, mode);
        }
        PUT_MODE (doloop_reg, word_mode);
        doloop_seq = gen_doloop_end (doloop_reg, iterations, iterations_max,
                                     GEN_INT (level), start_label);
    }
    if (! doloop_seq)
    {
        if (dump_file)
            fprintf (dump_file,
                     "Doloop: Target unwilling to use doloop pattern!\n");
        return false;
    }

    /* If multiple instructions were created, the last must be the
       jump instruction.  Also, a raw define_insn may yield a plain
       pattern.  */
    doloop_pat = doloop_seq;
    if (INSN_P (doloop_pat))
    {
        while (NEXT_INSN (doloop_pat) != NULL_RTX)
            doloop_pat = NEXT_INSN (doloop_pat);
        if (JUMP_P (doloop_pat))
            doloop_pat = PATTERN (doloop_pat);
        else
            doloop_pat = NULL_RTX;
    }

    if (! doloop_pat
            || ! (condition = doloop_condition_get (doloop_pat)))
    {
        if (dump_file)
            fprintf (dump_file, "Doloop: Unrecognizable doloop pattern!\n");
        return false;
    }

    doloop_modify (loop, desc, doloop_seq, condition, count);
    return true;
}
Example #22
0
static bool
is_feasible_trace (basic_block bb)
{
    basic_block pred1 = EDGE_PRED (bb, 0)->src;
    basic_block pred2 = EDGE_PRED (bb, 1)->src;
    int num_stmts_in_join = count_stmts_in_block (bb);
    int num_stmts_in_pred1 = count_stmts_in_block (pred1);
    int num_stmts_in_pred2 = count_stmts_in_block (pred2);

    /* This is meant to catch cases that are likely opportunities for
       if-conversion.  Essentially we look for the case where
       BB's predecessors are both single statement blocks where
       the output of that statement feed the same PHI in BB.  */
    if (num_stmts_in_pred1 == 1 && num_stmts_in_pred2 == 1)
    {
        gimple *stmt1 = last_and_only_stmt (pred1);
        gimple *stmt2 = last_and_only_stmt (pred2);

        if (stmt1 && stmt2
                && gimple_code (stmt1) == GIMPLE_ASSIGN
                && gimple_code (stmt2) == GIMPLE_ASSIGN)
        {
            enum tree_code code1 = gimple_assign_rhs_code (stmt1);
            enum tree_code code2 = gimple_assign_rhs_code (stmt2);

            if (!poor_ifcvt_candidate_code (code1)
                    && !poor_ifcvt_candidate_code (code2))
            {
                tree lhs1 = gimple_assign_lhs (stmt1);
                tree lhs2 = gimple_assign_lhs (stmt2);
                gimple_stmt_iterator gsi;
                for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
                {
                    gimple *phi = gsi_stmt (gsi);
                    if ((gimple_phi_arg_def (phi, 0) == lhs1
                            && gimple_phi_arg_def (phi, 1) == lhs2)
                            || (gimple_phi_arg_def (phi, 1) == lhs1
                                && gimple_phi_arg_def (phi, 0) == lhs2))
                    {
                        if (dump_file && (dump_flags & TDF_DETAILS))
                            fprintf (dump_file,
                                     "Block %d appears to be a join point for "
                                     "if-convertable diamond.\n",
                                     bb->index);
                        return false;
                    }
                }
            }
        }
    }

    /* We may want something here which looks at dataflow and tries
       to guess if duplication of BB is likely to result in simplification
       of instructions in BB in either the original or the duplicate.  */

    /* Upper Hard limit on the number statements to copy.  */
    if (num_stmts_in_join
            >= PARAM_VALUE (PARAM_MAX_JUMP_THREAD_DUPLICATION_STMTS))
        return false;

    return true;
}
Example #23
0
static tree
chrec_fold_plus_1 (enum tree_code code, tree type,
		   tree op0, tree op1)
{
  if (automatically_generated_chrec_p (op0)
      || automatically_generated_chrec_p (op1))
    return chrec_fold_automatically_generated_operands (op0, op1);

  switch (TREE_CODE (op0))
    {
    case POLYNOMIAL_CHREC:
      gcc_checking_assert
	(!chrec_contains_symbols_defined_in_loop (op0, CHREC_VARIABLE (op0)));
      switch (TREE_CODE (op1))
	{
	case POLYNOMIAL_CHREC:
	  gcc_checking_assert
	    (!chrec_contains_symbols_defined_in_loop (op1,
						      CHREC_VARIABLE (op1)));
	  return chrec_fold_plus_poly_poly (code, type, op0, op1);

	CASE_CONVERT:
	  if (tree_contains_chrecs (op1, NULL))
	    return chrec_dont_know;

	default:
	  if (code == PLUS_EXPR || code == POINTER_PLUS_EXPR)
	    return build_polynomial_chrec
	      (CHREC_VARIABLE (op0),
	       chrec_fold_plus (type, CHREC_LEFT (op0), op1),
	       CHREC_RIGHT (op0));
	  else
	    return build_polynomial_chrec
	      (CHREC_VARIABLE (op0),
	       chrec_fold_minus (type, CHREC_LEFT (op0), op1),
	       CHREC_RIGHT (op0));
	}

    CASE_CONVERT:
      if (tree_contains_chrecs (op0, NULL))
	return chrec_dont_know;

    default:
      switch (TREE_CODE (op1))
	{
	case POLYNOMIAL_CHREC:
	  gcc_checking_assert
	    (!chrec_contains_symbols_defined_in_loop (op1,
						      CHREC_VARIABLE (op1)));
	  if (code == PLUS_EXPR || code == POINTER_PLUS_EXPR)
	    return build_polynomial_chrec
	      (CHREC_VARIABLE (op1),
	       chrec_fold_plus (type, op0, CHREC_LEFT (op1)),
	       CHREC_RIGHT (op1));
	  else
	    return build_polynomial_chrec
	      (CHREC_VARIABLE (op1),
	       chrec_fold_minus (type, op0, CHREC_LEFT (op1)),
	       chrec_fold_multiply (type, CHREC_RIGHT (op1),
				    SCALAR_FLOAT_TYPE_P (type)
				    ? build_real (type, dconstm1)
				    : build_int_cst_type (type, -1)));

	CASE_CONVERT:
	  if (tree_contains_chrecs (op1, NULL))
	    return chrec_dont_know;

	default:
	  {
	    int size = 0;
	    if ((tree_contains_chrecs (op0, &size)
		 || tree_contains_chrecs (op1, &size))
		&& size < PARAM_VALUE (PARAM_SCEV_MAX_EXPR_SIZE))
	      return build2 (code, type, op0, op1);
	    else if (size < PARAM_VALUE (PARAM_SCEV_MAX_EXPR_SIZE))
	      {
		if (code == POINTER_PLUS_EXPR)
		  return fold_build_pointer_plus (fold_convert (type, op0),
						  op1);
		else
		  return fold_build2 (code, type,
				      fold_convert (type, op0),
				      fold_convert (type, op1));
	      }
	    else
	      return chrec_dont_know;
	  }
	}
    }
}
Example #24
0
/* Propagate the constant parameters found by ipcp_iterate_stage()
   to the function's code.  */
static void
ipcp_insert_stage (void)
{
  struct cgraph_node *node, *node1 = NULL;
  int i;
  VEC (cgraph_edge_p, heap) * redirect_callers;
  VEC (ipa_replace_map_p,gc)* replace_trees;
  int node_callers, count;
  tree parm_tree;
  struct ipa_replace_map *replace_param;
  fibheap_t heap;
  long overall_size = 0, new_size = 0;
  long max_new_size;

  ipa_check_create_node_params ();
  ipa_check_create_edge_args ();
  if (dump_file)
    fprintf (dump_file, "\nIPA insert stage:\n\n");

  dead_nodes = BITMAP_ALLOC (NULL);

  for (node = cgraph_nodes; node; node = node->next)
    if (node->analyzed)
      {
	if (node->count > max_count)
	  max_count = node->count;
	overall_size += node->local.inline_summary.self_size;
      }

  max_new_size = overall_size;
  if (max_new_size < PARAM_VALUE (PARAM_LARGE_UNIT_INSNS))
    max_new_size = PARAM_VALUE (PARAM_LARGE_UNIT_INSNS);
  max_new_size = max_new_size * PARAM_VALUE (PARAM_IPCP_UNIT_GROWTH) / 100 + 1;

  /* First collect all functions we proved to have constant arguments to
     heap.  */
  heap = fibheap_new ();
  for (node = cgraph_nodes; node; node = node->next)
    {
      struct ipa_node_params *info;
      /* Propagation of the constant is forbidden in certain conditions.  */
      if (!node->analyzed || !ipcp_node_modifiable_p (node))
	  continue;
      info = IPA_NODE_REF (node);
      if (ipa_is_called_with_var_arguments (info))
	continue;
      if (ipcp_const_param_count (node))
	node->aux = fibheap_insert (heap, ipcp_estimate_cloning_cost (node),
				    node);
     }

  /* Now clone in priority order until code size growth limits are met or
     heap is emptied.  */
  while (!fibheap_empty (heap))
    {
      struct ipa_node_params *info;
      int growth = 0;
      bitmap args_to_skip;
      struct cgraph_edge *cs;

      node = (struct cgraph_node *)fibheap_extract_min (heap);
      node->aux = NULL;
      if (dump_file)
	fprintf (dump_file, "considering function %s\n",
		 cgraph_node_name (node));

      growth = ipcp_estimate_growth (node);

      if (new_size + growth > max_new_size)
	break;
      if (growth
	  && optimize_function_for_size_p (DECL_STRUCT_FUNCTION (node->decl)))
	{
	  if (dump_file)
	    fprintf (dump_file, "Not versioning, cold code would grow");
	  continue;
	}

      info = IPA_NODE_REF (node);
      count = ipa_get_param_count (info);

      replace_trees = VEC_alloc (ipa_replace_map_p, gc, 1);

      if (node->local.can_change_signature)
	args_to_skip = BITMAP_GGC_ALLOC ();
      else
	args_to_skip = NULL;
      for (i = 0; i < count; i++)
	{
	  struct ipcp_lattice *lat = ipcp_get_lattice (info, i);
	  parm_tree = ipa_get_param (info, i);

	  /* We can proactively remove obviously unused arguments.  */
	  if (!ipa_is_param_used (info, i))
	    {
	      if (args_to_skip)
	        bitmap_set_bit (args_to_skip, i);
	      continue;
	    }

	  if (lat->type == IPA_CONST_VALUE)
	    {
	      replace_param =
		ipcp_create_replace_map (parm_tree, lat);
	      if (replace_param == NULL)
		break;
	      VEC_safe_push (ipa_replace_map_p, gc, replace_trees, replace_param);
	      if (args_to_skip)
	        bitmap_set_bit (args_to_skip, i);
	    }
	}
      if (i < count)
	{
	  if (dump_file)
	    fprintf (dump_file, "Not versioning, some parameters couldn't be replaced");
	  continue;
	}

      new_size += growth;

      /* Look if original function becomes dead after cloning.  */
      for (cs = node->callers; cs != NULL; cs = cs->next_caller)
	if (cs->caller == node || ipcp_need_redirect_p (cs))
	  break;
      if (!cs && cgraph_will_be_removed_from_program_if_no_direct_calls (node))
	bitmap_set_bit (dead_nodes, node->uid);

      /* Compute how many callers node has.  */
      node_callers = 0;
      for (cs = node->callers; cs != NULL; cs = cs->next_caller)
	node_callers++;
      redirect_callers = VEC_alloc (cgraph_edge_p, heap, node_callers);
      for (cs = node->callers; cs != NULL; cs = cs->next_caller)
	if (!cs->indirect_inlining_edge)
	  VEC_quick_push (cgraph_edge_p, redirect_callers, cs);

      /* Redirecting all the callers of the node to the
         new versioned node.  */
      node1 =
	cgraph_create_virtual_clone (node, redirect_callers, replace_trees,
				     args_to_skip, "constprop");
      args_to_skip = NULL;
      VEC_free (cgraph_edge_p, heap, redirect_callers);
      replace_trees = NULL;

      if (node1 == NULL)
	continue;
      ipcp_process_devirtualization_opportunities (node1);

      if (dump_file)
	fprintf (dump_file, "versioned function %s with growth %i, overall %i\n",
		 cgraph_node_name (node), (int)growth, (int)new_size);
      ipcp_init_cloned_node (node, node1);

      info = IPA_NODE_REF (node);
      for (i = 0; i < count; i++)
	{
	  struct ipcp_lattice *lat = ipcp_get_lattice (info, i);
	  if (lat->type == IPA_CONST_VALUE)
	    ipcp_discover_new_direct_edges (node1, i, lat->constant);
        }

      if (dump_file)
	dump_function_to_file (node1->decl, dump_file, dump_flags);

      for (cs = node->callees; cs; cs = cs->next_callee)
        if (cs->callee->aux)
	  {
	    fibheap_delete_node (heap, (fibnode_t) cs->callee->aux);
	    cs->callee->aux = fibheap_insert (heap,
	    				      ipcp_estimate_cloning_cost (cs->callee),
					      cs->callee);
	  }
    }

  while (!fibheap_empty (heap))
    {
      if (dump_file)
	fprintf (dump_file, "skipping function %s\n",
		 cgraph_node_name (node));
      node = (struct cgraph_node *) fibheap_extract_min (heap);
      node->aux = NULL;
    }
  fibheap_delete (heap);
  BITMAP_FREE (dead_nodes);
  ipcp_update_callgraph ();
  ipcp_update_profiling ();
}
Example #25
0
static bool
try_unroll_loop_completely (struct loop *loop,
			    edge exit, tree niter,
			    enum unroll_level ul,
			    HOST_WIDE_INT maxiter,
			    location_t locus)
{
  unsigned HOST_WIDE_INT n_unroll = 0, ninsns, unr_insns;
  struct loop_size size;
  bool n_unroll_found = false;
  edge edge_to_cancel = NULL;
  int report_flags = MSG_OPTIMIZED_LOCATIONS | TDF_RTL | TDF_DETAILS;

  /* See if we proved number of iterations to be low constant.

     EXIT is an edge that will be removed in all but last iteration of 
     the loop.

     EDGE_TO_CACNEL is an edge that will be removed from the last iteration
     of the unrolled sequence and is expected to make the final loop not
     rolling. 

     If the number of execution of loop is determined by standard induction
     variable test, then EXIT and EDGE_TO_CANCEL are the two edges leaving
     from the iv test.  */
  if (tree_fits_uhwi_p (niter))
    {
      n_unroll = tree_to_uhwi (niter);
      n_unroll_found = true;
      edge_to_cancel = EDGE_SUCC (exit->src, 0);
      if (edge_to_cancel == exit)
	edge_to_cancel = EDGE_SUCC (exit->src, 1);
    }
  /* We do not know the number of iterations and thus we can not eliminate
     the EXIT edge.  */
  else
    exit = NULL;

  /* See if we can improve our estimate by using recorded loop bounds.  */
  if (maxiter >= 0
      && (!n_unroll_found || (unsigned HOST_WIDE_INT)maxiter < n_unroll))
    {
      n_unroll = maxiter;
      n_unroll_found = true;
      /* Loop terminates before the IV variable test, so we can not
	 remove it in the last iteration.  */
      edge_to_cancel = NULL;
    }

  if (!n_unroll_found)
    return false;

  if (n_unroll > (unsigned) PARAM_VALUE (PARAM_MAX_COMPLETELY_PEEL_TIMES))
    {
      if (dump_file && (dump_flags & TDF_DETAILS))
	fprintf (dump_file, "Not unrolling loop %d "
		 "(--param max-completely-peeled-times limit reached).\n",
		 loop->num);
      return false;
    }

  if (!edge_to_cancel)
    edge_to_cancel = loop_edge_to_cancel (loop);

  if (n_unroll)
    {
      sbitmap wont_exit;
      edge e;
      unsigned i;
      bool large;
      vec<edge> to_remove = vNULL;
      if (ul == UL_SINGLE_ITER)
	return false;

      large = tree_estimate_loop_size
		 (loop, exit, edge_to_cancel, &size,
		  PARAM_VALUE (PARAM_MAX_COMPLETELY_PEELED_INSNS));
      ninsns = size.overall;
      if (large)
	{
	  if (dump_file && (dump_flags & TDF_DETAILS))
	    fprintf (dump_file, "Not unrolling loop %d: it is too large.\n",
		     loop->num);
	  return false;
	}

      unr_insns = estimated_unrolled_size (&size, n_unroll);
      if (dump_file && (dump_flags & TDF_DETAILS))
	{
	  fprintf (dump_file, "  Loop size: %d\n", (int) ninsns);
	  fprintf (dump_file, "  Estimated size after unrolling: %d\n",
		   (int) unr_insns);
	}

      /* If the code is going to shrink, we don't need to be extra cautious
	 on guessing if the unrolling is going to be profitable.  */
      if (unr_insns
	  /* If there is IV variable that will become constant, we save
	     one instruction in the loop prologue we do not account
	     otherwise.  */
	  <= ninsns + (size.constant_iv != false))
	;
      /* We unroll only inner loops, because we do not consider it profitable
	 otheriwse.  We still can cancel loopback edge of not rolling loop;
	 this is always a good idea.  */
      else if (ul == UL_NO_GROWTH)
	{
	  if (dump_file && (dump_flags & TDF_DETAILS))
	    fprintf (dump_file, "Not unrolling loop %d: size would grow.\n",
		     loop->num);
	  return false;
	}
      /* Outer loops tend to be less interesting candidates for complete
	 unrolling unless we can do a lot of propagation into the inner loop
	 body.  For now we disable outer loop unrolling when the code would
	 grow.  */
      else if (loop->inner)
	{
	  if (dump_file && (dump_flags & TDF_DETAILS))
	    fprintf (dump_file, "Not unrolling loop %d: "
		     "it is not innermost and code would grow.\n",
		     loop->num);
	  return false;
	}
      /* If there is call on a hot path through the loop, then
	 there is most probably not much to optimize.  */
      else if (size.num_non_pure_calls_on_hot_path)
	{
	  if (dump_file && (dump_flags & TDF_DETAILS))
	    fprintf (dump_file, "Not unrolling loop %d: "
		     "contains call and code would grow.\n",
		     loop->num);
	  return false;
	}
      /* If there is pure/const call in the function, then we
	 can still optimize the unrolled loop body if it contains
	 some other interesting code than the calls and code
	 storing or cumulating the return value.  */
      else if (size.num_pure_calls_on_hot_path
	       /* One IV increment, one test, one ivtmp store
		  and one useful stmt.  That is about minimal loop
		  doing pure call.  */
	       && (size.non_call_stmts_on_hot_path
		   <= 3 + size.num_pure_calls_on_hot_path))
	{
	  if (dump_file && (dump_flags & TDF_DETAILS))
	    fprintf (dump_file, "Not unrolling loop %d: "
		     "contains just pure calls and code would grow.\n",
		     loop->num);
	  return false;
	}
      /* Complette unrolling is major win when control flow is removed and
	 one big basic block is created.  If the loop contains control flow
	 the optimization may still be a win because of eliminating the loop
	 overhead but it also may blow the branch predictor tables.
	 Limit number of branches on the hot path through the peeled
	 sequence.  */
      else if (size.num_branches_on_hot_path * (int)n_unroll
	       > PARAM_VALUE (PARAM_MAX_PEEL_BRANCHES))
	{
	  if (dump_file && (dump_flags & TDF_DETAILS))
	    fprintf (dump_file, "Not unrolling loop %d: "
		     " number of branches on hot path in the unrolled sequence"
		     " reach --param max-peel-branches limit.\n",
		     loop->num);
	  return false;
	}
      else if (unr_insns
	       > (unsigned) PARAM_VALUE (PARAM_MAX_COMPLETELY_PEELED_INSNS))
	{
	  if (dump_file && (dump_flags & TDF_DETAILS))
	    fprintf (dump_file, "Not unrolling loop %d: "
		     "(--param max-completely-peeled-insns limit reached).\n",
		     loop->num);
	  return false;
	}
      dump_printf_loc (report_flags, locus,
                       "loop turned into non-loop; it never loops.\n");

      initialize_original_copy_tables ();
      wont_exit = sbitmap_alloc (n_unroll + 1);
      bitmap_ones (wont_exit);
      bitmap_clear_bit (wont_exit, 0);

      if (!gimple_duplicate_loop_to_header_edge (loop, loop_preheader_edge (loop),
						 n_unroll, wont_exit,
						 exit, &to_remove,
						 DLTHE_FLAG_UPDATE_FREQ
						 | DLTHE_FLAG_COMPLETTE_PEEL))
	{
          free_original_copy_tables ();
	  free (wont_exit);
	  if (dump_file && (dump_flags & TDF_DETAILS))
	    fprintf (dump_file, "Failed to duplicate the loop\n");
	  return false;
	}

      FOR_EACH_VEC_ELT (to_remove, i, e)
	{
	  bool ok = remove_path (e);
	  gcc_assert (ok);
	}

      to_remove.release ();
      free (wont_exit);
      free_original_copy_tables ();
    }
Example #26
0
/* Add code:
   __thread gcov*	__gcov_indirect_call_counters; // pointer to actual counter
   __thread void*	__gcov_indirect_call_callee; // actual callee address
   __thread int __gcov_function_counter; // time profiler function counter
*/
static void
init_ic_make_global_vars (void)
{
  tree  gcov_type_ptr;

  ptr_void = build_pointer_type (void_type_node);

  /* Workaround for binutils bug 14342.  Once it is fixed, remove lto path.  */
  if (flag_lto)
    {
      ic_void_ptr_var
	= build_decl (UNKNOWN_LOCATION, VAR_DECL,
		      get_identifier ("__gcov_indirect_call_callee_ltopriv"),
		      ptr_void);
      TREE_PUBLIC (ic_void_ptr_var) = 1;
      DECL_COMMON (ic_void_ptr_var) = 1;
      DECL_VISIBILITY (ic_void_ptr_var) = VISIBILITY_HIDDEN;
      DECL_VISIBILITY_SPECIFIED (ic_void_ptr_var) = true;
    }
  else
    {
      ic_void_ptr_var
	= build_decl (UNKNOWN_LOCATION, VAR_DECL,
		      get_identifier (
			      (PARAM_VALUE (PARAM_INDIR_CALL_TOPN_PROFILE) ?
			       "__gcov_indirect_call_topn_callee" :
			       "__gcov_indirect_call_callee")),
		      ptr_void);
      TREE_PUBLIC (ic_void_ptr_var) = 1;
      DECL_EXTERNAL (ic_void_ptr_var) = 1;
    }
  TREE_STATIC (ic_void_ptr_var) = 1;
  DECL_ARTIFICIAL (ic_void_ptr_var) = 1;
  DECL_INITIAL (ic_void_ptr_var) = NULL;
  if (targetm.have_tls)
    set_decl_tls_model (ic_void_ptr_var, decl_default_tls_model (ic_void_ptr_var));

  varpool_node::finalize_decl (ic_void_ptr_var);

  gcov_type_ptr = build_pointer_type (get_gcov_type ());
  /* Workaround for binutils bug 14342.  Once it is fixed, remove lto path.  */
  if (flag_lto)
    {
      ic_gcov_type_ptr_var
	= build_decl (UNKNOWN_LOCATION, VAR_DECL,
		      get_identifier ("__gcov_indirect_call_counters_ltopriv"),
		      gcov_type_ptr);
      TREE_PUBLIC (ic_gcov_type_ptr_var) = 1;
      DECL_COMMON (ic_gcov_type_ptr_var) = 1;
      DECL_VISIBILITY (ic_gcov_type_ptr_var) = VISIBILITY_HIDDEN;
      DECL_VISIBILITY_SPECIFIED (ic_gcov_type_ptr_var) = true;
    }
  else
    {
      ic_gcov_type_ptr_var
	= build_decl (UNKNOWN_LOCATION, VAR_DECL,
		      get_identifier (
			      (PARAM_VALUE (PARAM_INDIR_CALL_TOPN_PROFILE) ?
			       "__gcov_indirect_call_topn_counters" :
		               "__gcov_indirect_call_counters")),
		      gcov_type_ptr);
      TREE_PUBLIC (ic_gcov_type_ptr_var) = 1;
      DECL_EXTERNAL (ic_gcov_type_ptr_var) = 1;
    }
  TREE_STATIC (ic_gcov_type_ptr_var) = 1;
  DECL_ARTIFICIAL (ic_gcov_type_ptr_var) = 1;
  DECL_INITIAL (ic_gcov_type_ptr_var) = NULL;
  if (targetm.have_tls)
    set_decl_tls_model (ic_gcov_type_ptr_var, decl_default_tls_model (ic_gcov_type_ptr_var));

  varpool_node::finalize_decl (ic_gcov_type_ptr_var);
}