#include <ctype.h>
+#ifndef TRAMPOLINE_ALIGNMENT
+#define TRAMPOLINE_ALIGNMENT FUNCTION_BOUNDARY
+#endif
+
#ifndef ASM_STABS_OP
#define ASM_STABS_OP ".stabs"
#endif
static struct constant_descriptor *record_constant_rtx PROTO((enum machine_mode,
rtx));
static struct pool_constant *find_pool_constant PROTO((rtx));
+static void mark_constant_pool PROTO((void));
+static void mark_constants PROTO((rtx));
static int output_addressed_constants PROTO((tree));
static void output_after_function_constants PROTO((void));
static void bc_assemble_integer PROTO((tree, int));
#endif
/* Write the assembler code to define one. */
- align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
+ align = floor_log2 (TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT);
if (align > 0)
ASM_OUTPUT_ALIGN (asm_out_file, align);
register int len, hi, i;
register enum tree_code code = TREE_CODE (exp);
- if (code == INTEGER_CST)
+ /* Either set P and LEN to the address and len of something to hash and
+ exit the switch or return a value. */
+
+ switch (code)
{
+ case INTEGER_CST:
p = (char *) &TREE_INT_CST_LOW (exp);
len = 2 * sizeof TREE_INT_CST_LOW (exp);
- }
- else if (code == REAL_CST)
- {
+ break;
+
+ case REAL_CST:
p = (char *) &TREE_REAL_CST (exp);
len = sizeof TREE_REAL_CST (exp);
- }
- else if (code == STRING_CST)
- p = TREE_STRING_POINTER (exp), len = TREE_STRING_LENGTH (exp);
- else if (code == COMPLEX_CST)
- return const_hash (TREE_REALPART (exp)) * 5
- + const_hash (TREE_IMAGPART (exp));
- else if (code == CONSTRUCTOR && TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
- {
- len = int_size_in_bytes (TREE_TYPE (exp));
- p = (char *) alloca (len);
- get_set_constructor_bytes (exp, (unsigned char *) p, len);
- }
- else if (code == CONSTRUCTOR)
- {
- register tree link;
-
- /* For record type, include the type in the hashing.
- We do not do so for array types
- because (1) the sizes of the elements are sufficient
- and (2) distinct array types can have the same constructor.
- Instead, we include the array size because the constructor could
- be shorter. */
- if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE)
- hi = ((HOST_WIDE_INT) TREE_TYPE (exp) & ((1 << HASHBITS) - 1))
- % MAX_HASH_TABLE;
- else
- hi = ((5 + int_size_in_bytes (TREE_TYPE (exp)))
- & ((1 << HASHBITS) - 1)) % MAX_HASH_TABLE;
+ break;
- for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
- if (TREE_VALUE (link))
- hi = (hi * 603 + const_hash (TREE_VALUE (link))) % MAX_HASH_TABLE;
+ case STRING_CST:
+ p = TREE_STRING_POINTER (exp);
+ len = TREE_STRING_LENGTH (exp);
+ break;
- return hi;
- }
- else if (code == ADDR_EXPR)
- {
- struct addr_const value;
- decode_addr_const (exp, &value);
- if (GET_CODE (value.base) == SYMBOL_REF)
+ case COMPLEX_CST:
+ return (const_hash (TREE_REALPART (exp)) * 5
+ + const_hash (TREE_IMAGPART (exp)));
+
+ case CONSTRUCTOR:
+ if (TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
{
- /* Don't hash the address of the SYMBOL_REF;
- only use the offset and the symbol name. */
- hi = value.offset;
- p = XSTR (value.base, 0);
- for (i = 0; p[i] != 0; i++)
- hi = ((hi * 613) + (unsigned) (p[i]));
+ len = int_size_in_bytes (TREE_TYPE (exp));
+ p = (char *) alloca (len);
+ get_set_constructor_bytes (exp, (unsigned char *) p, len);
+ break;
}
- else if (GET_CODE (value.base) == LABEL_REF)
- hi = value.offset + CODE_LABEL_NUMBER (XEXP (value.base, 0)) * 13;
+ else
+ {
+ register tree link;
- hi &= (1 << HASHBITS) - 1;
- hi %= MAX_HASH_TABLE;
+ /* For record type, include the type in the hashing.
+ We do not do so for array types
+ because (1) the sizes of the elements are sufficient
+ and (2) distinct array types can have the same constructor.
+ Instead, we include the array size because the constructor could
+ be shorter. */
+ if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE)
+ hi = ((HOST_WIDE_INT) TREE_TYPE (exp) & ((1 << HASHBITS) - 1))
+ % MAX_HASH_TABLE;
+ else
+ hi = ((5 + int_size_in_bytes (TREE_TYPE (exp)))
+ & ((1 << HASHBITS) - 1)) % MAX_HASH_TABLE;
+
+ for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
+ if (TREE_VALUE (link))
+ hi
+ = (hi * 603 + const_hash (TREE_VALUE (link))) % MAX_HASH_TABLE;
+
+ return hi;
+ }
+
+ case ADDR_EXPR:
+ {
+ struct addr_const value;
+
+ decode_addr_const (exp, &value);
+ if (GET_CODE (value.base) == SYMBOL_REF)
+ {
+ /* Don't hash the address of the SYMBOL_REF;
+ only use the offset and the symbol name. */
+ hi = value.offset;
+ p = XSTR (value.base, 0);
+ for (i = 0; p[i] != 0; i++)
+ hi = ((hi * 613) + (unsigned) (p[i]));
+ }
+ else if (GET_CODE (value.base) == LABEL_REF)
+ hi = value.offset + CODE_LABEL_NUMBER (XEXP (value.base, 0)) * 13;
+
+ hi &= (1 << HASHBITS) - 1;
+ hi %= MAX_HASH_TABLE;
+ }
return hi;
+
+ case PLUS_EXPR:
+ case MINUS_EXPR:
+ return (const_hash (TREE_OPERAND (exp, 0)) * 9
+ + const_hash (TREE_OPERAND (exp, 1)));
+
+ case NOP_EXPR:
+ case CONVERT_EXPR:
+ case NON_LVALUE_EXPR:
+ return const_hash (TREE_OPERAND (exp, 0)) * 7 + 2;
}
- else if (code == PLUS_EXPR || code == MINUS_EXPR)
- return const_hash (TREE_OPERAND (exp, 0)) * 9
- + const_hash (TREE_OPERAND (exp, 1));
- else if (code == NOP_EXPR || code == CONVERT_EXPR)
- return const_hash (TREE_OPERAND (exp, 0)) * 7 + 2;
/* Compute hashing function */
hi = len;
if (code != (enum tree_code) *p++)
return 0;
- if (code == INTEGER_CST)
+ /* Either set STRP, P and LEN to pointers and length to compare and exit the
+ switch, or return the result of the comparison. */
+
+ switch (code)
{
+ case INTEGER_CST:
/* Integer constants are the same only if the same width of type. */
if (*p++ != TYPE_PRECISION (TREE_TYPE (exp)))
return 0;
+
strp = (char *) &TREE_INT_CST_LOW (exp);
len = 2 * sizeof TREE_INT_CST_LOW (exp);
- }
- else if (code == REAL_CST)
- {
+ break;
+
+ case REAL_CST:
/* Real constants are the same only if the same width of type. */
if (*p++ != TYPE_PRECISION (TREE_TYPE (exp)))
return 0;
+
strp = (char *) &TREE_REAL_CST (exp);
len = sizeof TREE_REAL_CST (exp);
- }
- else if (code == STRING_CST)
- {
+ break;
+
+ case STRING_CST:
if (flag_writable_strings)
return 0;
+
strp = TREE_STRING_POINTER (exp);
len = TREE_STRING_LENGTH (exp);
if (bcmp ((char *) &TREE_STRING_LENGTH (exp), p,
sizeof TREE_STRING_LENGTH (exp)))
return 0;
+
p += sizeof TREE_STRING_LENGTH (exp);
- }
- else if (code == COMPLEX_CST)
- {
- p = compare_constant_1 (TREE_REALPART (exp), p);
- if (p == 0) return 0;
- p = compare_constant_1 (TREE_IMAGPART (exp), p);
- return p;
- }
- else if (code == CONSTRUCTOR && TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
- {
- int xlen = len = int_size_in_bytes (TREE_TYPE (exp));
- strp = (char *) alloca (len);
- get_set_constructor_bytes (exp, (unsigned char *) strp, len);
- if (bcmp ((char *) &xlen, p, sizeof xlen))
- return 0;
- p += sizeof xlen;
- }
- else if (code == CONSTRUCTOR)
- {
- register tree link;
- int length = list_length (CONSTRUCTOR_ELTS (exp));
- tree type;
+ break;
- if (bcmp ((char *) &length, p, sizeof length))
+ case COMPLEX_CST:
+ p = compare_constant_1 (TREE_REALPART (exp), p);
+ if (p == 0)
return 0;
- p += sizeof length;
- /* For record constructors, insist that the types match.
- For arrays, just verify both constructors are for arrays. */
- if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE)
- type = TREE_TYPE (exp);
- else
- type = 0;
- if (bcmp ((char *) &type, p, sizeof type))
- return 0;
- p += sizeof type;
+ return compare_constant_1 (TREE_IMAGPART (exp), p);
- /* For arrays, insist that the size in bytes match. */
- if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE)
+ case CONSTRUCTOR:
+ if (TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
{
- int size = int_size_in_bytes (TREE_TYPE (exp));
- if (bcmp ((char *) &size, p, sizeof size))
+ int xlen = len = int_size_in_bytes (TREE_TYPE (exp));
+
+ strp = (char *) alloca (len);
+ get_set_constructor_bytes (exp, (unsigned char *) strp, len);
+ if (bcmp ((char *) &xlen, p, sizeof xlen))
return 0;
- p += sizeof size;
- }
- for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
+ p += sizeof xlen;
+ break;
+ }
+ else
{
- if (TREE_VALUE (link))
+ register tree link;
+ int length = list_length (CONSTRUCTOR_ELTS (exp));
+ tree type;
+
+ if (bcmp ((char *) &length, p, sizeof length))
+ return 0;
+
+ p += sizeof length;
+
+ /* For record constructors, insist that the types match.
+ For arrays, just verify both constructors are for arrays. */
+ if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE)
+ type = TREE_TYPE (exp);
+ else
+ type = 0;
+
+ if (bcmp ((char *) &type, p, sizeof type))
+ return 0;
+
+ p += sizeof type;
+
+ /* For arrays, insist that the size in bytes match. */
+ if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE)
{
- if ((p = compare_constant_1 (TREE_VALUE (link), p)) == 0)
+ int size = int_size_in_bytes (TREE_TYPE (exp));
+ if (bcmp ((char *) &size, p, sizeof size))
return 0;
+
+ p += sizeof size;
}
- else
+
+ for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
{
- tree zero = 0;
+ if (TREE_VALUE (link))
+ {
+ if ((p = compare_constant_1 (TREE_VALUE (link), p)) == 0)
+ return 0;
+ }
+ else
+ {
+ tree zero = 0;
- if (bcmp ((char *) &zero, p, sizeof zero))
- return 0;
- p += sizeof zero;
+ if (bcmp ((char *) &zero, p, sizeof zero))
+ return 0;
+
+ p += sizeof zero;
+ }
}
+
+ return p;
}
- return p;
- }
- else if (code == ADDR_EXPR)
- {
- struct addr_const value;
- decode_addr_const (exp, &value);
- strp = (char *) &value.offset;
- len = sizeof value.offset;
- /* Compare the offset. */
- while (--len >= 0)
- if (*p++ != *strp++)
- return 0;
- /* Compare symbol name. */
- strp = XSTR (value.base, 0);
- len = strlen (strp) + 1;
- }
- else if (code == PLUS_EXPR || code == MINUS_EXPR)
- {
- p = compare_constant_1 (TREE_OPERAND (exp, 0), p);
- if (p == 0) return 0;
- p = compare_constant_1 (TREE_OPERAND (exp, 1), p);
- return p;
- }
- else if (code == NOP_EXPR || code == CONVERT_EXPR)
- {
+ case ADDR_EXPR:
+ {
+ struct addr_const value;
+
+ decode_addr_const (exp, &value);
+ strp = (char *) &value.offset;
+ len = sizeof value.offset;
+ /* Compare the offset. */
+ while (--len >= 0)
+ if (*p++ != *strp++)
+ return 0;
+
+ /* Compare symbol name. */
+ strp = XSTR (value.base, 0);
+ len = strlen (strp) + 1;
+ }
+ break;
+
+ case PLUS_EXPR:
+ case MINUS_EXPR:
p = compare_constant_1 (TREE_OPERAND (exp, 0), p);
- return p;
+ if (p == 0)
+ return 0;
+
+ return compare_constant_1 (TREE_OPERAND (exp, 1), p);
+
+ case NOP_EXPR:
+ case CONVERT_EXPR:
+ case NON_LVALUE_EXPR:
+ return compare_constant_1 (TREE_OPERAND (exp, 0), p);
}
/* Compare constant contents. */
case NOP_EXPR:
case CONVERT_EXPR:
+ case NON_LVALUE_EXPR:
return build1 (TREE_CODE (exp), TREE_TYPE (exp),
copy_constant (TREE_OPERAND (exp, 0)));
int labelno;
int align;
int offset;
+ int mark;
};
/* Pointers to first and last constant in pool. */
pool_offset &= ~ (align - 1);
/* If RTL is not being placed into the saveable obstack, make a
- copy of X that is in the saveable obstack in case we are being
- called from combine or some other phase that discards memory
- it allocates. We need only do this if it is a CONST, since
- no other RTX should be allocated in this situation. */
+ copy of X that is in the saveable obstack in case we are
+ being called from combine or some other phase that discards
+ memory it allocates. We used to only do this if it is a
+ CONST; however, reload can allocate a CONST_INT when
+ eliminating registers. */
if (rtl_obstack != saveable_obstack
- && GET_CODE (x) == CONST)
+ && (GET_CODE (x) == CONST || GET_CODE (x) == CONST_INT))
{
push_obstacks_nochange ();
rtl_in_saveable_obstack ();
- x = gen_rtx (CONST, GET_MODE (x),
- gen_rtx (PLUS, GET_MODE (x),
- XEXP (XEXP (x, 0), 0), XEXP (XEXP (x, 0), 1)));
+ if (GET_CODE (x) == CONST)
+ x = gen_rtx (CONST, GET_MODE (x),
+ gen_rtx (PLUS, GET_MODE (x),
+ XEXP (XEXP (x, 0), 0),
+ XEXP (XEXP (x, 0), 1)));
+ else
+ x = GEN_INT (INTVAL (x));
+
pop_obstacks ();
}
pool->labelno = const_labelno;
pool->align = align;
pool->offset = pool_offset;
+ pool->mark = 1;
pool->next = 0;
if (last_pool == 0)
rtx x;
union real_extract u;
+ /* It is possible for gcc to call force_const_mem and then to later
+ discard the instructions which refer to the constant. In such a
+ case we do not need to output the constant. */
+ if (optimize >= 0 && flag_expensive_optimizations)
+ mark_constant_pool ();
+
#ifdef ASM_OUTPUT_POOL_PROLOGUE
ASM_OUTPUT_POOL_PROLOGUE (asm_out_file, fnname, fndecl, pool_offset);
#endif
{
x = pool->constant;
+ if (! pool->mark)
+ continue;
+
/* See if X is a LABEL_REF (or a CONST referring to a LABEL_REF)
whose CODE_LABEL has been deleted. This can occur if a jump table
is eliminated by optimization. If so, write a constant of zero
/* Done with this pool. */
first_pool = last_pool = 0;
}
+
+/* Look through the instructions for this function, and mark all the
+ entries in the constant pool which are actually being used. */
+
+static void
+mark_constant_pool ()
+{
+ register rtx insn;
+ struct pool_constant *pool;
+
+ if (first_pool == 0)
+ return;
+
+ for (pool = first_pool; pool; pool = pool->next)
+ pool->mark = 0;
+
+ for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+ mark_constants (PATTERN (insn));
+
+ for (insn = current_function_epilogue_delay_list;
+ insn;
+ insn = XEXP (insn, 1))
+ if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+ mark_constants (PATTERN (insn));
+}
+
+static void
+mark_constants (x)
+ register rtx x;
+{
+ register int i;
+ register char *format_ptr;
+
+ if (x == 0)
+ return;
+
+ if (GET_CODE (x) == SYMBOL_REF)
+ {
+ if (CONSTANT_POOL_ADDRESS_P (x))
+ find_pool_constant (x)->mark = 1;
+ return;
+ }
+
+ /* Insns may appear inside a SEQUENCE. Only check the patterns of
+ insns, not any notes that may be attached. We don't want to mark
+ a constant just because it happens to appear in a REG_EQUIV note. */
+ if (GET_RTX_CLASS (GET_CODE (x)) == 'i')
+ {
+ mark_constants (PATTERN (x));
+ return;
+ }
+
+ format_ptr = GET_RTX_FORMAT (GET_CODE (x));
+
+ for (i = 0; i < GET_RTX_LENGTH (GET_CODE (x)); i++)
+ {
+ switch (*format_ptr++)
+ {
+ case 'e':
+ mark_constants (XEXP (x, i));
+ break;
+
+ case 'E':
+ if (XVEC (x, i) != 0)
+ {
+ register int j;
+
+ for (j = 0; j < XVECLEN (x, i); j++)
+ mark_constants (XVECEXP (x, i, j));
+ }
+ break;
+
+ case 'S':
+ case 's':
+ case '0':
+ case 'i':
+ case 'w':
+ case 'n':
+ case 'u':
+ break;
+
+ default:
+ abort ();
+ }
+ }
+}
\f
/* Find all the constants whose addresses are referenced inside of EXP,
and make sure assembler code with a label has been output for each one.
exp = fold (exp);
- while (TREE_CODE (exp) == NOP_EXPR || TREE_CODE (exp) == CONVERT_EXPR)
+ while (TREE_CODE (exp) == NOP_EXPR || TREE_CODE (exp) == CONVERT_EXPR
+ || TREE_CODE (exp) == NON_LVALUE_EXPR)
exp = TREE_OPERAND (exp, 0);
if (TREE_CODE (exp) == INTEGER_CST)
{
{
const_part = TREE_OPERAND (exp, 0);
while (TREE_CODE (const_part) == NOP_EXPR
- || TREE_CODE (const_part) == CONVERT_EXPR)
+ || TREE_CODE (const_part) == CONVERT_EXPR
+ || TREE_CODE (const_part) == NON_LVALUE_EXPR)
const_part = TREE_OPERAND (const_part, 0);
addr_part = TREE_OPERAND (exp, 1);
while (TREE_CODE (addr_part) == NOP_EXPR
- || TREE_CODE (addr_part) == CONVERT_EXPR)
+ || TREE_CODE (addr_part) == CONVERT_EXPR
+ || TREE_CODE (addr_part) == NON_LVALUE_EXPR)
addr_part = TREE_OPERAND (addr_part, 0);
if (TREE_CODE (const_part) != INTEGER_CST)
tmp = const_part, const_part = addr_part, addr_part = tmp;