This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Don't output unused string constants
- To: gcc-patches at gcc dot gnu dot org
- Subject: [PATCH] Don't output unused string constants
- From: Jakub Jelinek <jakub at redhat dot com>
- Date: Mon, 6 Nov 2000 17:52:50 +0100
- Reply-To: Jakub Jelinek <jakub at redhat dot com>
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