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]

[PATCH] Don't output unused string constants


Hi!

gcc outputs all string constants which make it into the rtl level no matter
whether they are ever referenced in the resulting code or not.
Simplest example is e.g.:

char *foo(void) { if (0) return "a"; return "b"; }

For some projects, especially containing a lot of dead code, this can make a
big difference. Additionally, when unused string constants are output, it
makes a difference for the programmer whether to use
#ifdef FOO
	somecode
#endif
or
	if (FOO) {
		somecode
	}
where FOO is compile-time constant (plus it makes a difference for inline
functions, code using builtin_constant_p and other stuff).

This patch defers outputing string constants (unless they are requested to
be output immediately, such as in char *a[] = { "a", "b" }; ) until
mark_constant_pool time at which time it together with marking used
constants scans for used string constants and outputs them.

Bootstrapped on i386-*-linux, no regressions (I had to tweak one test so
that it still fails, because unused string was used there to clobber .rodata
section after another string).

Ok to commit?

2000-11-06  Jakub Jelinek  <jakub@redhat.com>

	* varasm.c (struct deferred_string): New structure.
	(const_str_table, const_str_count): New variables.
	(STRHASH): New macro.
	(mark_const_str_entry): New function.
	(output_constant_def): Add DEFER argument, defer string
	constants until mark_constant_pool time if requested.
	(mark_constant_pool): Walk the insn chain even if const_str_count is
	non-zero.
	(mark_constants): If a SYMBOL_REF for deferred string is found,
	output it and remove from hash table.
	(output_addressed_constants): Set DEFER to 0 in call to
	output_constant_def.
	* rtl.h (STRING_POOL_ADDRESS_P): Define.
	(output_constant_def): Adjust prototype.
	* expr.c (expand_expr): Set DEFER to 1 in call to output_constant_def.

	* gcc.c-torture/execute/20000801-4.c: Make sure the second string is
	output.

--- gcc/varasm.c.jj	Mon Nov  6 13:51:51 2000
+++ gcc/varasm.c	Mon Nov  6 17:28:35 2000
@@ -185,6 +185,7 @@ static void asm_output_aligned_bss	PARAM
 #endif /* BSS_SECTION_ASM_OP */
 static void mark_pool_constant          PARAMS ((struct pool_constant *));
 static void mark_const_hash_entry	PARAMS ((void *));
+static void mark_const_str_entry	PARAMS ((void *));
 static void asm_emit_uninitialised	PARAMS ((tree, const char*, int, int));
 
 static enum in_section { no_section, in_text, in_data, in_named
@@ -2333,6 +2334,26 @@ struct constant_descriptor
 #define MAX_HASH_TABLE 1009
 static struct constant_descriptor *const_hash_table[MAX_HASH_TABLE];
 
+#define MAX_STR_HASH_TABLE 251
+struct deferred_string
+{
+  struct deferred_string *next;
+  char *label;
+  tree exp;
+  int labelno;
+};
+
+#define MAX_STR_HASH_TABLE 251
+static struct deferred_string *const_str_table[MAX_STR_HASH_TABLE];
+
+static int const_str_count;
+
+/* Hash code for a SYMBOL_REF with STRING_POOL_ADDRESS_P true.
+   The argument is XSTR (... , 0)  */
+
+#define STRHASH(LABEL) \
+  ((((unsigned long) (LABEL)) & ((1 << HASHBITS) - 1)) % MAX_STR_HASH_TABLE)
+
 /* Mark a const_hash_table descriptor for GC.  */
 
 static void 
@@ -2349,6 +2370,21 @@ mark_const_hash_entry (ptr)
     }
 }
 
+/* Mark a const_str_table descriptor for GC.  */
+
+static void 
+mark_const_str_entry (ptr)
+     void *ptr;
+{
+  struct deferred_string *desc = * (struct deferred_string **) ptr;
+
+  while (desc)
+    {
+      ggc_mark_tree (desc->exp);
+      desc = desc->next;
+    }
+}
+
 /* Compute a hash code for a constant expression.  */
 
 static int
@@ -3047,18 +3083,25 @@ copy_constant (exp)
    Otherwise, output such a constant in memory (or defer it for later)
    and generate an rtx for it.
 
+   If DEFER is non-zero, the output of string constants can be deferred
+   and output only if referenced in the function after all optimizations.
+
    The TREE_CST_RTL of EXP is set up to point to that rtx.
    The const_hash_table records which constants already have label strings.  */
 
 rtx
-output_constant_def (exp)
+output_constant_def (exp, defer)
      tree exp;
+     int defer;
 {
   register int hash;
   register struct constant_descriptor *desc;
+  struct deferred_string **defstr;
   char label[256];
   int reloc;
   int found = 1;
+  int after_function = 0;
+  int labelno = -1;
 
   if (TREE_CST_RTL (exp))
     return TREE_CST_RTL (exp);
@@ -3086,7 +3129,8 @@ output_constant_def (exp)
 	 future calls to this function to find.  */
 	  
       /* Create a string containing the label name, in LABEL.  */
-      ASM_GENERATE_INTERNAL_LABEL (label, "LC", const_labelno);
+      labelno = const_labelno++;
+      ASM_GENERATE_INTERNAL_LABEL (label, "LC", labelno);
 
       desc = record_constant (exp);
       desc->next = const_hash_table[hash];
@@ -3112,18 +3156,36 @@ output_constant_def (exp)
   ENCODE_SECTION_INFO (exp);
 #endif
 
+#ifdef CONSTANT_AFTER_FUNCTION_P
+  if (current_function_decl != 0
+      && CONSTANT_AFTER_FUNCTION_P (exp))
+    after_function = 1;
+#endif
+
+  if (found
+      && STRING_POOL_ADDRESS_P (XEXP (desc->rtl, 0))
+      && (!defer || defer_addressed_constants_flag || after_function))
+    for (defstr = &const_str_table[STRHASH (desc->label)];
+         *defstr; defstr = &(*defstr)->next)
+      if ((*defstr)->label == desc->label)
+	{
+	  struct deferred_string *p = *defstr;
+
+	  /* If the string is currently deferred but we need to output it now,
+	     remove it from deferred string hash table.  */
+	  found = 0;
+	  labelno = p->labelno;
+	  *defstr = p->next;
+	  STRING_POOL_ADDRESS_P (XEXP (desc->rtl, 0)) = 0;
+	  free (p);
+	  const_str_count--;
+	  break;
+	}
+
   /* If this is the first time we've seen this particular constant,
      output it (or defer its output for later).  */
   if (! found)
     {
-      int after_function = 0;
-
-#ifdef CONSTANT_AFTER_FUNCTION_P
-      if (current_function_decl != 0
-	  && CONSTANT_AFTER_FUNCTION_P (exp))
-	after_function = 1;
-#endif
-
       if (defer_addressed_constants_flag || after_function)
 	{
 	  struct deferred_constant *p;
@@ -3131,7 +3193,7 @@ output_constant_def (exp)
 
 	  p->exp = copy_constant (exp);
 	  p->reloc = reloc;
-	  p->labelno = const_labelno++;
+	  p->labelno = labelno;
 	  if (after_function)
 	    {
 	      p->next = after_function_constants;
@@ -3147,8 +3209,29 @@ output_constant_def (exp)
 	{
 	  /* Do no output if -fsyntax-only.  */
 	  if (! flag_syntax_only)
-	    output_constant_def_contents (exp, reloc, const_labelno);
-	  ++const_labelno;
+	    {
+	      if (TREE_CODE (exp) != STRING_CST
+		  || !defer
+		  || flag_writable_strings)
+		output_constant_def_contents (exp, reloc, labelno);
+	      else
+		{
+		  struct deferred_string *p;
+		  unsigned long strhash;
+
+		  p = (struct deferred_string *)
+		      xmalloc (sizeof (struct deferred_string));
+
+		  p->exp = copy_constant (exp);
+		  p->label = desc->label;
+		  p->labelno = labelno;
+		  strhash = STRHASH (desc->label);
+		  p->next = const_str_table[strhash];
+		  const_str_table[strhash] = p;
+		  STRING_POOL_ADDRESS_P (XEXP (desc->rtl, 0)) = 1;
+		  const_str_count++;
+		}
+	    }
 	}
     }
 
@@ -3798,7 +3881,7 @@ mark_constant_pool ()
   register rtx insn;
   struct pool_constant *pool;
 
-  if (first_pool == 0)
+  if (first_pool == 0 && const_str_count == 0)
     return;
 
   for (pool = first_pool; pool; pool = pool->next)
@@ -3859,6 +3942,24 @@ mark_constants (x)
     {
       if (CONSTANT_POOL_ADDRESS_P (x))
 	find_pool_constant (cfun, x)->mark = 1;
+      else if (STRING_POOL_ADDRESS_P (x))
+	{
+	  struct deferred_string **defstr;
+
+	  for (defstr = &const_str_table[STRHASH (XSTR (x, 0))];
+	       *defstr; defstr = &(*defstr)->next)
+	    if ((*defstr)->label == XSTR (x, 0))
+	      {
+		struct deferred_string *p = *defstr;
+
+		*defstr = p->next;
+		STRING_POOL_ADDRESS_P (x) = 0;
+		output_constant_def_contents (p->exp, 0, p->labelno);
+		free (p);
+		const_str_count--;
+		break;
+	      }
+	}
       return;
     }
   /* Never search inside a CONST_DOUBLE, because CONST_DOUBLE_MEM may be
@@ -3935,7 +4036,7 @@ output_addressed_constants (exp)
 	    || TREE_CODE (constant) == CONSTRUCTOR)
 	  /* No need to do anything here
 	     for addresses of variables or functions.  */
-	  output_constant_def (constant);
+	  output_constant_def (constant, 0);
       }
       reloc = 1;
       break;
@@ -4751,6 +4852,8 @@ init_varasm_once ()
 {
   ggc_add_root (const_hash_table, MAX_HASH_TABLE, sizeof const_hash_table[0],
 		mark_const_hash_entry);
+  ggc_add_root (const_str_table, MAX_STR_HASH_TABLE, sizeof const_str_table[0],
+		mark_const_str_entry);
   ggc_add_string_root (&in_named_name, 1);
 }
 
--- gcc/rtl.h.jj	Mon Oct 16 21:51:12 2000
+++ gcc/rtl.h	Mon Nov  6 14:47:12 2000
@@ -168,7 +168,9 @@ typedef struct rtx_def
      either changing how we compute the frame address or saving and
      restoring registers in the prologue and epilogue.
      1 in a MEM if the MEM refers to a scalar, rather than a member of
-     an aggregate.  */
+     an aggregate.
+     1 in a SYMBOL_REF if it addresses something in the per-function
+     constant string pool.  */
   unsigned frame_related : 1;
 
   /* The first element of the operands of this rtx.
@@ -904,6 +906,9 @@ extern const char * const note_insn_name
 /* 1 in a SYMBOL_REF if it addresses this function's constants pool.  */
 #define CONSTANT_POOL_ADDRESS_P(RTX) ((RTX)->unchanging)
 
+/* 1 in a SYMBOL_REF if it addresses this function's string constant pool.  */
+#define STRING_POOL_ADDRESS_P(RTX) ((RTX)->frame_related)
+
 /* Flag in a SYMBOL_REF for machine-specific purposes.  */
 #define SYMBOL_REF_FLAG(RTX) ((RTX)->volatil)
 
@@ -1587,7 +1592,7 @@ extern rtx gen_rtx_MEM PARAMS ((enum mac
 extern rtx find_next_ref		PARAMS ((rtx, rtx));
 extern rtx *find_single_use		PARAMS ((rtx, rtx, rtx *));
 
-extern rtx output_constant_def		PARAMS ((union tree_node *));
+extern rtx output_constant_def		PARAMS ((union tree_node *, int));
 extern rtx immed_real_const		PARAMS ((union tree_node *));
 extern union tree_node *make_tree	PARAMS ((union tree_node *, rtx));
 
--- gcc/expr.c.jj	Tue Oct 31 12:25:06 2000
+++ gcc/expr.c	Mon Nov  6 14:43:46 2000
@@ -6143,7 +6143,7 @@ expand_expr (exp, target, tmode, modifie
     case COMPLEX_CST:
     case STRING_CST:
       if (! TREE_CST_RTL (exp))
-	output_constant_def (exp);
+	output_constant_def (exp, 1);
 
       /* TREE_CST_RTL probably contains a constant address.
 	 On RISC machines where a constant address isn't valid,
@@ -6456,7 +6456,7 @@ expand_expr (exp, target, tmode, modifie
 			&& ! mostly_zeros_p (exp))))
 	       || (modifier == EXPAND_INITIALIZER && TREE_CONSTANT (exp)))
 	{
-	  rtx constructor = output_constant_def (exp);
+	  rtx constructor = output_constant_def (exp, 1);
 
 	  if (modifier != EXPAND_CONST_ADDRESS
 	      && modifier != EXPAND_INITIALIZER
--- gcc/testsuite/gcc.c-torture/execute/20000801-4.c.jj	Thu Aug  3 09:36:13 2000
+++ gcc/testsuite/gcc.c-torture/execute/20000801-4.c	Mon Nov  6 17:20:23 2000
@@ -14,11 +14,14 @@ foo (void)
   return 0 == s[1];
 }
 
+char *t;
+
 int
 main (void)
 {
   {
     char s[] = "x";
+    t = s;
   }
   if (foo ())
     exit (0);

	Jakub

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