⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 profile.c

📁 GCC编译器源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* Calculate branch probabilities, and basic block execution counts.    Copyright (C) 1990, 91, 92, 93, 94, 96, 1997 Free Software Foundation, Inc.   Contributed by James E. Wilson, UC Berkeley/Cygnus Support;   based on some ideas from Dain Samples of UC Berkeley.   Further mangling by Bob Manson, Cygnus Support.This file is part of GNU CC.GNU CC is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2, or (at your option)any later version.GNU CC is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU CC; see the file COPYING.  If not, write tothe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  *//* ??? Really should not put insns inside of LIBCALL sequences, when putting   insns after a call, should look for the insn setting the retval, and   insert the insns after that one.  *//* ??? Register allocation should use basic block execution counts to   give preference to the most commonly executed blocks.  *//* ??? The .da files are not safe.  Changing the program after creating .da   files or using different options when compiling with -fbranch-probabilities   can result the arc data not matching the program.  Maybe add instrumented   arc count to .bbg file?  Maybe check whether PFG matches the .bbg file?  *//* ??? Should calculate branch probabilities before instrumenting code, since   then we can use arc counts to help decide which arcs to instrument.  *//* ??? Rearrange code so that the most frequently executed arcs become from   one block to the next block (i.e. a fall through), move seldom executed   code outside of loops even at the expense of adding a few branches to   achieve this, see Dain Sample's UC Berkeley thesis.  */#include "config.h"#include <stdio.h>#include "rtl.h"#include "flags.h"#include "insn-flags.h"#include "insn-config.h"#include "output.h"#include "regs.h"#include "tree.h"#include "output.h"#include "gcov-io.h"extern char * xmalloc ();extern void free ();/* One of these is dynamically created whenever we identify an arc in the   function.  */struct adj_list{  int source;  int target;  int arc_count;  unsigned int count_valid : 1;  unsigned int on_tree : 1;  unsigned int fake : 1;  unsigned int fall_through : 1;  rtx branch_insn;  struct adj_list *pred_next;  struct adj_list *succ_next;};#define ARC_TARGET(ARCPTR) (ARCPTR->target)#define ARC_SOURCE(ARCPTR) (ARCPTR->source)#define ARC_COUNT(ARCPTR)  (ARCPTR->arc_count)/* Count the number of basic blocks, and create an array of these structures,   one for each bb in the function.  */struct bb_info{  struct adj_list *succ;  struct adj_list *pred;  int succ_count;  int pred_count;  int exec_count;  unsigned int count_valid : 1;  unsigned int on_tree : 1;  rtx first_insn;};/* Indexed by label number, gives the basic block number containing that   label.  */static int *label_to_bb;/* Number of valid entries in the label_to_bb array.  */static int label_to_bb_size;/* Indexed by block index, holds the basic block graph.  */static struct bb_info *bb_graph;/* Name and file pointer of the output file for the basic block graph.  */static char *bbg_file_name;static FILE *bbg_file;/* Name and file pointer of the input file for the arc count data.  */static char *da_file_name;static FILE *da_file;/* Pointer of the output file for the basic block/line number map. */static FILE *bb_file;/* Last source file name written to bb_file. */static char *last_bb_file_name;/* Indicates whether the next line number note should be output to   bb_file or not.  Used to eliminate a redundant note after an   expanded inline function call.  */static int ignore_next_note;/* Used by final, for allocating the proper amount of storage for the   instrumented arc execution counts.  */int count_instrumented_arcs;/* Number of executions for the return label.  */int return_label_execution_count;/* Collect statistics on the performance of this pass for the entire source   file.  */static int total_num_blocks;static int total_num_arcs;static int total_num_arcs_instrumented;static int total_num_blocks_created;static int total_num_passes;static int total_num_times_called;static int total_hist_br_prob[20];static int total_num_never_executed;static int total_num_branches;/* Forward declarations.  */static void init_arc PROTO((struct adj_list *, int, int, rtx));static void find_spanning_tree PROTO((int));static void expand_spanning_tree PROTO((int));static void fill_spanning_tree PROTO((int));static void init_arc_profiler PROTO((void));static void output_arc_profiler PROTO((int, rtx));#ifndef LONG_TYPE_SIZE#define LONG_TYPE_SIZE BITS_PER_WORD#endif/* If non-zero, we need to output a constructor to set up the   per-object-file data. */static int need_func_profiler = 0;/* Add arc instrumentation code to the entire insn chain.   F is the first insn of the chain.   NUM_BLOCKS is the number of basic blocks found in F.   DUMP_FILE, if nonzero, is an rtl dump file we can write to.  */static voidinstrument_arcs (f, num_blocks, dump_file)     rtx f;     int num_blocks;     FILE *dump_file;{  register int i;  register struct adj_list *arcptr, *backptr;  int num_arcs = 0;  int num_instr_arcs = 0;  rtx insn;  int neg_one = -1;  int zero = 0;  int inverted;  rtx note;  /* Instrument the program start.  */  /* Handle block 0 specially, since it will always be instrumented,     but it doesn't have a valid first_insn or branch_insn.  We must     put the instructions before the NOTE_INSN_FUNCTION_BEG note, so     that they don't clobber any of the parameters of the current     function.  */  for (insn = f; insn; insn = NEXT_INSN (insn))    if (GET_CODE (insn) == NOTE	&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG)      break;  insn = PREV_INSN (insn);  need_func_profiler = 1;  output_arc_profiler (total_num_arcs_instrumented + num_instr_arcs++, insn);  for (i = 1; i < num_blocks; i++)    for (arcptr = bb_graph[i].succ; arcptr; arcptr = arcptr->succ_next)      if (! arcptr->on_tree)	{	  if (dump_file)	    fprintf (dump_file, "Arc %d to %d instrumented\n", i,		     ARC_TARGET (arcptr));	  /* Check to see if this arc is the only exit from its source block,	     or the only entrance to its target block.  In either case,	     we don't need to create a new block to instrument the arc.  */	  	  if (bb_graph[i].succ == arcptr && arcptr->succ_next == 0)	    {	      /* Instrument the source block.  */	      output_arc_profiler (total_num_arcs_instrumented				   + num_instr_arcs++,				   PREV_INSN (bb_graph[i].first_insn));	    }	  else if (arcptr == bb_graph[ARC_TARGET (arcptr)].pred		   && arcptr->pred_next == 0)	    {	      /* Instrument the target block.  */	      output_arc_profiler (total_num_arcs_instrumented				   + num_instr_arcs++, 				   PREV_INSN (bb_graph[ARC_TARGET (arcptr)].first_insn));	    }	  else if (arcptr->fall_through)	    {	      /* This is a fall-through; put the instrumentation code after		 the branch that ends this block.  */	      	      for (backptr = bb_graph[i].succ; backptr;		   backptr = backptr->succ_next)		if (backptr != arcptr)		  break;	      	      output_arc_profiler (total_num_arcs_instrumented				   + num_instr_arcs++,				   backptr->branch_insn);	    }	  else	    {	      /* Must emit a new basic block to hold the arc counting code.  */	      enum rtx_code code = GET_CODE (PATTERN (arcptr->branch_insn));	      if (code == SET)		{		  /* Create the new basic block right after the branch.		     Invert the branch so that it jumps past the end of the new		     block.  The new block will consist of the instrumentation		     code, and a jump to the target of this arc.  */		  int this_is_simplejump = simplejump_p (arcptr->branch_insn);		  rtx new_label = gen_label_rtx ();		  rtx old_label, set_src;		  rtx after = arcptr->branch_insn;		  		  /* Simplejumps can't reach here.  */		  if (this_is_simplejump)		    abort ();		  /* We can't use JUMP_LABEL, because it won't be set if we		     are compiling without optimization.  */		  set_src = SET_SRC (single_set (arcptr->branch_insn));		  if (GET_CODE (set_src) == LABEL_REF)		    old_label = set_src;		  else if (GET_CODE (set_src) != IF_THEN_ELSE)		    abort ();		  else if (XEXP (set_src, 1) == pc_rtx)		    old_label = XEXP (XEXP (set_src, 2), 0);		  else		    old_label = XEXP (XEXP (set_src, 1), 0);		  /* Set the JUMP_LABEL so that redirect_jump will work.  */		  JUMP_LABEL (arcptr->branch_insn) = old_label;		  /* Add a use for OLD_LABEL that will be needed when we emit		     the JUMP_INSN below.  If we don't do this here,		     `invert_jump' might delete it for us.  We must add two		     when not optimizing, because the NUSES is zero now,		     but must be at least two to prevent the label from being		     deleted.  */		  LABEL_NUSES (old_label) += 2;		  		  /* Emit the insns for the new block in reverse order,		     since that is most convenient.  */		  if (this_is_simplejump)		    {		      after = NEXT_INSN (arcptr->branch_insn);		      if (! redirect_jump (arcptr->branch_insn, new_label))			/* Don't know what to do if this branch won't			   redirect.  */			abort ();		    }		  else		    {		      if (! invert_jump (arcptr->branch_insn, new_label))			/* Don't know what to do if this branch won't invert.  */			abort ();		      emit_label_after (new_label, after);		      LABEL_NUSES (new_label)++;		    }		  emit_barrier_after (after);		  emit_jump_insn_after (gen_jump (old_label), after);		  JUMP_LABEL (NEXT_INSN (after)) = old_label;		  		  /* Instrument the source arc.  */		  output_arc_profiler (total_num_arcs_instrumented				       + num_instr_arcs++,				       after);		  if (this_is_simplejump)		    {		      emit_label_after (new_label, after);		      LABEL_NUSES (new_label)++;		    }		}	      else if (code == ADDR_VEC || code == ADDR_DIFF_VEC)		{		  /* A table jump.  Create a new basic block immediately		     after the table, by emitting a barrier, a label, a		     counting note, and a jump to the old label.  Put the		     new label in the table.  */		  		  rtx new_label = gen_label_rtx ();		  rtx old_lref, new_lref;		  int index;		  		  /* Must determine the old_label reference, do this		     by counting the arcs after this one, which will		     give the index of our label in the table.  */		  		  index = 0;		  for (backptr = arcptr->succ_next; backptr;		       backptr = backptr->succ_next)		    index++;		  		  old_lref = XVECEXP (PATTERN (arcptr->branch_insn),				      (code == ADDR_DIFF_VEC), index);		  		  /* Emit the insns for the new block in reverse order,		     since that is most convenient.  */		  emit_jump_insn_after (gen_jump (XEXP (old_lref, 0)),					arcptr->branch_insn);		  JUMP_LABEL (NEXT_INSN (arcptr->branch_insn))		    = XEXP (old_lref, 0);		  /* Instrument the source arc.  */		  output_arc_profiler (total_num_arcs_instrumented				       + num_instr_arcs++,				       arcptr->branch_insn);		  emit_label_after (new_label, arcptr->branch_insn);		  LABEL_NUSES (NEXT_INSN (arcptr->branch_insn))++;		  emit_barrier_after (arcptr->branch_insn);		  		  /* Fix up the table jump.  */		  new_lref = gen_rtx (LABEL_REF, Pmode, new_label);		  XVECEXP (PATTERN (arcptr->branch_insn),			   (code == ADDR_DIFF_VEC), index) = new_lref;		}	      else		abort ();	      num_arcs += 1;	      if (dump_file)		fprintf (dump_file,			 "Arc %d to %d needed new basic block\n", i,			 ARC_TARGET (arcptr));	    }	}    total_num_arcs_instrumented += num_instr_arcs;  count_instrumented_arcs = total_num_arcs_instrumented;  total_num_blocks_created += num_arcs;  if (dump_file)    {      fprintf (dump_file, "%d arcs instrumented\n", num_instr_arcs);      fprintf (dump_file, "%d extra basic blocks created\n", num_arcs);    }}/* Output STRING to bb_file, surrounded by DELIMITER.  */static voidoutput_gcov_string (string, delimiter)     char *string;     long delimiter;{  long temp;			  /* Write a delimiter to indicate that a file name follows.  */  __write_long (delimiter, bb_file, 4);  /* Write the string.  */  temp = strlen (string) + 1;  fwrite (string, temp, 1, bb_file);  /* Append a few zeros, to align the output to a 4 byte boundary.  */  temp = temp & 0x3;  if (temp)    {      char c[4];

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -