PATCH: Avoid unncessary identifier lookups

Mark Mitchell mark@codesourcery.com
Mon Dec 20 02:14:00 GMT 2004


The assemble_name function tries to look up the name to see if there
is an existing IDENTIFIER_NODE with that name, and, if so, set
TREE_SYMBOL_REFERENCED.  That's a design bug; the argument to
assemble_name should be a tree directly in that case -- it's a bad
idea to try to get back to the IDENTIFIER_NODE via the identifier hash
table.  However, it's hard to fix that, especially at this point.

This inefficiency was significant for Qt builds; profiling showed that
as many as 25% of all identifier hash table lookups were coming from
assemble_name, because that was used by both default_internal_label
and darwin_asm_output_dwarf_delta.  Eliminating the inefficiency is
worth about 0.3% on Qt builds.  (I have three patches which together
produce a clearly measurable 1% improvement; it's hard to isolate the
exact amount for each patch because there is enough measurement noise
that it would take a ton of runs to get very precise.)

Tested on i686-pc-linux-gnu, applied on the mainline.

--
Mark Mitchell
CodeSourcery, LLC
mark@codesourcery.com

2004-12-19  Mark Mitchell  <mark@codesourcery.com>

	* defaults.h (ASM_OUTPUT_INTERNAL_LABEL): New macro.
	* output.h (assemble_name_raw): Declare it.
	* system.h (ASM_OUTPUT_INTERNAL_LABEL): Do not poison it.
	* varasm.c (assemble_name_raw): New function.
	(assemble_name): Use it.
	(default_internal_label): Likewise.
	* config/darwin.c (darwin_asm_output_dwarf_delta): Likewise.
	* doc/tm.texi (ASM_OUTPUT_INTERNAL_LABEL): Document.

Index: defaults.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/defaults.h,v
retrieving revision 1.164
diff -c -5 -p -r1.164 defaults.h
*** defaults.h	13 Dec 2004 16:03:36 -0000	1.164
--- defaults.h	20 Dec 2004 02:05:36 -0000
*************** do { fputs (integer_asm_op (POINTER_SIZE
*** 143,152 ****
--- 143,161 ----
  #ifndef ASM_OUTPUT_LABEL
  #define ASM_OUTPUT_LABEL(FILE,NAME) \
    do { assemble_name ((FILE), (NAME)); fputs (":\n", (FILE)); } while (0)
  #endif
  
+ /* Output the definition of a compiler-generated label named NAME.  */
+ #ifndef ASM_OUTPUT_INTERNAL_LABEL
+ #define ASM_OUTPUT_INTERNAL_LABEL(FILE,NAME)	\
+   do {						\
+     assemble_name_raw ((FILE), (NAME));		\
+     fputs (":\n", (FILE));			\
+   } while (0)
+ #endif
+ 
  /* This is how to output a reference to a user-level label named NAME.  */
  
  #ifndef ASM_OUTPUT_LABELREF
  #define ASM_OUTPUT_LABELREF(FILE,NAME)  asm_fprintf ((FILE), "%U%s", (NAME))
  #endif
Index: output.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/output.h,v
retrieving revision 1.149
diff -c -5 -p -r1.149 output.h
*** output.h	17 Nov 2004 22:05:59 -0000	1.149
--- output.h	20 Dec 2004 02:05:36 -0000
*************** extern void assemble_string (const char 
*** 289,303 ****
  extern void assemble_external_libcall (rtx);
  
  /* Assemble a label named NAME.  */
  extern void assemble_label (const char *);
  
! /* Output to FILE a reference to the assembler name of a C-level name NAME.
!    If NAME starts with a *, the rest of NAME is output verbatim.
!    Otherwise NAME is transformed in an implementation-defined way
!    (usually by the addition of an underscore).
!    Many macros in the tm file are defined to call this function.  */
  extern void assemble_name (FILE *, const char *);
  
  /* Return the assembler directive for creating a given kind of integer
     object.  SIZE is the number of bytes in the object and ALIGNED_P
     indicates whether it is known to be aligned.  Return NULL if the
--- 289,308 ----
  extern void assemble_external_libcall (rtx);
  
  /* Assemble a label named NAME.  */
  extern void assemble_label (const char *);
  
! /* Output to FILE (an assembly file) a reference to NAME.  If NAME
!    starts with a *, the rest of NAME is output verbatim.  Otherwise
!    NAME is transformed in a target-specific way (usually by the
!    addition of an underscore).  */
! extern void assemble_name_raw (FILE *, const char *);
! 
! /* Like assemble_name_raw, but should be used when NAME might refer to
!    an entity that is also represented as a tree (like a function or
!    variable).  If NAME does refer to such an entity, that entity will
!    be marked as referenced.  */
  extern void assemble_name (FILE *, const char *);
  
  /* Return the assembler directive for creating a given kind of integer
     object.  SIZE is the number of bytes in the object and ALIGNED_P
     indicates whether it is known to be aligned.  Return NULL if the
Index: system.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/system.h,v
retrieving revision 1.238
diff -c -5 -p -r1.238 system.h
*** system.h	29 Nov 2004 20:46:11 -0000	1.238
--- system.h	20 Dec 2004 02:05:36 -0000
*************** extern void fancy_abort (const char *, i
*** 629,639 ****
  	TRADITIONAL_RETURN_FLOAT NO_BUILTIN_SIZE_TYPE			   \
  	NO_BUILTIN_PTRDIFF_TYPE NO_BUILTIN_WCHAR_TYPE NO_BUILTIN_WINT_TYPE \
  	BLOCK_PROFILER BLOCK_PROFILER_CODE FUNCTION_BLOCK_PROFILER	   \
  	FUNCTION_BLOCK_PROFILER_EXIT MACHINE_STATE_SAVE			   \
  	MACHINE_STATE_RESTORE SCCS_DIRECTIVE SECTION_ASM_OP		   \
! 	ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL ASM_OUTPUT_INTERNAL_LABEL \
  	OBJC_PROLOGUE ALLOCATE_TRAMPOLINE HANDLE_PRAGMA ROUND_TYPE_SIZE	   \
  	ROUND_TYPE_SIZE_UNIT CONST_SECTION_ASM_OP CRT_GET_RFIB_TEXT	   \
  	DBX_LBRAC_FIRST DBX_OUTPUT_ENUM DBX_OUTPUT_SOURCE_FILENAME	   \
  	DBX_WORKING_DIRECTORY INSN_CACHE_DEPTH INSN_CACHE_SIZE		   \
  	INSN_CACHE_LINE_WIDTH INIT_SECTION_PREAMBLE NEED_ATEXIT ON_EXIT	   \
--- 629,639 ----
  	TRADITIONAL_RETURN_FLOAT NO_BUILTIN_SIZE_TYPE			   \
  	NO_BUILTIN_PTRDIFF_TYPE NO_BUILTIN_WCHAR_TYPE NO_BUILTIN_WINT_TYPE \
  	BLOCK_PROFILER BLOCK_PROFILER_CODE FUNCTION_BLOCK_PROFILER	   \
  	FUNCTION_BLOCK_PROFILER_EXIT MACHINE_STATE_SAVE			   \
  	MACHINE_STATE_RESTORE SCCS_DIRECTIVE SECTION_ASM_OP		   \
! 	ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL \
  	OBJC_PROLOGUE ALLOCATE_TRAMPOLINE HANDLE_PRAGMA ROUND_TYPE_SIZE	   \
  	ROUND_TYPE_SIZE_UNIT CONST_SECTION_ASM_OP CRT_GET_RFIB_TEXT	   \
  	DBX_LBRAC_FIRST DBX_OUTPUT_ENUM DBX_OUTPUT_SOURCE_FILENAME	   \
  	DBX_WORKING_DIRECTORY INSN_CACHE_DEPTH INSN_CACHE_SIZE		   \
  	INSN_CACHE_LINE_WIDTH INIT_SECTION_PREAMBLE NEED_ATEXIT ON_EXIT	   \
Index: varasm.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/varasm.c,v
retrieving revision 1.469
diff -c -5 -p -r1.469 varasm.c
*** varasm.c	18 Dec 2004 21:49:53 -0000	1.469
--- varasm.c	20 Dec 2004 02:05:36 -0000
*************** mark_decl_referenced (tree decl)
*** 1887,1901 ****
      cgraph_varpool_mark_needed_node (cgraph_varpool_node (decl));
    /* else do nothing - we can get various sorts of CST nodes here,
       which do not need to be marked.  */
  }
  
! /* Output to FILE a reference to the assembler name of a C-level name NAME.
!    If NAME starts with a *, the rest of NAME is output verbatim.
!    Otherwise NAME is transformed in an implementation-defined way
!    (usually by the addition of an underscore).
!    Many macros in the tm file are defined to call this function.  */
  
  void
  assemble_name (FILE *file, const char *name)
  {
    const char *real_name;
--- 1887,1914 ----
      cgraph_varpool_mark_needed_node (cgraph_varpool_node (decl));
    /* else do nothing - we can get various sorts of CST nodes here,
       which do not need to be marked.  */
  }
  
! /* Output to FILE (an assembly file) a reference to NAME.  If NAME
!    starts with a *, the rest of NAME is output verbatim.  Otherwise
!    NAME is transformed in a target-specific way (usually by the
!    addition of an underscore).  */
! 
! void
! assemble_name_raw (FILE *file, const char *name)
! {
!   if (name[0] == '*')
!     fputs (&name[1], file);
!   else
!     ASM_OUTPUT_LABELREF (file, name);
! }
! 
! /* Like assemble_name_raw, but should be used when NAME might refer to
!    an entity that is also represented as a tree (like a function or
!    variable).  If NAME does refer to such an entity, that entity will
!    be marked as referenced.  */
  
  void
  assemble_name (FILE *file, const char *name)
  {
    const char *real_name;
*************** assemble_name (FILE *file, const char *n
*** 1905,1918 ****
  
    id = maybe_get_identifier (real_name);
    if (id)
      mark_referenced (id);
  
!   if (name[0] == '*')
!     fputs (&name[1], file);
!   else
!     ASM_OUTPUT_LABELREF (file, name);
  }
  
  /* Allocate SIZE bytes writable static space with a gensym name
     and return an RTX to refer to its address.  */
  
--- 1918,1928 ----
  
    id = maybe_get_identifier (real_name);
    if (id)
      mark_referenced (id);
  
!   assemble_name_raw (file, name);
  }
  
  /* Allocate SIZE bytes writable static space with a gensym name
     and return an RTX to refer to its address.  */
  
*************** void
*** 5202,5212 ****
  default_internal_label (FILE *stream, const char *prefix,
  			unsigned long labelno)
  {
    char *const buf = alloca (40 + strlen (prefix));
    ASM_GENERATE_INTERNAL_LABEL (buf, prefix, labelno);
!   ASM_OUTPUT_LABEL (stream, buf);
  }
  
  /* This is the default behavior at the beginning of a file.  It's
     controlled by two other target-hook toggles.  */
  void
--- 5212,5222 ----
  default_internal_label (FILE *stream, const char *prefix,
  			unsigned long labelno)
  {
    char *const buf = alloca (40 + strlen (prefix));
    ASM_GENERATE_INTERNAL_LABEL (buf, prefix, labelno);
!   ASM_OUTPUT_INTERNAL_LABEL (stream, buf);
  }
  
  /* This is the default behavior at the beginning of a file.  It's
     controlled by two other target-hook toggles.  */
  void
Index: config/darwin.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/darwin.c,v
retrieving revision 1.99
diff -c -5 -p -r1.99 darwin.c
*** config/darwin.c	17 Dec 2004 00:25:06 -0000	1.99
--- config/darwin.c	20 Dec 2004 02:05:37 -0000
*************** darwin_asm_output_dwarf_delta (FILE *fil
*** 1365,1377 ****
  
    if (islocaldiff)
      fprintf (file, "\t.set L$set$%d,", darwin_dwarf_label_counter);
    else
      fprintf (file, "\t%s\t", ".long");
!   assemble_name (file, lab1);
    fprintf (file, "-");
!   assemble_name (file, lab2);
    if (islocaldiff)
      fprintf (file, "\n\t.long L$set$%d", darwin_dwarf_label_counter++);
  }
  
  void
--- 1365,1377 ----
  
    if (islocaldiff)
      fprintf (file, "\t.set L$set$%d,", darwin_dwarf_label_counter);
    else
      fprintf (file, "\t%s\t", ".long");
!   assemble_name_raw (file, lab1);
    fprintf (file, "-");
!   assemble_name_raw (file, lab2);
    if (islocaldiff)
      fprintf (file, "\n\t.long L$set$%d", darwin_dwarf_label_counter++);
  }
  
  void
Index: doc/tm.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/doc/tm.texi,v
retrieving revision 1.405
diff -c -5 -p -r1.405 tm.texi
*** doc/tm.texi	13 Dec 2004 06:57:12 -0000	1.405
--- doc/tm.texi	20 Dec 2004 02:05:37 -0000
*************** Use the expression @code{assemble_name (
*** 6667,6676 ****
--- 6667,6683 ----
  output the name itself; before and after that, output the additional
  assembler syntax for defining the name, and a newline.  A default
  definition of this macro is provided which is correct for most systems.
  @end defmac
  
+ @findex assemble_name_raw
+ @defmac ASM_OUTPUT_INTERNAL_LABEL (@var{stream}, @var{name})
+ Identical to @code{ASM_OUTPUT_lABEL}, except that @var{name} is known
+ to refer to a compiler-generated label.  The default definition uses
+ @code{assemble_name_raw}, which is like @code{assemble_name} except
+ that it is more efficient.
+ 
  @defmac SIZE_ASM_OP
  A C string containing the appropriate assembler directive to specify the
  size of a symbol, without any arguments.  On systems that use ELF, the
  default (in @file{config/elfos.h}) is @samp{"\t.size\t"}; on other
  systems, the default is not to define this macro.



More information about the Gcc-patches mailing list