small varasm.c improvements

Zack Weinberg zack@codesourcery.com
Mon May 5 21:54:00 GMT 2003


This patch accomplishes a handful of improvements to varasm.c.  Most
significant is that output_constant_def will now defer anything, not
just a string constant.  That means that, for instance, complex
numbers which appear in dead code no longer get emitted to .rodata
anyway.

This doesn't come up much in C - floating-point constants (complex or
real) show the difference but that was the only way that I found.
(The structures were an attempt to get a CONSTRUCTOR handed to o_c_d,
but it didn't work; those use a different code path and were already
being elided.  Anyone who knows how to test this more thoroughly,
please feel free to improve the test cases.)  It might be a bigger win
for other languages, or for architectures where not all integers can
be immediate.

Also, the 'n_deferred_constants' count is now per-function, which
means that output_constant_pool can reliably tell whether there are
any deferred constants, hashtab.c is used instead of an open-coded
hash table, and I got rid of the redundant 'label' field in struct
constant_descriptor_tree -- its size is cut in half.

All these changes together produce an 0.25% speedup in bootstrap time
and an 0.06% slowdown in time to run the testsuite.  These may just be
noise.  There were no regressions on i686-linux.

zw

        * rtl.h (STRING_POOL_ADDRESS_P): Rename to DEFERRED_CONSTANT_P.
        * varasm.c (struct varasm_status): Add deferred_constants field.
        (n_deferred_strings): Delete variable.
        (n_deferred_constants): New #define.
        (struct constant_descriptor_tree): Kill next and label fields.
        (const_hash_table, MAX_HASH_TABLE): Delete.
        (const_desc_htab): New static variable.
        (const_hash): Rename const_desc_hash, and make it fit the
        hashtab.h interface.
        (const_desc_eq): New.
        (const_hash_1, compare_constant): Const-ify arguments.
        (build_constant_desc): Set DEFERRED_CONSTANT_P on all new
        SYMBOL_REFs.  Clarify comments.  Don't set desc->label.
        (output_constant_def): Do the lookup/insert using the
        hashtab.h interface.  Don't muck with n_deferred_constants or
        DEFERRED_CONSTANT_P here.
        Always call maybe_output_constant_def_contents.
        (maybe_output_constant_def_contents): Take a pointer to the
        descriptor, not the EXP and RTL separately.  Return
        immediately if this constant is not deferred.  Defer output of
        everything, except writable string constants.  Update
        n_deferred_constants here.
        (output_constant_def_contents): Now takes just one argument,
        an rtx.  Clear DEFERRED_CONSTANT_P here.
        (mark_constant_pool): Update for rename of n_deferred_strings.
        (mark_constant): Don't clear DEFERRED_CONSTANT_P here.

        (init_varasm_status): Clear p->deferred_constants.
        (init_varasm_once): Call htab_create_ggc for const_desc_htab.

        * gcc.dg/const-elim-1.c, gcc.dg/const-elim-2.c: New testcases.

===================================================================
Index: rtl.h
--- rtl.h	3 May 2003 14:25:20 -0000	1.402
+++ rtl.h	5 May 2003 21:23:00 -0000
@@ -1234,10 +1234,11 @@ do {						\
 #define CONSTANT_POOL_ADDRESS_P(RTX)					\
   (RTL_FLAG_CHECK1("CONSTANT_POOL_ADDRESS_P", (RTX), SYMBOL_REF)->unchanging)
 
-/* 1 if RTX is a symbol_ref that addresses this function's string constant
-   pool  */
-#define STRING_POOL_ADDRESS_P(RTX)					\
-  (RTL_FLAG_CHECK1("STRING_POOL_ADDRESS_P", (RTX), SYMBOL_REF)->frame_related)
+/* 1 if RTX is a symbol_ref that addresses a value in the file's constant
+   pool which has not yet been output.  This information is private to
+   varasm.c.  */
+#define DEFERRED_CONSTANT_P(RTX)					\
+  (RTL_FLAG_CHECK1("DEFERRED_CONSTANT_P", (RTX), SYMBOL_REF)->frame_related)
 
 /* Used if RTX is a symbol_ref, for machine-specific purposes.  */
 #define SYMBOL_REF_FLAG(RTX)						\
===================================================================
Index: varasm.c
--- varasm.c	4 May 2003 14:27:17 -0000	1.348
+++ varasm.c	5 May 2003 21:23:01 -0000
@@ -96,6 +96,10 @@ struct varasm_status GTY(())
   /* Current offset in constant pool (does not include any machine-specific
      header).  */
   HOST_WIDE_INT x_pool_offset;
+
+  /* Number of tree-constants deferred during the expansion of this
+     function.  */
+  unsigned int deferred_constants;
 };
 
 #define const_rtx_hash_table (cfun->varasm->x_const_rtx_hash_table)
@@ -103,6 +107,7 @@ struct varasm_status GTY(())
 #define first_pool (cfun->varasm->x_first_pool)
 #define last_pool (cfun->varasm->x_last_pool)
 #define pool_offset (cfun->varasm->x_pool_offset)
+#define n_deferred_constants (cfun->varasm->deferred_constants)
 
 /* Number for making the label on the next
    constant that is stored in memory.  */
@@ -138,12 +143,12 @@ static HOST_WIDE_INT const_alias_set;
 static const char *strip_reg_name	PARAMS ((const char *));
 static int contains_pointers_p		PARAMS ((tree));
 static void decode_addr_const		PARAMS ((tree, struct addr_const *));
-static unsigned int const_hash		PARAMS ((tree));
-static unsigned int const_hash_1	PARAMS ((tree));
-static int compare_constant		PARAMS ((tree, tree));
+static hashval_t const_desc_hash	PARAMS ((const void *));
+static int const_desc_eq		PARAMS ((const void *, const void *));
+static hashval_t const_hash_1		PARAMS ((const tree));
+static int compare_constant		PARAMS ((const tree, const tree));
 static tree copy_constant		PARAMS ((tree));
-static void maybe_output_constant_def_contents PARAMS ((tree, rtx, int));
-static void output_constant_def_contents  PARAMS ((tree, const char *));
+static void output_constant_def_contents  PARAMS ((rtx));
 static void decode_rtx_const		PARAMS ((enum machine_mode, rtx,
 					       struct rtx_const *));
 static unsigned int const_hash_rtx	PARAMS ((enum machine_mode, rtx));
@@ -2143,12 +2148,6 @@ struct rtx_const GTY(())
 
 struct constant_descriptor_tree GTY(())
 {
-  /* More constant_descriptors with the same hash code.  */
-  struct constant_descriptor_tree *next;
-
-  /* The label of the constant.  */
-  const char *label;
-
   /* A MEM for the constant.  */
   rtx rtl;
 
@@ -2156,28 +2155,28 @@ struct constant_descriptor_tree GTY(())
   tree value;
 };
 
-#define MAX_HASH_TABLE 1009
-static GTY(()) struct constant_descriptor_tree *
-  const_hash_table[MAX_HASH_TABLE];
+static GTY((param_is (struct constant_descriptor_tree)))
+     htab_t const_desc_htab;
 
 static struct constant_descriptor_tree * build_constant_desc PARAMS ((tree));
-static unsigned int n_deferred_strings = 0;
+static void maybe_output_constant_def_contents
+    PARAMS ((struct constant_descriptor_tree *, int));
 
 /* Compute a hash code for a constant expression.  */
 
-static unsigned int
-const_hash (exp)
-     tree exp;
+static hashval_t
+const_desc_hash (ptr)
+     const void *ptr;
 {
-  return const_hash_1 (exp) % MAX_HASH_TABLE;
+  return const_hash_1 (((struct constant_descriptor_tree *)ptr)->value);
 }
 
-static unsigned int
+static hashval_t
 const_hash_1 (exp)
-     tree exp;
+     const tree exp;
 {
   const char *p;
-  unsigned int hi;
+  hashval_t hi;
   int len, i;
   enum tree_code code = TREE_CODE (exp);
 
@@ -2198,7 +2197,6 @@ const_hash_1 (exp)
       p = TREE_STRING_POINTER (exp);
       len = TREE_STRING_LENGTH (exp);
       break;
-
     case COMPLEX_CST:
       return (const_hash_1 (TREE_REALPART (exp)) * 5
 	      + const_hash_1 (TREE_IMAGPART (exp)));
@@ -2272,13 +2270,23 @@ const_hash_1 (exp)
   return hi;
 }
 
+/* Wrapper of compare_constant, for the htab interface.  */
+static int
+const_desc_eq (p1, p2)
+     const void *p1;
+     const void *p2;
+{
+  return compare_constant (((struct constant_descriptor_tree *)p1)->value,
+			   ((struct constant_descriptor_tree *)p2)->value);
+}
+
 /* Compare t1 and t2, and return 1 only if they are known to result in
    the same bit pattern on output.  */
 
 static int
 compare_constant (t1, t2)
-     tree t1;
-     tree t2;
+     const tree t1;
+     const tree t2;
 {
   enum tree_code typecode;
 
@@ -2531,11 +2539,18 @@ build_constant_desc (exp)
   /* Set flags or add text to the name to record information, such as
      that it is a local symbol.  If the name is changed, the macro
      ASM_OUTPUT_LABELREF will have to know how to strip this
-     information.  */
+     information.  This call might invalidate our local variable
+     SYMBOL; we can't use it afterward.  */
+
   (*targetm.encode_section_info) (exp, rtl, true);
 
+  /* Descriptors start out deferred; this simplifies the logic in
+     maybe_output_constant_def_contents.  However, we do not bump
+     n_deferred_constants here, because we don't know if we're inside
+     a function and have an n_deferred_constants to bump.  */
+  DEFERRED_CONSTANT_P (XEXP (rtl, 0)) = 1;
+
   desc->rtl = rtl;
-  desc->label = XSTR (XEXP (desc->rtl, 0), 0);
 
   return desc;
 }
@@ -2548,8 +2563,8 @@ build_constant_desc (exp)
    Otherwise, output such a constant in memory
    and generate an rtx for it.
 
-   If DEFER is nonzero, the output of string constants can be deferred
-   and output only if referenced in the function after all optimizations.
+   If DEFER is nonzero, this constant can be deferred and output only
+   if referenced in the function after all optimizations.
 
    The const_hash_table records which constants already have label strings.  */
 
@@ -2558,70 +2573,64 @@ output_constant_def (exp, defer)
      tree exp;
      int defer;
 {
-  int hash;
   struct constant_descriptor_tree *desc;
+  struct constant_descriptor_tree key;
+  void **loc;
 
-  /* Compute hash code of EXP.  Search the descriptors for that hash code
-     to see if any of them describes EXP.  If yes, the descriptor records
-     the label number already assigned.  */
-
-  hash = const_hash (exp);
-  for (desc = const_hash_table[hash]; desc; desc = desc->next)
-    if (compare_constant (exp, desc->value))
-      break;
+  /* Look up EXP in the table of constant descriptors.  If we didn't find
+     it, create a new one.  */
+  key.value = exp;
+  loc = htab_find_slot (const_desc_htab, &key, INSERT);
 
+  desc = *loc;
   if (desc == 0)
     {
       desc = build_constant_desc (exp);
-      desc->next = const_hash_table[hash];
-      const_hash_table[hash] = desc;
-
-      maybe_output_constant_def_contents (exp, desc->rtl, defer);
-    }
-  else if (!defer && STRING_POOL_ADDRESS_P (XEXP (desc->rtl, 0)))
-    {
-      /* This string is currently deferred but we need to output it
-	 now; mark it no longer deferred.  */
-      STRING_POOL_ADDRESS_P (XEXP (desc->rtl, 0)) = 0;
-      n_deferred_strings--;
-      maybe_output_constant_def_contents (exp, desc->rtl, 0);
+      *loc = desc;
     }
 
+  maybe_output_constant_def_contents (desc, defer);
   return desc->rtl;
 }
 
-/* Subroutine of output_constant_def:
-   Decide whether or not to defer the output of EXP, which can be
-   accesed through rtl RTL, and either do the output or record EXP in
-   the table of deferred strings.  */
+/* Subroutine of output_constant_def: Decide whether or not we need to
+   output the constant DESC now, and if so, do it.  */
 static void
-maybe_output_constant_def_contents (exp, rtl, defer)
-     tree exp;
-     rtx rtl;
+maybe_output_constant_def_contents (desc, defer)
+     struct constant_descriptor_tree *desc;
      int defer;
 {
+  rtx symbol = XEXP (desc->rtl, 0);
+
   if (flag_syntax_only)
     return;
 
-  /* Is this a string constant that can be deferred?  */
-  if (defer && TREE_CODE (exp) == STRING_CST && !flag_writable_strings)
+  if (!DEFERRED_CONSTANT_P (symbol))
+    /* Already output; don't do it again.  */
+    return;
+
+  /* The only constants that cannot safely be deferred, assuming the
+     context allows it, are strings under flag_writable_strings.  */
+  if (defer && (TREE_CODE (desc->value) != STRING_CST
+		|| !flag_writable_strings))
     {
-      STRING_POOL_ADDRESS_P (XEXP (rtl, 0)) = 1;
-      n_deferred_strings++;
+      if (cfun)
+	n_deferred_constants++;
       return;
     }
 
-  output_constant_def_contents (exp, XSTR (XEXP (rtl, 0), 0));
+  output_constant_def_contents (symbol);
 }
 
-/* Now output assembler code to define the label for EXP,
-   and follow it with the data of EXP.  */
+/* We must output the constant data referred to by SYMBOL; do so.  */
 
 static void
-output_constant_def_contents (exp, label)
-     tree exp;
-     const char *label;
+output_constant_def_contents (symbol)
+     rtx symbol;
 {
+  tree exp = SYMBOL_REF_DECL (symbol);
+  const char *label = XSTR (symbol, 0);
+
   /* Make sure any other constants whose addresses appear in EXP
      are assigned label numbers.  */
   int reloc = output_addressed_constants (exp);
@@ -2632,6 +2641,9 @@ output_constant_def_contents (exp, label
   align = CONSTANT_ALIGNMENT (exp, align);
 #endif
 
+  /* We are no longer deferring this constant.  */
+  DEFERRED_CONSTANT_P (symbol) = 0;
+
   if (IN_NAMED_SECTION (exp))
     named_section (exp, NULL, reloc);
   else
@@ -2715,6 +2727,7 @@ init_varasm_status (f)
 
   p->x_first_pool = p->x_last_pool = 0;
   p->x_pool_offset = 0;
+  p->deferred_constants = 0;
 }
 
 
@@ -3329,8 +3342,8 @@ output_constant_pool (fnname, fndecl)
 }
 
 /* Look through the instructions for this function, and mark all the
-   entries in the constant pool which are actually being used.
-   Emit used deferred strings.  */
+   entries in the constant pool which are actually being used.  Emit
+   deferred constants which have indeed been used.  */
 
 static void
 mark_constant_pool ()
@@ -3339,7 +3352,7 @@ mark_constant_pool ()
   rtx link;
   struct pool_constant *pool;
 
-  if (first_pool == 0 && n_deferred_strings == 0)
+  if (first_pool == 0 && n_deferred_constants == 0)
     return;
 
   for (pool = first_pool; pool; pool = pool->next)
@@ -3453,11 +3466,10 @@ mark_constant (current_rtx, data)
 	  else
 	    return -1;
 	}
-      else if (STRING_POOL_ADDRESS_P (x))
+      else if (DEFERRED_CONSTANT_P (x))
 	{
-	  STRING_POOL_ADDRESS_P (x) = 0;
-	  n_deferred_strings--;
-	  output_constant_def_contents (SYMBOL_REF_DECL (x), XSTR (x, 0));
+	  n_deferred_constants--;
+	  output_constant_def_contents (x);
 	}
     }
   return 0;
@@ -4544,6 +4556,8 @@ init_varasm_once ()
 {
   in_named_htab = htab_create_ggc (31, in_named_entry_hash,
 				   in_named_entry_eq, NULL);
+  const_desc_htab = htab_create_ggc (1009, const_desc_hash,
+				     const_desc_eq, NULL);
 
   const_alias_set = new_alias_set ();
 }
===================================================================
Index: testsuite/gcc.dg/const-elim-1.c
--- testsuite/gcc.dg/const-elim-1.c	1 Jan 1970 00:00:00 -0000
+++ testsuite/gcc.dg/const-elim-1.c	5 May 2003 21:23:04 -0000
@@ -0,0 +1,48 @@
+/* Verify that constants in memory, referenced only by dead code,
+   are not emitted to the object file.
+   FIXME: Not presently possible to apply -pedantic to code with
+   complex constants in it.  The __extension__ should shut up the
+   warning but doesn't.  (Hard to fix -- the lexer is not aware of
+   the parser's state.)  */
+
+/* { dg-do compile } */
+/* { dg-options "-O2 -std=c99" } */
+/* { dg-final { scan-assembler-not "LC" } } */
+
+#define I (__extension__ 1.0iF)
+
+struct S { int a; double b[2]; void *c; };
+
+extern void use_str(const char *);
+extern void use_S(const struct S *);
+extern void use_cplx(__complex__ double);
+
+static inline int
+returns_23(void) { return 23; }
+
+void
+test1(void)
+{
+	if (returns_23() == 23)
+		return;
+
+	use_str("waltz, nymph, for quick jigs vex bud");
+	use_S(&(const struct S){12, {3.1415, 2.1828}, 0 });
+	use_cplx(3.1415 + 2.1828*I);
+}
+
+void
+test2(void)
+{
+	const char *str = "pack my box with five dozen liquor jugs";
+	const struct S S = { 23, { 1.414, 1.618 }, 0 };
+	const __complex__ double cplx = 1.414 + 1.618*I;
+
+	if (returns_23() == 23)
+		return;
+
+	use_str(str);
+	use_S(&S);
+	use_cplx(cplx);
+}
+
===================================================================
Index: testsuite/gcc.dg/const-elim-2.c
--- testsuite/gcc.dg/const-elim-2.c	1 Jan 1970 00:00:00 -0000
+++ testsuite/gcc.dg/const-elim-2.c	5 May 2003 21:23:04 -0000
@@ -0,0 +1,10 @@
+/* The string constant in this test case should be emitted exactly once.  */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler-times "hi there" 1 } } */
+
+static inline int returns_23() { return 23; }
+
+const char *test1(void) { if (returns_23()) return 0; return "hi there"; }
+const char *test2(void) { return "hi there"; }
+const char *test3(void) { return "hi there"; }



More information about the Gcc-patches mailing list