This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] rtlopt branch merge part 10 -- profiler sections


Hello,

there are two additional profiled quantities on rtlopt-branch (histograms of
loop iterations and of values of variables); the counters for these profiles
are kept in own sections of .da files. This patch creates infrastructure for
easy addition of new sections.

Zdenek

   * gcov-dump.c (print_prefix): Fix signedness warning.
	* gcov-io.h (struct counter_section, struct counter_section_data): New.
	(struct function_info): n_arc_counts field removed, n_counter_sections,
	counter_sections fields added.
	(struct gcov_info): arc_counts, n_arc_counts fields removed,
	n_counter_sections, counter_sections fields added.
	* libgcov.c (gcov_exit, __gcov_flush): Add support for multiple
	profile sections.
	* profile.h (MAX_COUNTER_SECTIONS): New.
	(struct section_info): New.
	(struct profile_info): count_instrumented_edges,
	count_edges_instrumented_now fields removed, n_sections, section_info
	fields added.
	(find_counters_section): Declare.
	* profile.c (struct function_list): count_edges field removed,
	n_counter_sections, counter_sections fields added.
	(set_purpose, label_for_tag, build_counter_section_fields,
	build_counter_section_value, build_counter_section_data_fields,
	build_counter_section_data_value, build_function_info_fields,
	build_function_info_value, build_gcov_info_fields,
	build_gcov_info_value): New static functions.
	(find_counters_section): New function.
	(instrument_edges, get_exec_counts, compute_branch_probabilities,
	branch_prob, create_profiler): Modified to support multiple profile
	sections.

Index: gcov-dump.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/gcov-dump.c,v
retrieving revision 1.3
diff -c -3 -p -r1.3 gcov-dump.c
*** gcov-dump.c	5 Jan 2003 04:37:08 -0000	1.3
--- gcov-dump.c	9 Feb 2003 19:57:45 -0000
*************** print_prefix (filename, depth)
*** 131,137 ****
  {
    static const char prefix[] = "    ";
    
!   printf ("%s:%.*s", filename, depth, prefix);
  }
  
  static void
--- 131,137 ----
  {
    static const char prefix[] = "    ";
    
!   printf ("%s:%.*s", filename, (int) depth, prefix);
  }
  
  static void
Index: gcov-io.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/gcov-io.h,v
retrieving revision 1.19
diff -c -3 -p -r1.19 gcov-io.h
*** gcov-io.h	24 Jan 2003 01:46:50 -0000	1.19
--- gcov-io.h	9 Feb 2003 19:57:46 -0000
*************** struct gcov_summary
*** 216,231 ****
    gcov_type arc_sum_max;  /* sum of max_one */
  };
  
- #if IN_LIBGCC2
  /* Structures embedded in coveraged program.  The structures generated
     by write_profile must match these.  */
  
  /* Information about a single function.  */
  struct function_info
  {
    const char *name;	        /* (mangled) name of function */
    unsigned checksum;		/* function checksum */
!   unsigned n_arc_counts;	/* number of instrumented arcs */
  };
  
  /* Information about a single object file.  */
--- 216,248 ----
    gcov_type arc_sum_max;  /* sum of max_one */
  };
  
  /* Structures embedded in coveraged program.  The structures generated
     by write_profile must match these.  */
  
+ /* Information about section of counters for a function.  */
+ struct counter_section
+ {
+   unsigned tag;		/* Tag of the section.  */
+   unsigned n_counters;	/* Number of counters in the section.  */
+ };
+ 
+ #if IN_LIBGCC2
+ /* Information about section of counters for an object file.  */
+ struct counter_section_data
+ {
+   unsigned tag;		/* Tag of the section.  */
+   unsigned n_counters;	/* Number of counters in the section.  */
+   gcov_type *counters;	/* The data.  */
+ };
+ 
  /* Information about a single function.  */
  struct function_info
  {
    const char *name;	        /* (mangled) name of function */
    unsigned checksum;		/* function checksum */
!   unsigned n_counter_sections;	/* Number of types of counters */
!   const struct counter_section *counter_sections;
!   				/* The section descriptions */
  };
  
  /* Information about a single object file.  */
*************** struct gcov_info
*** 237,247 ****
    const char *filename;		/* output file name */
    long wkspc;	  	        /* libgcc workspace */
  
-   const struct function_info *functions; /* table of functions */
    unsigned n_functions;             /* number of functions */
  
!   gcov_type *arc_counts;	/* table of arc counts */
!   unsigned n_arc_counts;	/* number of arc counts */
  };
  
  /* Register a new object file module.  */
--- 254,265 ----
    const char *filename;		/* output file name */
    long wkspc;	  	        /* libgcc workspace */
  
    unsigned n_functions;             /* number of functions */
+   const struct function_info *functions; /* table of functions */
  
!   unsigned n_counter_sections;	/* Number of types of counters */
!   const struct counter_section_data *counter_sections;
!   				/* The data to be put into the sections.  */
  };
  
  /* Register a new object file module.  */
Index: libgcov.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/libgcov.c,v
retrieving revision 1.1
diff -c -3 -p -r1.1 libgcov.c
*** libgcov.c	27 Jan 2003 23:22:15 -0000	1.1
--- libgcov.c	9 Feb 2003 19:57:46 -0000
*************** gcov_exit (void)
*** 112,125 ****
        int merging = 0;
        long base;
        const struct function_info *fn_info;
        gcov_type *count_ptr;
        gcov_type object_max_one = 0;
  
        ptr->wkspc = 0;
        if (!ptr->filename)
  	continue;
  
!       for (ix = ptr->n_arc_counts, count_ptr = ptr->arc_counts; ix--;)
  	{
  	  gcov_type count = *count_ptr++;
  
--- 112,146 ----
        int merging = 0;
        long base;
        const struct function_info *fn_info;
+       gcov_type **counters;
        gcov_type *count_ptr;
        gcov_type object_max_one = 0;
+       gcov_type count;
+       unsigned tag, length, flength, checksum;
+       unsigned arc_data_index, f_sect_index, sect_index;
  
        ptr->wkspc = 0;
        if (!ptr->filename)
  	continue;
  
!       counters = malloc (sizeof (gcov_type *) * ptr->n_counter_sections);
!       for (ix = 0; ix < ptr->n_counter_sections; ix++)
! 	counters[ix] = ptr->counter_sections[ix].counters;
! 
!       for (arc_data_index = 0;
! 	   arc_data_index < ptr->n_counter_sections
! 	   && ptr->counter_sections[arc_data_index].tag != GCOV_TAG_ARC_COUNTS;
! 	   arc_data_index++)
! 	continue;
! 
!       if (arc_data_index == ptr->n_counter_sections)
! 	{
! 	  /* For now; later we may want to just measure other profiles,
! 	     but now I am lazy to check for all consequences.  */
! 	  abort ();
! 	}
!       for (ix = ptr->counter_sections[arc_data_index].n_counters,
! 	   count_ptr = ptr->counter_sections[arc_data_index].counters; ix--;)
  	{
  	  gcov_type count = *count_ptr++;
  
*************** gcov_exit (void)
*** 155,161 ****
        if (merging)
  	{
  	  /* Merge data from file.  */
- 	  unsigned tag, length;
  	      
  	  if (gcov_read_unsigned (da_file, &tag) || tag != GCOV_DATA_MAGIC)
  	    {
--- 176,181 ----
*************** gcov_exit (void)
*** 173,179 ****
  	    }
  	  
  	  /* Merge execution counts for each function.  */
- 	  count_ptr = ptr->arc_counts;
  	  for (ix = ptr->n_functions, fn_info = ptr->functions;
  	       ix--; fn_info++)
  	    {
--- 193,198 ----
*************** gcov_exit (void)
*** 194,226 ****
  			   ptr->filename, fn_info->name);
  		  goto read_fatal;
  		}
! 	      {
! 		unsigned flength, checksum;
! 		
! 		if (gcov_read_unsigned (da_file, &flength)
! 		    || gcov_skip_string (da_file, flength)
! 		    || gcov_read_unsigned (da_file, &checksum))
! 		  goto read_error;
! 		if (flength != strlen (fn_info->name)
! 		    || checksum != fn_info->checksum)
! 		  goto read_mismatch;
! 	      }
! 	      /* Check arc counts */
! 	      if (gcov_read_unsigned (da_file, &tag)
! 		  || gcov_read_unsigned (da_file, &length))
  		goto read_error;
! 	      if (tag != GCOV_TAG_ARC_COUNTS
! 		  || length / 8 != fn_info->n_arc_counts)
  		goto read_mismatch;
! 	      {
! 		gcov_type count;
! 		
! 		for (jx = fn_info->n_arc_counts; jx--; count_ptr++)
! 		  if (gcov_read_counter (da_file, &count))
  		    goto read_error;
! 		  else
! 		    *count_ptr += count;
! 	      }
  	    }
  
  	  /* Check object summary */
--- 213,252 ----
  			   ptr->filename, fn_info->name);
  		  goto read_fatal;
  		}
! 
! 	      if (gcov_read_unsigned (da_file, &flength)
! 		  || gcov_skip_string (da_file, flength)
! 		  || gcov_read_unsigned (da_file, &checksum))
  		goto read_error;
! 	      if (flength != strlen (fn_info->name)
! 		  || checksum != fn_info->checksum)
  		goto read_mismatch;
! 
! 	      /* Counters.  */
! 	      for (f_sect_index = 0;
! 		   f_sect_index < fn_info->n_counter_sections;
! 		   f_sect_index++)
! 		{
! 		  if (gcov_read_unsigned (da_file, &tag)
! 		      || gcov_read_unsigned (da_file, &length))
  		    goto read_error;
! 		  for (sect_index = 0;
! 		       sect_index < ptr->n_counter_sections;
! 		       sect_index++)
! 		    if (ptr->counter_sections[sect_index].tag == tag)
! 		      break;
! 		  if (fn_info->counter_sections[f_sect_index].tag != tag
! 		      || sect_index == ptr->n_counter_sections
! 		      || length / 8 != fn_info->counter_sections[f_sect_index].n_counters)
! 		    goto read_mismatch;
! 		  
! 		  for (jx = fn_info->counter_sections[f_sect_index].n_counters;
! 		       jx--; counters[sect_index]++)
! 		    if (gcov_read_counter (da_file, &count))
! 		      goto read_error;
! 		    else
! 		      *counters[sect_index] += count;
! 		}
  	    }
  
  	  /* Check object summary */
*************** gcov_exit (void)
*** 279,285 ****
  	}
  
        object.runs++;
!       object.arcs = ptr->n_arc_counts;
        object.arc_sum = 0;
        if (object.arc_max_one < object_max_one)
  	object.arc_max_one = object_max_one;
--- 305,311 ----
  	}
  
        object.runs++;
!       object.arcs = ptr->counter_sections[arc_data_index].n_counters;
        object.arc_sum = 0;
        if (object.arc_max_one < object_max_one)
  	object.arc_max_one = object_max_one;
*************** gcov_exit (void)
*** 299,305 ****
  	}
        
        /* Write execution counts for each function.  */
!       count_ptr = ptr->arc_counts;
        for (ix = ptr->n_functions, fn_info = ptr->functions; ix--; fn_info++)
  	{
  	  /* Announce function.  */
--- 325,332 ----
  	}
        
        /* Write execution counts for each function.  */
!       for (ix = 0; ix < ptr->n_counter_sections; ix++)
! 	counters[ix] = ptr->counter_sections[ix].counters;
        for (ix = ptr->n_functions, fn_info = ptr->functions; ix--; fn_info++)
  	{
  	  /* Announce function.  */
*************** gcov_exit (void)
*** 312,335 ****
  	      || gcov_write_unsigned (da_file, fn_info->checksum)
  	      || gcov_write_length (da_file, base))
  	    goto write_error;
! 	  
! 	  /* arc counts.  */
! 	  if (gcov_write_unsigned (da_file, GCOV_TAG_ARC_COUNTS)
! 	      || !(base = gcov_reserve_length (da_file)))
! 	    goto write_error;
! 	  
! 	  for (jx = fn_info->n_arc_counts; jx--;)
  	    {
! 	      gcov_type count = *count_ptr++;
  	      
! 	      object.arc_sum += count;
! 	      if (object.arc_max_sum < count)
! 		object.arc_max_sum = count;
! 	      if (gcov_write_counter (da_file, count))
! 		goto write_error; /* RIP Edsger Dijkstra */
  	    }
- 	  if (gcov_write_length (da_file, base))
- 	    goto write_error;
  	}
  
        /* Object file summary.  */
--- 339,379 ----
  	      || gcov_write_unsigned (da_file, fn_info->checksum)
  	      || gcov_write_length (da_file, base))
  	    goto write_error;
! 
! 	  /* counters.  */
! 	  for (f_sect_index = 0;
! 	       f_sect_index < fn_info->n_counter_sections;
! 	       f_sect_index++)
  	    {
! 	      tag = fn_info->counter_sections[f_sect_index].tag;
! 	      for (sect_index = 0;
!     		   sect_index < ptr->n_counter_sections;
! 		   sect_index++)
! 		if (ptr->counter_sections[sect_index].tag == tag)
! 		  break;
! 	      if (sect_index == ptr->n_counter_sections)
! 		abort ();
! 
! 	      if (gcov_write_unsigned (da_file, tag)
! 		  || !(base = gcov_reserve_length (da_file)))
! 		goto write_error;
! 	  
!     	      for (jx = fn_info->counter_sections[f_sect_index].n_counters; jx--;)
! 		{
! 		  gcov_type count = *counters[sect_index]++;
  	      
! 		  if (tag == GCOV_TAG_ARC_COUNTS)
! 		    {
! 		      object.arc_sum += count;
! 		      if (object.arc_max_sum < count)
! 			object.arc_max_sum = count;
! 		    }
! 		  if (gcov_write_counter (da_file, count))
! 		    goto write_error; /* RIP Edsger Dijkstra */
! 		}
! 	      if (gcov_write_length (da_file, base))
! 		goto write_error;
  	    }
  	}
  
        /* Object file summary.  */
*************** gcov_exit (void)
*** 367,377 ****
  	}
        else
  	{
! 	  program_arcs += ptr->n_arc_counts;
  	  program_sum += object.arc_sum;
  	  if (program_max_sum < object.arc_max_sum)
  	    program_max_sum = object.arc_max_sum;
  	}
      }
  
    /* Generate whole program statistics.  */
--- 411,422 ----
  	}
        else
  	{
! 	  program_arcs += ptr->counter_sections[arc_data_index].n_counters;
  	  program_sum += object.arc_sum;
  	  if (program_max_sum < object.arc_max_sum)
  	    program_max_sum = object.arc_max_sum;
  	}
+       free(counters);
      }
  
    /* Generate whole program statistics.  */
*************** __gcov_flush (void)
*** 465,473 ****
    gcov_exit ();
    for (ptr = gcov_list; ptr; ptr = ptr->next)
      {
!       unsigned i;
        
!       for (i = ptr->n_arc_counts; i--;)
! 	ptr->arc_counts[i] = 0;
      }
  }
--- 510,519 ----
    gcov_exit ();
    for (ptr = gcov_list; ptr; ptr = ptr->next)
      {
!       unsigned i, j;
        
!       for (j = 0; j < ptr->n_counter_sections; j++)
! 	for (i = ptr->counter_sections[j].n_counters; i--;)
! 	  ptr->counter_sections[j].counters[i] = 0;
      }
  }
Index: profile.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/profile.c,v
retrieving revision 1.107
diff -c -3 -p -r1.107 profile.c
*** profile.c	27 Jan 2003 23:22:15 -0000	1.107
--- profile.c	9 Feb 2003 19:58:01 -0000
*************** struct function_list
*** 96,102 ****
    struct function_list *next; 	/* next function */
    const char *name; 		/* function name */
    unsigned cfg_checksum;	/* function checksum */
!   unsigned count_edges;	        /* number of intrumented edges  */
  };
  
  static struct function_list *functions_head = 0;
--- 96,104 ----
    struct function_list *next; 	/* next function */
    const char *name; 		/* function name */
    unsigned cfg_checksum;	/* function checksum */
!   unsigned n_counter_sections;	/* number of counter sections */
!   struct counter_section counter_sections[MAX_COUNTER_SECTIONS];
!   				/* the sections */
  };
  
  static struct function_list *functions_head = 0;
*************** static gcov_type * get_exec_counts PARAM
*** 156,161 ****
--- 158,173 ----
  static unsigned compute_checksum PARAMS ((void));
  static basic_block find_group PARAMS ((basic_block));
  static void union_groups PARAMS ((basic_block, basic_block));
+ static void set_purpose PARAMS ((tree, tree));
+ static rtx label_for_tag PARAMS ((unsigned));
+ static tree build_counter_section_fields PARAMS ((void));
+ static tree build_counter_section_value PARAMS ((unsigned, unsigned));
+ static tree build_counter_section_data_fields PARAMS ((void));
+ static tree build_counter_section_data_value PARAMS ((unsigned, unsigned));
+ static tree build_function_info_fields PARAMS ((void));
+ static tree build_function_info_value PARAMS ((struct function_list *));
+ static tree build_gcov_info_fields PARAMS ((tree));
+ static tree build_gcov_info_value PARAMS ((void));
  
  
  /* Add edge instrumentation code to the entire insn chain.
*************** instrument_edges (el)
*** 170,175 ****
--- 182,188 ----
    int num_instr_edges = 0;
    int num_edges = NUM_EDGES (el);
    basic_block bb;
+   struct section_info *section_info;
    remove_fake_edges ();
  
    FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
*************** instrument_edges (el)
*** 194,208 ****
  	}
      }
  
!   profile_info.count_edges_instrumented_now = num_instr_edges;
    total_num_edges_instrumented += num_instr_edges;
!   profile_info.count_instrumented_edges = total_num_edges_instrumented;
  
    total_num_blocks_created += num_edges;
    if (rtl_dump_file)
      fprintf (rtl_dump_file, "%d edges instrumented\n", num_instr_edges);
- 
-   commit_edge_insertions_watch_calls ();
  }
  
  struct section_reference
--- 207,220 ----
  	}
      }
  
!   section_info = find_counters_section (GCOV_TAG_ARC_COUNTS);
!   section_info->n_counters_now = num_instr_edges;
    total_num_edges_instrumented += num_instr_edges;
!   section_info->n_counters = total_num_edges_instrumented;
  
    total_num_blocks_created += num_edges;
    if (rtl_dump_file)
      fprintf (rtl_dump_file, "%d edges instrumented\n", num_instr_edges);
  }
  
  struct section_reference
*************** compute_branch_probabilities ()
*** 847,852 ****
--- 858,864 ----
    free_aux_for_blocks ();
    if (exec_counts)
      free (exec_counts);
+   find_counters_section (GCOV_TAG_ARC_COUNTS)->present = 1;
  }
  
  /* Compute checksum for the current function.  We generate a CRC32.  */
*************** void
*** 908,920 ****
  branch_prob ()
  {
    basic_block bb;
!   int i;
!   int num_edges, ignored_edges;
    struct edge_list *el;
    const char *name = IDENTIFIER_POINTER
  		      (DECL_ASSEMBLER_NAME (current_function_decl));
  
    profile_info.current_function_cfg_checksum = compute_checksum ();
  
    if (rtl_dump_file)
      fprintf (rtl_dump_file, "CFG checksum is %u\n",
--- 920,937 ----
  branch_prob ()
  {
    basic_block bb;
!   unsigned i;
!   unsigned num_edges, ignored_edges;
    struct edge_list *el;
    const char *name = IDENTIFIER_POINTER
  		      (DECL_ASSEMBLER_NAME (current_function_decl));
  
    profile_info.current_function_cfg_checksum = compute_checksum ();
+   for (i = 0; i < profile_info.n_sections; i++)
+     {
+       profile_info.section_info[i].n_counters_now = 0;
+       profile_info.section_info[i].present = 0;
+     }
  
    if (rtl_dump_file)
      fprintf (rtl_dump_file, "CFG checksum is %u\n",
*************** branch_prob ()
*** 1082,1088 ****
        if (gcov_write_unsigned (bbg_file, GCOV_TAG_BLOCKS)
  	  || !(offset = gcov_reserve_length (bbg_file)))
  	goto bbg_error;
!       for (i = 0; i != n_basic_blocks + 2; i++)
  	if (gcov_write_unsigned (bbg_file, 0))
  	  goto bbg_error;
        if (gcov_write_length (bbg_file, offset))
--- 1099,1105 ----
        if (gcov_write_unsigned (bbg_file, GCOV_TAG_BLOCKS)
  	  || !(offset = gcov_reserve_length (bbg_file)))
  	goto bbg_error;
!       for (i = 0; i != (unsigned) (n_basic_blocks + 2); i++)
  	if (gcov_write_unsigned (bbg_file, 0))
  	  goto bbg_error;
        if (gcov_write_length (bbg_file, offset))
*************** branch_prob ()
*** 1118,1123 ****
--- 1135,1141 ----
  		    goto bbg_error;
  	        }
  	    }
+ 
  	  if (gcov_write_length (bbg_file, offset))
  	    goto bbg_error;
  	}
*************** branch_prob ()
*** 1184,1189 ****
--- 1202,1208 ----
  		  }
  		insn = NEXT_INSN (insn);
  	      }
+ 
  	    if (offset)
  	      {
  		if (gcov_write_unsigned (bbg_file, 0)
*************** branch_prob ()
*** 1210,1215 ****
--- 1229,1237 ----
        struct function_list *item;
        
        instrument_edges (el);
+ 
+       /* Commit changes done by instrumentation.  */
+       commit_edge_insertions_watch_calls ();
        allocate_reg_info (max_reg_num (), FALSE, FALSE);
  
        /* ??? Probably should re-use the existing struct function.  */
*************** branch_prob ()
*** 1221,1237 ****
        item->next = 0;
        item->name = xstrdup (name);
        item->cfg_checksum = profile_info.current_function_cfg_checksum;
!       item->count_edges = profile_info.count_edges_instrumented_now;
      }
  
    remove_fake_edges ();
    /* Re-merge split basic blocks and the mess introduced by
       insert_insn_on_edge.  */
    cleanup_cfg (profile_arc_flag ? CLEANUP_EXPENSIVE : 0);
    if (rtl_dump_file)
      dump_flow_info (rtl_dump_file);
  
-   free_aux_for_edges ();
    free_edge_list (el);
  }
  
--- 1243,1268 ----
        item->next = 0;
        item->name = xstrdup (name);
        item->cfg_checksum = profile_info.current_function_cfg_checksum;
!       item->n_counter_sections = 0;
!       for (i = 0; i < profile_info.n_sections; i++)
! 	if (profile_info.section_info[i].n_counters_now)
! 	  {
! 	    item->counter_sections[item->n_counter_sections].tag = 
! 		    profile_info.section_info[i].tag;
! 	    item->counter_sections[item->n_counter_sections].n_counters =
! 		    profile_info.section_info[i].n_counters_now;
! 	    item->n_counter_sections++;
! 	  }
      }
  
    remove_fake_edges ();
+   free_aux_for_edges ();
    /* Re-merge split basic blocks and the mess introduced by
       insert_insn_on_edge.  */
    cleanup_cfg (profile_arc_flag ? CLEANUP_EXPENSIVE : 0);
    if (rtl_dump_file)
      dump_flow_info (rtl_dump_file);
  
    free_edge_list (el);
  }
  
*************** end_branch_prob ()
*** 1477,1674 ****
      }
  }
  
! /* Write out the structure which libgcc uses to locate all the arc
!    counters.  The structures used here must match those defined in
!    gcov-io.h.  Write out the constructor to call __gcov_init.  */
  
! void
! create_profiler ()
  {
!   tree fields, field, value = NULL_TREE;
!   tree ginfo_type;
!   tree string_type;
!   tree gcov_type, gcov_ptr_type;
!   char name[20];
!   char *ctor_name;
!   tree structure, ctor;
!   rtx structure_address;
!   int save_flag_inline_functions = flag_inline_functions;
  
!   if (!profile_info.count_instrumented_edges)
!     return;
    
!   string_type = build_pointer_type
!     (build_qualified_type (char_type_node,  TYPE_QUAL_CONST));
    gcov_type = make_signed_type (GCOV_TYPE_SIZE);
    gcov_ptr_type
      = build_pointer_type (build_qualified_type
  			  (gcov_type, TYPE_QUAL_CONST));
    
!   ginfo_type = (*lang_hooks.types.make_type) (RECORD_TYPE);
!   
  
    /* Version ident */
    fields = build_decl (FIELD_DECL, NULL_TREE, long_unsigned_type_node);
!   value = tree_cons (fields, convert (long_unsigned_type_node, build_int_2
! 				      (GCOV_VERSION, 0)), value);
!       
!   /* NULL */
!   field = build_decl (FIELD_DECL, NULL_TREE, build_pointer_type
! 		      (build_qualified_type
! 		       (ginfo_type, TYPE_QUAL_CONST)));
    TREE_CHAIN (field) = fields;
    fields = field;
-   value = tree_cons (fields, null_pointer_node, value);
    
    /* Filename */
!   {
!     tree filename_string;
!     char *filename;
!     int filename_len;
!     
!     filename = getpwd ();
!     filename = (filename && da_file_name[0] != '/'
! 		? concat (filename, "/", da_file_name, NULL)
! 		: da_file_name);
!     filename_len = strlen (filename);
!     filename_string = build_string (filename_len + 1, filename);
!     if (filename != da_file_name)
!       free (filename);
!     TREE_TYPE (filename_string) = build_array_type
!       (char_type_node, build_index_type
!        (build_int_2 (filename_len, 0)));
!     
!     field = build_decl (FIELD_DECL, NULL_TREE, string_type);
!     TREE_CHAIN (field) = fields;
!     fields = field;
!     value = tree_cons (fields, build1 (ADDR_EXPR, string_type,
! 				       filename_string), value);
!   }
    
    /* Workspace */
    field = build_decl (FIELD_DECL, NULL_TREE, long_integer_type_node);
    TREE_CHAIN (field) = fields;
    fields = field;
!   value = tree_cons (fields,
! 		     convert (long_integer_type_node, integer_zero_node),
! 		     value);
        
    /* function_info table */
!   {
!     struct function_list *item;
!     int num_nodes = 0;
!     tree array_value = NULL_TREE;
!     tree finfo_type, finfo_ptr_type;
!     tree name, checksum, arcs;
!     
!     finfo_type = (*lang_hooks.types.make_type) (RECORD_TYPE);
!     name = build_decl (FIELD_DECL, NULL_TREE, string_type);
!     checksum = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
!     TREE_CHAIN (checksum) = name;
!     arcs = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
!     TREE_CHAIN (arcs) = checksum;
!     finish_builtin_struct (finfo_type, "__function_info",
! 			   arcs, NULL_TREE);
!     finfo_ptr_type = build_pointer_type
!       (build_qualified_type (finfo_type, TYPE_QUAL_CONST));
      
!     for (item = functions_head; item != 0; item = item->next, num_nodes++)
!       {
! 	size_t name_len = strlen (item->name);
! 	tree finfo_value = NULL_TREE;
! 	tree fname = build_string (name_len + 1, item->name);
! 	
! 	TREE_TYPE (fname) = build_array_type
! 	  (char_type_node, build_index_type (build_int_2 (name_len, 0)));
! 	finfo_value = tree_cons (name, build1
! 				 (ADDR_EXPR, string_type,
! 				  fname), finfo_value);
! 	finfo_value = tree_cons (checksum, convert
! 				 (unsigned_type_node,
! 				  build_int_2 (item->cfg_checksum, 0)),
! 				 finfo_value);
! 	finfo_value = tree_cons (arcs, convert
! 				 (unsigned_type_node,
! 				  build_int_2 (item->count_edges, 0)),
! 				 finfo_value);
! 	array_value = tree_cons (NULL_TREE, build
! 				 (CONSTRUCTOR, finfo_type, NULL_TREE,
! 				  nreverse (finfo_value)), array_value);
!       }
  
!     /* Create constructor for array.  */
!     if (num_nodes)
!       {
! 	tree array_type;
  
! 	array_type = build_array_type (finfo_type, build_index_type
! 				       (build_int_2 (num_nodes - 1, 0)));
! 	array_value = build (CONSTRUCTOR, array_type,
! 			     NULL_TREE, nreverse (array_value));
! 	array_value = build1
! 	  (ADDR_EXPR, finfo_ptr_type, array_value);
!       }
!     else
!       array_value = null_pointer_node;
!     
!     field = build_decl (FIELD_DECL, NULL_TREE, finfo_ptr_type);
!     TREE_CHAIN (field) = fields;
!     fields = field;
!     value = tree_cons (fields, array_value, value);
!     
!     /* number of functions */
!     field = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
!     TREE_CHAIN (field) = fields;
!     fields = field;
!     value = tree_cons (fields, convert (unsigned_type_node, build_int_2
! 					(num_nodes, 0)), value);
!   }
    
!   /* arc count table */
!   {
!     tree counts_table = null_pointer_node;
!     
!     if (profile_info.count_instrumented_edges)
!       {
! 	tree gcov_type_array_type
! 	  = build_array_type (gcov_type, build_index_type
! 			      (build_int_2 (profile_info.
! 					    count_instrumented_edges - 1, 0)));
! 	/* No values.  */
! 	counts_table
! 	  = build (VAR_DECL, gcov_type_array_type, NULL_TREE, NULL_TREE);
! 	TREE_STATIC (counts_table) = 1;
! 	DECL_NAME (counts_table) = get_identifier (XSTR (profiler_label, 0));
! 	assemble_variable (counts_table, 0, 0, 0);
! 	counts_table = build1 (ADDR_EXPR, gcov_ptr_type, counts_table);
!       }
!     
!     field = build_decl (FIELD_DECL, NULL_TREE, gcov_ptr_type);
!     TREE_CHAIN (field) = fields;
!     fields = field;
!     value = tree_cons (fields, counts_table, value);
!   }
    
!   /* number of arc counts */
!   field = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
!   TREE_CHAIN (field) = fields;
!   fields = field;
!   value = tree_cons (fields, convert
! 		     (unsigned_type_node,
! 		      build_int_2 (profile_info
! 				   .count_instrumented_edges, 0)),
  		     value);
    
!   finish_builtin_struct (ginfo_type, "__gcov_info", fields, NULL_TREE);
!   structure = build (VAR_DECL, ginfo_type, NULL_TREE, NULL_TREE);
!   DECL_INITIAL (structure)
!     = build (CONSTRUCTOR, ginfo_type, NULL_TREE, nreverse (value));
!   TREE_STATIC (structure) = 1;
    ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 0);
!   DECL_NAME (structure) = get_identifier (name);
    
    /* Build structure.  */
!   assemble_variable (structure, 0, 0, 0);
  
    /* Build the constructor function to invoke __gcov_init.  */
    ctor_name = concat (IDENTIFIER_POINTER (get_file_function_name ('I')),
--- 1508,2077 ----
      }
  }
  
! /* Find (and create if not present) a section with TAG.  */
! struct section_info *
! find_counters_section (tag)
!      unsigned tag;
! {
!   unsigned i;
  
!   for (i = 0; i < profile_info.n_sections; i++)
!     if (profile_info.section_info[i].tag == tag)
!       return profile_info.section_info + i;
! 
!   if (i == MAX_COUNTER_SECTIONS)
!     abort ();
! 
!   profile_info.section_info[i].tag = tag;
!   profile_info.section_info[i].present = 0;
!   profile_info.section_info[i].n_counters = 0;
!   profile_info.section_info[i].n_counters_now = 0;
!   profile_info.n_sections++;
! 
!   return profile_info.section_info + i;
! }
! 
! /* Set FIELDS as purpose to VALUE.  */
! static void
! set_purpose (value, fields)
!      tree value;
!      tree fields;
  {
!   tree act_field, act_value;
!   
!   for (act_field = fields, act_value = value;
!        act_field;
!        act_field = TREE_CHAIN (act_field), act_value = TREE_CHAIN (act_value))
!     TREE_PURPOSE (act_value) = act_field;
! }
  
! /* Returns label for base of counters inside TAG section.  */
! static rtx
! label_for_tag (tag)
!      unsigned tag;
! {
!   switch (tag)
!     {
!     case GCOV_TAG_ARC_COUNTS:
!       return profiler_label;
!     default:
!       abort ();
!     }
! }
! 
! /* Creates fields of struct counter_section (in gcov-io.h).  */
! static tree
! build_counter_section_fields ()
! {
!   tree field, fields;
! 
!   /* tag */
!   fields = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
! 
!   /* n_counters */
!   field = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
!   TREE_CHAIN (field) = fields;
!   fields = field;
! 
!   return fields;
! }
! 
! /* Creates value of struct counter_section (in gcov-io.h).  */
! static tree
! build_counter_section_value (tag, n_counters)
!      unsigned tag;
!      unsigned n_counters;
! {
!   tree value = NULL_TREE;
! 
!   /* tag */
!   value = tree_cons (NULL_TREE,
! 		     convert (unsigned_type_node,
! 			      build_int_2 (tag, 0)),
! 		     value);
    
!   /* n_counters */
!   value = tree_cons (NULL_TREE,
! 		     convert (unsigned_type_node,
! 			      build_int_2 (n_counters, 0)),
! 		     value);
! 
!   return value;
! }
! 
! /* Creates fields of struct counter_section_data (in gcov-io.h).  */
! static tree
! build_counter_section_data_fields ()
! {
!   tree field, fields, gcov_type, gcov_ptr_type;
! 
!   gcov_type = make_signed_type (GCOV_TYPE_SIZE);
!   gcov_ptr_type =
! 	  build_pointer_type (build_qualified_type (gcov_type,
! 						    TYPE_QUAL_CONST));
! 
!   /* tag */
!   fields = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
! 
!   /* n_counters */
!   field = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
!   TREE_CHAIN (field) = fields;
!   fields = field;
! 
!   /* counters */
!   field = build_decl (FIELD_DECL, NULL_TREE, gcov_ptr_type);
!   TREE_CHAIN (field) = fields;
!   fields = field;
! 
!   return fields;
! }
! 
! /* Creates value of struct counter_section_data (in gcov-io.h).  */
! static tree
! build_counter_section_data_value (tag, n_counters)
!      unsigned tag;
!      unsigned n_counters;
! {
!   tree value = NULL_TREE, counts_table, gcov_type, gcov_ptr_type;
! 
    gcov_type = make_signed_type (GCOV_TYPE_SIZE);
    gcov_ptr_type
      = build_pointer_type (build_qualified_type
  			  (gcov_type, TYPE_QUAL_CONST));
+ 
+   /* tag */
+   value = tree_cons (NULL_TREE,
+ 		     convert (unsigned_type_node,
+ 			      build_int_2 (tag, 0)),
+ 		     value);
    
!   /* n_counters */
!   value = tree_cons (NULL_TREE,
! 		     convert (unsigned_type_node,
! 			      build_int_2 (n_counters, 0)),
! 		     value);
! 
!   /* counters */
!   if (n_counters)
!     {
!       tree gcov_type_array_type =
! 	      build_array_type (gcov_type,
! 				build_index_type (build_int_2 (n_counters - 1,
! 							       0)));
!       counts_table =
! 	      build (VAR_DECL, gcov_type_array_type, NULL_TREE, NULL_TREE);
!       TREE_STATIC (counts_table) = 1;
!       DECL_NAME (counts_table) = get_identifier (XSTR (label_for_tag (tag), 0));
!       assemble_variable (counts_table, 0, 0, 0);
!       counts_table = build1 (ADDR_EXPR, gcov_ptr_type, counts_table);
!     }
!   else
!     counts_table = null_pointer_node;
! 
!   value = tree_cons (NULL_TREE, counts_table, value);
! 
!   return value;
! }
! 
! /* Creates fields for struct function_info type (in gcov-io.h).  */
! static tree
! build_function_info_fields ()
! {
!   tree field, fields, counter_section_fields, counter_section_type;
!   tree counter_sections_ptr_type;
!   tree string_type =
! 	  build_pointer_type (build_qualified_type (char_type_node,
! 						    TYPE_QUAL_CONST));
!   /* name */
!   fields = build_decl (FIELD_DECL, NULL_TREE, string_type);
! 
!   /* checksum */
!   field = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
!   TREE_CHAIN (field) = fields;
!   fields = field;
! 
!   /* n_counter_sections */
!   field = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
!   TREE_CHAIN (field) = fields;
!   fields = field;
! 
!   /* counter_sections */
!   counter_section_fields = build_counter_section_fields ();
!   counter_section_type = (*lang_hooks.types.make_type) (RECORD_TYPE);
!   finish_builtin_struct (counter_section_type, "__counter_section",
! 			 counter_section_fields, NULL_TREE);
!   counter_sections_ptr_type =
! 	  build_pointer_type
! 	  	(build_qualified_type (counter_section_type,
! 				       TYPE_QUAL_CONST));
!   field = build_decl (FIELD_DECL, NULL_TREE, counter_sections_ptr_type);
!   TREE_CHAIN (field) = fields;
!   fields = field;
! 
!   return fields;
! }
! 
! /* Creates value for struct function_info (in gcov-io.h).  */
! static tree
! build_function_info_value (function)
!      struct function_list *function;
! {
!   tree value = NULL_TREE;
!   size_t name_len = strlen (function->name);
!   tree fname = build_string (name_len + 1, function->name);
!   tree string_type =
! 	  build_pointer_type (build_qualified_type (char_type_node,
! 						    TYPE_QUAL_CONST));
!   tree counter_section_fields, counter_section_type, counter_sections_value;
!   tree counter_sections_ptr_type, counter_sections_array_type;
!   unsigned i;
! 
!   /* name */
!   TREE_TYPE (fname) =
! 	  build_array_type (char_type_node,
! 			    build_index_type (build_int_2 (name_len, 0)));
!   value = tree_cons (NULL_TREE,
! 		     build1 (ADDR_EXPR,
! 			     string_type,
! 			     fname),
! 		     value);
! 
!   /* checksum */
!   value = tree_cons (NULL_TREE,
! 		     convert (unsigned_type_node,
! 			      build_int_2 (function->cfg_checksum, 0)),
! 		     value);
! 
!   /* n_counter_sections */
! 
!   value = tree_cons (NULL_TREE,
! 		     convert (unsigned_type_node,
! 			      build_int_2 (function->n_counter_sections, 0)),
! 	    	    value);
! 
!   /* counter_sections */
!   counter_section_fields = build_counter_section_fields ();
!   counter_section_type = (*lang_hooks.types.make_type) (RECORD_TYPE);
!   counter_sections_ptr_type =
! 	  build_pointer_type
! 	  	(build_qualified_type (counter_section_type,
! 				       TYPE_QUAL_CONST));
!   counter_sections_array_type =
! 	  build_array_type (counter_section_type,
! 			    build_index_type (
!       				build_int_2 (function->n_counter_sections - 1,
! 		  			     0)));
! 
!   counter_sections_value = NULL_TREE;
!   for (i = 0; i < function->n_counter_sections; i++)
!     {
!       tree counter_section_value =
! 	      build_counter_section_value (function->counter_sections[i].tag,
! 					   function->counter_sections[i].n_counters);
!       set_purpose (counter_section_value, counter_section_fields);
!       counter_sections_value = tree_cons (NULL_TREE,
! 					  build (CONSTRUCTOR,
! 						 counter_section_type,
! 						 NULL_TREE,
! 						 nreverse (counter_section_value)),
! 					  counter_sections_value);
!     }
!   finish_builtin_struct (counter_section_type, "__counter_section",
! 			 counter_section_fields, NULL_TREE);
! 
!   if (function->n_counter_sections)
!     {
!       counter_sections_value = 
! 	      build (CONSTRUCTOR,
!  		     counter_sections_array_type,
! 		     NULL_TREE,
! 		     nreverse (counter_sections_value)),
!       counter_sections_value = build1 (ADDR_EXPR,
! 				       counter_sections_ptr_type,
! 				       counter_sections_value);
!     }
!   else
!     counter_sections_value = null_pointer_node;
! 
!   value = tree_cons (NULL_TREE, counter_sections_value, value);
! 
!   return value;
! }
! 
! /* Creates fields of struct gcov_info type (in gcov-io.h).  */
! static tree
! build_gcov_info_fields (gcov_info_type)
!      tree gcov_info_type;
! {
!   tree field, fields;
!   char *filename;
!   int filename_len;
!   tree string_type =
! 	  build_pointer_type (build_qualified_type (char_type_node,
! 						    TYPE_QUAL_CONST));
!   tree function_info_fields, function_info_type, function_info_ptr_type;
!   tree counter_section_data_fields, counter_section_data_type;
!   tree counter_section_data_ptr_type;
  
    /* Version ident */
    fields = build_decl (FIELD_DECL, NULL_TREE, long_unsigned_type_node);
! 
!   /* next -- NULL */
!   field = build_decl (FIELD_DECL, NULL_TREE,
! 		      build_pointer_type (build_qualified_type (gcov_info_type,
! 								TYPE_QUAL_CONST)));
    TREE_CHAIN (field) = fields;
    fields = field;
    
    /* Filename */
!   filename = getpwd ();
!   filename = (filename && da_file_name[0] != '/'
! 	      ? concat (filename, "/", da_file_name, NULL)
! 	      : da_file_name);
!   filename_len = strlen (filename);
!   if (filename != da_file_name)
!     free (filename);
! 
!   field = build_decl (FIELD_DECL, NULL_TREE, string_type);
!   TREE_CHAIN (field) = fields;
!   fields = field;
    
    /* Workspace */
    field = build_decl (FIELD_DECL, NULL_TREE, long_integer_type_node);
    TREE_CHAIN (field) = fields;
    fields = field;
! 
!   /* number of functions */
!   field = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
!   TREE_CHAIN (field) = fields;
!   fields = field;
        
    /* function_info table */
!   function_info_fields = build_function_info_fields ();
!   function_info_type = (*lang_hooks.types.make_type) (RECORD_TYPE);
!   finish_builtin_struct (function_info_type, "__function_info",
! 			 function_info_fields, NULL_TREE);
!   function_info_ptr_type =
! 	  build_pointer_type
! 	  	(build_qualified_type (function_info_type,
! 				       TYPE_QUAL_CONST));
!   field = build_decl (FIELD_DECL, NULL_TREE, function_info_ptr_type);
!   TREE_CHAIN (field) = fields;
!   fields = field;
      
!   /* n_counter_sections  */
!   field = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
!   TREE_CHAIN (field) = fields;
!   fields = field;
!   
!   /* counter sections */
!   counter_section_data_fields = build_counter_section_data_fields ();
!   counter_section_data_type = (*lang_hooks.types.make_type) (RECORD_TYPE);
!   finish_builtin_struct (counter_section_data_type, "__counter_section_data",
! 			 counter_section_data_fields, NULL_TREE);
!   counter_section_data_ptr_type =
! 	  build_pointer_type
! 	  	(build_qualified_type (counter_section_data_type,
! 				       TYPE_QUAL_CONST));
!   field = build_decl (FIELD_DECL, NULL_TREE, counter_section_data_ptr_type);
!   TREE_CHAIN (field) = fields;
!   fields = field;
  
!   return fields;
! }
  
! /* Creates struct gcov_info value (in gcov-io.h).  */
! static tree
! build_gcov_info_value ()
! {
!   tree value = NULL_TREE;
!   tree filename_string;
!   char *filename;
!   int filename_len;
!   unsigned n_functions, i;
!   struct function_list *item;
!   tree string_type =
! 	  build_pointer_type (build_qualified_type (char_type_node,
! 						    TYPE_QUAL_CONST));
!   tree function_info_fields, function_info_type, function_info_ptr_type;
!   tree functions;
!   tree counter_section_data_fields, counter_section_data_type;
!   tree counter_section_data_ptr_type, counter_sections;
! 
!   /* Version ident */
!   value = tree_cons (NULL_TREE,
! 		     convert (long_unsigned_type_node,
! 			      build_int_2 (GCOV_VERSION, 0)),
! 		     value);
! 
!   /* next -- NULL */
!   value = tree_cons (NULL_TREE, null_pointer_node, value);
    
!   /* Filename */
!   filename = getpwd ();
!   filename = (filename && da_file_name[0] != '/'
! 	      ? concat (filename, "/", da_file_name, NULL)
! 	      : da_file_name);
!   filename_len = strlen (filename);
!   filename_string = build_string (filename_len + 1, filename);
!   if (filename != da_file_name)
!     free (filename);
!   TREE_TYPE (filename_string) =
! 	  build_array_type (char_type_node,
! 			    build_index_type (build_int_2 (filename_len, 0)));
!   value = tree_cons (NULL_TREE,
! 		     build1 (ADDR_EXPR,
! 			     string_type,
! 		       	     filename_string),
! 		     value);
    
!   /* Workspace */
!   value = tree_cons (NULL_TREE,
! 		     convert (long_integer_type_node, integer_zero_node),
  		     value);
+       
+   /* number of functions */
+   n_functions = 0;
+   for (item = functions_head; item != 0; item = item->next, n_functions++)
+     continue;
+   value = tree_cons (NULL_TREE,
+ 		     convert (unsigned_type_node,
+ 			      build_int_2 (n_functions, 0)),
+ 		     value);
+ 
+   /* function_info table */
+   function_info_fields = build_function_info_fields ();
+   function_info_type = (*lang_hooks.types.make_type) (RECORD_TYPE);
+   function_info_ptr_type =
+ 	  build_pointer_type (
+ 		build_qualified_type (function_info_type,
+ 	       			      TYPE_QUAL_CONST));
+   functions = NULL_TREE;
+   for (item = functions_head; item != 0; item = item->next)
+     {
+       tree function_info_value = build_function_info_value (item);
+       set_purpose (function_info_value, function_info_fields);
+       functions = tree_cons (NULL_TREE,
+     			     build (CONSTRUCTOR,
+ 			    	    function_info_type,
+ 				    NULL_TREE,
+ 				    nreverse (function_info_value)),
+ 			     functions);
+     }
+   finish_builtin_struct (function_info_type, "__function_info",
+ 			 function_info_fields, NULL_TREE);
+ 
+   /* Create constructor for array.  */
+   if (n_functions)
+     {
+       tree array_type;
+ 
+       array_type = build_array_type (
+ 			function_info_type,
+    			build_index_type (build_int_2 (n_functions - 1, 0)));
+       functions = build (CONSTRUCTOR,
+       			 array_type,
+ 			 NULL_TREE,
+ 			 nreverse (functions));
+       functions = build1 (ADDR_EXPR,
+ 			  function_info_ptr_type,
+ 			  functions);
+     }
+   else
+     functions = null_pointer_node;
+ 
+   value = tree_cons (NULL_TREE, functions, value);
+ 
+   /* n_counter_sections  */
+   value = tree_cons (NULL_TREE,
+ 		     convert (unsigned_type_node,
+ 			      build_int_2 (profile_info.n_sections, 0)),
+ 		     value);
+   
+   /* counter sections */
+   counter_section_data_fields = build_counter_section_data_fields ();
+   counter_section_data_type = (*lang_hooks.types.make_type) (RECORD_TYPE);
+   counter_sections = NULL_TREE;
+   for (i = 0; i < profile_info.n_sections; i++)
+     {
+       tree counter_sections_value =
+ 	      build_counter_section_data_value (
+ 		profile_info.section_info[i].tag,
+ 		profile_info.section_info[i].n_counters);
+       set_purpose (counter_sections_value, counter_section_data_fields);
+       counter_sections = tree_cons (NULL_TREE,
+ 		       		    build (CONSTRUCTOR,
+ 		       			   counter_section_data_type,
+ 		       			   NULL_TREE,
+ 		       			   nreverse (counter_sections_value)),
+ 		       		    counter_sections);
+     }
+   finish_builtin_struct (counter_section_data_type, "__counter_section_data",
+ 			 counter_section_data_fields, NULL_TREE);
+   counter_section_data_ptr_type =
+ 	  build_pointer_type
+ 	  	(build_qualified_type (counter_section_data_type,
+ 				       TYPE_QUAL_CONST));
+ 
+   if (profile_info.n_sections)
+     {
+       counter_sections =
+     	      build (CONSTRUCTOR,
+     		     build_array_type (
+ 	       			       counter_section_data_type,
+ 		       		       build_index_type (build_int_2 (profile_info.n_sections - 1, 0))),
+ 		     NULL_TREE,
+ 		     nreverse (counter_sections));
+       counter_sections = build1 (ADDR_EXPR,
+ 				 counter_section_data_ptr_type,
+ 				 counter_sections);
+     }
+   else
+     counter_sections = null_pointer_node;
+   value = tree_cons (NULL_TREE, counter_sections, value);
+ 
+   return value;
+ }
+ 
+ /* Write out the structure which libgcc uses to locate all the arc
+    counters.  The structures used here must match those defined in
+    gcov-io.h.  Write out the constructor to call __gcov_init.  */
+ 
+ void
+ create_profiler ()
+ {
+   tree gcov_info_fields, gcov_info_type, gcov_info_value, gcov_info;
+   char name[20];
+   char *ctor_name;
+   tree ctor;
+   rtx gcov_info_address;
+   int save_flag_inline_functions = flag_inline_functions;
+   unsigned i;
+ 
+   for (i = 0; i < profile_info.n_sections; i++)
+     if (profile_info.section_info[i].n_counters_now)
+       break;
+   if (i == profile_info.n_sections)
+     return;
    
!   gcov_info_type = (*lang_hooks.types.make_type) (RECORD_TYPE);
!   gcov_info_fields = build_gcov_info_fields (gcov_info_type);
!   gcov_info_value = build_gcov_info_value ();
!   set_purpose (gcov_info_value, gcov_info_fields);
!   finish_builtin_struct (gcov_info_type, "__gcov_info",
! 			 gcov_info_fields, NULL_TREE);
! 
!   gcov_info = build (VAR_DECL, gcov_info_type, NULL_TREE, NULL_TREE);
!   DECL_INITIAL (gcov_info) =
! 	  build (CONSTRUCTOR, gcov_info_type, NULL_TREE,
! 		 nreverse (gcov_info_value));
! 
!   TREE_STATIC (gcov_info) = 1;
    ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 0);
!   DECL_NAME (gcov_info) = get_identifier (name);
    
    /* Build structure.  */
!   assemble_variable (gcov_info, 0, 0, 0);
  
    /* Build the constructor function to invoke __gcov_init.  */
    ctor_name = concat (IDENTIFIER_POINTER (get_file_function_name ('I')),
*************** create_profiler ()
*** 1696,1707 ****
    cfun->arc_profile = 0;
  
    /* Actually generate the code to call __gcov_init.  */
!   structure_address = force_reg (Pmode, gen_rtx_SYMBOL_REF
! 				 (Pmode, IDENTIFIER_POINTER
! 				  (DECL_NAME (structure))));
    emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__gcov_init"),
  		     LCT_NORMAL, VOIDmode, 1,
! 		     structure_address, Pmode);
  
    expand_function_end (input_filename, lineno, 0);
    (*lang_hooks.decls.poplevel) (1, 0, 1);
--- 2099,2112 ----
    cfun->arc_profile = 0;
  
    /* Actually generate the code to call __gcov_init.  */
!   gcov_info_address = force_reg (Pmode,
! 				 gen_rtx_SYMBOL_REF (
! 					Pmode,
! 					IDENTIFIER_POINTER (
! 						DECL_NAME (gcov_info))));
    emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__gcov_init"),
  		     LCT_NORMAL, VOIDmode, 1,
! 		     gcov_info_address, Pmode);
  
    expand_function_end (input_filename, lineno, 0);
    (*lang_hooks.decls.poplevel) (1, 0, 1);
Index: profile.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/profile.h,v
retrieving revision 1.4
diff -c -3 -p -r1.4 profile.h
*** profile.h	16 Dec 2002 18:19:47 -0000	1.4
--- profile.h	9 Feb 2003 19:58:01 -0000
*************** Software Foundation, 59 Temple Place - S
*** 21,38 ****
  #ifndef GCC_PROFILE_H
  #define GCC_PROFILE_H
  
! struct profile_info
!   {
!     /* Used by final, for allocating the proper amount of storage for the
!        instrumented arc execution counts.  */
! 
!     int count_instrumented_edges;
! 
!     /* Used by final, for writing correct # of instrumented edges
!        in this function.  */
  
!     int count_edges_instrumented_now;
  
      /* Checksum of the cfg. Used for 'identification' of code.
         Used by final.  */
  
--- 21,45 ----
  #ifndef GCC_PROFILE_H
  #define GCC_PROFILE_H
  
! /* The number of different counter sections.  */
! #define MAX_COUNTER_SECTIONS	1
  
! /* Info about number of counters in the section.  */
! struct section_info
! {
!   unsigned tag;		/* Section tag.  */
!   int present;		/* Are the data from this section read into gcc?  */
!   int n_counters;	/* Total number of counters.  */
!   int n_counters_now;	/* Number of counters in the current function.  */
! };
  
+ struct profile_info
+   {
+     /* Information about numbers of counters in counter sections, for
+        allocating the storage and storing the sizes.  */
+     unsigned n_sections;
+     struct section_info section_info[MAX_COUNTER_SECTIONS];
+     
      /* Checksum of the cfg. Used for 'identification' of code.
         Used by final.  */
  
*************** struct profile_info
*** 46,54 ****
      /* The number of profiles merged to form the profile data for the current
         function.  */
      int count_profiles_merged;
- 
    };
  
  extern struct profile_info profile_info;
  
  #endif
--- 53,62 ----
      /* The number of profiles merged to form the profile data for the current
         function.  */
      int count_profiles_merged;
    };
  
  extern struct profile_info profile_info;
+ 
+ struct section_info *find_counters_section	PARAMS ((unsigned));
  
  #endif


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]