/* Output variables, constants and external declarations, for GNU compiler.
- Copyright (C) 1987, 88, 89, 92, 93, 1994 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 89, 92, 93, 94, 1995 Free Software Foundation, Inc.
This file is part of GNU CC.
#include "flags.h"
#include "function.h"
#include "expr.h"
+#include "output.h"
#include "hard-reg-set.h"
#include "regs.h"
#include "defaults.h"
extern struct obstack *current_obstack;
extern struct obstack *saveable_obstack;
+extern struct obstack *rtl_obstack;
extern struct obstack permanent_obstack;
#define obstack_chunk_alloc xmalloc
/* Nonzero if at least one function definition has been seen. */
static int function_defined;
-extern FILE *asm_out_file;
-
-static char *compare_constant_1 ();
-static void record_constant_1 ();
-static void output_constant_def_contents ();
-static int contains_pointers_p ();
-static void bc_output_ascii ();
-
-void output_constant_pool ();
-void assemble_name ();
-int output_addressed_constants ();
-void output_constant ();
-void output_constructor ();
-void output_byte_asm ();
-void text_section ();
-void readonly_data_section ();
-void data_section ();
-void named_section ();
-static void bc_assemble_integer ();
+struct addr_const;
+struct constant_descriptor;
+struct rtx_const;
+struct pool_constant;
+
+static void bc_make_decl_rtl PROTO((tree, char *, int));
+static char *strip_reg_name PROTO((char *));
+static void bc_output_ascii PROTO((FILE *, char *, int));
+static int contains_pointers_p PROTO((tree));
+static void decode_addr_const PROTO((tree, struct addr_const *));
+static int const_hash PROTO((tree));
+static int compare_constant PROTO((tree,
+ struct constant_descriptor *));
+static char *compare_constant_1 PROTO((tree, char *));
+static struct constant_descriptor *record_constant PROTO((tree));
+static void record_constant_1 PROTO((tree));
+static tree copy_constant PROTO((tree));
+static void output_constant_def_contents PROTO((tree, int, int));
+static void decode_rtx_const PROTO((enum machine_mode, rtx,
+ struct rtx_const *));
+static int const_hash_rtx PROTO((enum machine_mode, rtx));
+static int compare_constant_rtx PROTO((enum machine_mode, rtx,
+ struct constant_descriptor *));
+static struct constant_descriptor *record_constant_rtx PROTO((enum machine_mode,
+ rtx));
+static struct pool_constant *find_pool_constant PROTO((rtx));
+static int output_addressed_constants PROTO((tree));
+static void bc_assemble_integer PROTO((tree, int));
+static void output_constructor PROTO((tree, int));
\f
#ifdef EXTRA_SECTIONS
static enum in_section {no_section, in_text, in_data, in_named, EXTRA_SECTIONS} in_section
return in_section == in_text;
}
-/* Tell assembler to change to named section. */
+/* Tell assembler to change to section NAME for DECL.
+ If DECL is NULL, just switch to section NAME.
+ If NAME is NULL, get the name from DECL. */
void
-named_section (name)
+named_section (decl, name)
+ tree decl;
char *name;
{
+ if (decl != NULL_TREE
+ && (TREE_CODE (decl) != FUNCTION_DECL && TREE_CODE (decl) != VAR_DECL))
+ abort ();
+ if (name == NULL)
+ name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
+
if (in_section != in_named || strcmp (name, in_named_name))
{
in_named_name = name;
in_section = in_named;
#ifdef ASM_OUTPUT_SECTION_NAME
- ASM_OUTPUT_SECTION_NAME (asm_out_file, name);
+ ASM_OUTPUT_SECTION_NAME (asm_out_file, decl, name);
#else
/* Section attributes are not supported if this macro isn't provided -
some host formats don't support them at all. The front-end should
#endif
}
}
+
+/* Switch to the section for function DECL.
+
+ If DECL is NULL_TREE, switch to the text section.
+ ??? It's not clear that we will ever be passed NULL_TREE, but it's
+ safer to handle it. */
+
+void
+function_section (decl)
+ tree decl;
+{
+ if (decl != NULL_TREE
+ && DECL_SECTION_NAME (decl) != NULL_TREE)
+ named_section (decl, (char *) 0);
+ else
+ text_section ();
+}
\f
/* Create the rtl to represent a function, for a function definition.
DECL is a FUNCTION_DECL node which describes which function.
as the assembler symbol name.
TOP_LEVEL is nonzero if this is a file-scope variable.
This is never called for PARM_DECLs. */
-void
+
+static void
bc_make_decl_rtl (decl, asmspec, top_level)
tree decl;
char *asmspec;
unit that behaved thusly). So warn the user. */
else if (TREE_CODE (decl) == VAR_DECL
&& DECL_SECTION_NAME (decl) != NULL_TREE
- && DECL_INITIAL (decl) == NULL_TREE)
+ && DECL_INITIAL (decl) == NULL_TREE
+ && DECL_COMMON (decl)
+ && ! flag_no_common)
{
warning_with_decl (decl,
"section attribute ignored for uninitialized variable `%s'");
+ /* Remove the section name so subsequent declarations won't see it.
+ We are ignoring it, remember. */
+ DECL_SECTION_NAME (decl) = NULL_TREE;
}
/* Now handle ordinary static variables and functions (in memory).
if (TREE_READONLY (decl))
RTX_UNCHANGING_P (DECL_RTL (decl)) = 1;
MEM_IN_STRUCT_P (DECL_RTL (decl))
- = (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
- || TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE
- || TREE_CODE (TREE_TYPE (decl)) == UNION_TYPE
- || TREE_CODE (TREE_TYPE (decl)) == QUAL_UNION_TYPE);
+ = AGGREGATE_TYPE_P (TREE_TYPE (decl));
/* Optionally set flags or add text to the name to record information
such as that it is a function name.
output_constant_pool (fnname, decl);
- if (IN_NAMED_SECTION (decl))
- named_section (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)));
- else
- text_section ();
+ function_section (decl);
/* Tell assembler to move to target machine's alignment for functions. */
align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
tree decl;
int top_level;
int at_end;
+ int dont_output_data;
{
register char *name;
int align;
DECL_SOURCE_LINE (decl),
"storage size of `%s' isn't known",
IDENTIFIER_POINTER (DECL_NAME (decl)));
+ TREE_ASM_WRITTEN (decl) = 1;
return;
}
TREE_ASM_WRITTEN (decl) = 1;
- /* If storage size is erroneously variable, just continue.
- Error message was already made. */
+ app_disable ();
- if (DECL_SIZE (decl))
+ if (! dont_output_data)
{
if (TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST)
goto finish;
- app_disable ();
-
/* This is better than explicit arithmetic, since it avoids overflow. */
size_tree = size_binop (CEIL_DIV_EXPR,
- DECL_SIZE (decl), size_int (BITS_PER_UNIT));
+ DECL_SIZE (decl), size_int (BITS_PER_UNIT));
if (TREE_INT_CST_HIGH (size_tree) != 0)
{
/* Switch to the proper section for this data. */
if (IN_NAMED_SECTION (decl))
- named_section (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)));
+ named_section (decl, NULL);
else
{
/* C++ can have const variables that get initialized from constructors,
{
if (DECL_INITIAL (decl))
/* Output the actual data. */
- output_constant (DECL_INITIAL (decl),
- int_size_in_bytes (TREE_TYPE (decl)));
+ output_constant (DECL_INITIAL (decl), TREE_INT_CST_LOW (size_tree));
else
/* Leave space for it. */
- assemble_zeros (int_size_in_bytes (TREE_TYPE (decl)));
+ assemble_zeros (TREE_INT_CST_LOW (size_tree));
}
finish:
tree fields;
/* For a type that has fields, see if the fields have pointers. */
for (fields = TYPE_FIELDS (type); fields; fields = TREE_CHAIN (fields))
- if (contains_pointers_p (TREE_TYPE (fields)))
+ if (TREE_CODE (fields) == FIELD_DECL
+ && contains_pointers_p (TREE_TYPE (fields)))
return 1;
return 0;
}
}
}
-/* Output text storage for constructor CONSTR. Returns rtx of
- storage. */
+/* Output text storage for constructor CONSTR. */
-rtx
-bc_output_constructor (constr)
- tree constr;
+void
+bc_output_constructor (constr, size)
+ tree constr;
+ int size;
{
int i;
text_section ();
/* Align */
- for (i = 0; TYPE_ALIGN (constr) >= BITS_PER_UNIT << (i + 1); i++);
+ for (i = 0; TYPE_ALIGN (constr) >= BITS_PER_UNIT << (i + 1); i++)
+ ;
+
if (i > 0)
BC_OUTPUT_ALIGN (asm_out_file, i);
/* Output data */
- output_constant (constr, int_size_in_bytes (TREE_TYPE (constr)));
+ output_constant (constr, size);
}
-
/* Create storage for constructor CONSTR. */
void
BC_OUTPUT_SKIP (asm_out_file, int_size_in_bytes (TREE_TYPE (constr)));
}
-
/* Output something to declare an external symbol to the assembler.
(Most assemblers don't need this, so we normally output nothing.)
Do nothing if DECL is not external. */
FILE *file;
char *name;
{
+ char *real_name;
+
+ STRIP_NAME_ENCODING (real_name, name);
+ TREE_SYMBOL_REFERENCED (get_identifier (real_name)) = 1;
+
if (name[0] == '*')
{
if (output_bytecode)
{
error ("floating point trap outputting a constant");
#ifdef REAL_IS_NOT_DOUBLE
- bzero (&d, sizeof d);
+ bzero ((char *) &d, sizeof d);
d = dconst0;
#else
d = 0;
ASM_OUTPUT_SHORT_FLOAT (asm_out_file, d);
break;
#endif
+#ifdef ASM_OUTPUT_THREE_QUARTER_FLOAT
+ case TQFmode:
+ ASM_OUTPUT_THREE_QUARTER_FLOAT (asm_out_file, d);
+ break;
+#endif
#ifdef ASM_OUTPUT_FLOAT
case SFmode:
ASM_OUTPUT_FLOAT (asm_out_file, d);
/* We cannot represent this value as a constant. */
abort ();
+ /* If this would be an entire word for the target, but is not for
+ the host, then sign-extend on the host so that the number will look
+ the same way on the host that it would on the target.
+
+ For example, when building a 64 bit alpha hosted 32 bit sparc
+ targeted compiler, then we want the 32 bit unsigned value -1 to be
+ represented as a 64 bit value -1, and not as 0x00000000ffffffff.
+ The later confuses the sparc backend. */
+
+ if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT && BITS_PER_WORD == width
+ && (i0 & ((HOST_WIDE_INT) 1 << (width - 1))))
+ i0 |= ((HOST_WIDE_INT) (-1) << width);
+
/* If MODE fits within HOST_BITS_PER_WIDE_INT, always use a CONST_INT.
??? Strictly speaking, this is wrong if we create a CONST_INT
/* Detect special cases. */
/* Avoid REAL_VALUES_EQUAL here in order to distinguish minus zero. */
- if (!bcmp (&dconst0, &d, sizeof d))
+ if (!bcmp ((char *) &dconst0, (char *) &d, sizeof d))
return CONST0_RTX (mode);
/* Check for NaN first, because some ports (specifically the i386) do not
emit correct ieee-fp code by default, and thus will generate a core
If one is found, return it. */
for (r = const_double_chain; r; r = CONST_DOUBLE_CHAIN (r))
- if (! bcmp (&CONST_DOUBLE_LOW (r), &u, sizeof u)
+ if (! bcmp ((char *) &CONST_DOUBLE_LOW (r), (char *) &u, sizeof u)
&& GET_MODE (r) == mode)
return r;
rtl_in_saveable_obstack ();
r = rtx_alloc (CONST_DOUBLE);
PUT_MODE (r, mode);
- bcopy (&u, &CONST_DOUBLE_LOW (r), sizeof u);
+ bcopy ((char *) &u, (char *) &CONST_DOUBLE_LOW (r), sizeof u);
pop_obstacks ();
/* Don't touch const_double_chain in nested function; see force_const_mem.
/* Compute a hash code for a constant expression. */
-int
+static int
const_hash (exp)
tree 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;
return 0;
strp = TREE_STRING_POINTER (exp);
len = TREE_STRING_LENGTH (exp);
- if (bcmp (&TREE_STRING_LENGTH (exp), p,
+ if (bcmp ((char *) &TREE_STRING_LENGTH (exp), p,
sizeof TREE_STRING_LENGTH (exp)))
return 0;
p += sizeof TREE_STRING_LENGTH (exp);
p = compare_constant_1 (TREE_IMAGPART (exp), p);
return p;
}
+ else if (code == CONSTRUCTOR && TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
+ {
+ len = int_size_in_bytes (TREE_TYPE (exp));
+ strp = (char*) alloca (len);
+ get_set_constructor_bytes (exp, (unsigned char *) strp, len);
+ }
else if (code == CONSTRUCTOR)
{
register tree link;
int length = list_length (CONSTRUCTOR_ELTS (exp));
tree type;
- if (bcmp (&length, p, sizeof length))
+ if (bcmp ((char *) &length, p, sizeof length))
return 0;
p += sizeof length;
type = TREE_TYPE (exp);
else
type = 0;
- if (bcmp (&type, p, sizeof type))
+ if (bcmp ((char *) &type, p, sizeof type))
return 0;
p += sizeof type;
if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE)
{
int size = int_size_in_bytes (TREE_TYPE (exp));
- if (bcmp (&size, p, sizeof size))
+ if (bcmp ((char *) &size, p, sizeof size))
return 0;
p += sizeof size;
}
{
tree zero = 0;
- if (bcmp (&zero, p, sizeof zero))
+ if (bcmp ((char *) &zero, p, sizeof zero))
return 0;
p += sizeof zero;
}
obstack_1grow (&permanent_obstack, (unsigned int) code);
- if (code == INTEGER_CST)
+ switch (code)
{
+ case INTEGER_CST:
obstack_1grow (&permanent_obstack, TYPE_PRECISION (TREE_TYPE (exp)));
strp = (char *) &TREE_INT_CST_LOW (exp);
len = 2 * sizeof TREE_INT_CST_LOW (exp);
- }
- else if (code == REAL_CST)
- {
+ break;
+
+ case REAL_CST:
obstack_1grow (&permanent_obstack, TYPE_PRECISION (TREE_TYPE (exp)));
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;
+
strp = TREE_STRING_POINTER (exp);
len = TREE_STRING_LENGTH (exp);
obstack_grow (&permanent_obstack, (char *) &TREE_STRING_LENGTH (exp),
sizeof TREE_STRING_LENGTH (exp));
- }
- else if (code == COMPLEX_CST)
- {
+ break;
+
+ case COMPLEX_CST:
record_constant_1 (TREE_REALPART (exp));
record_constant_1 (TREE_IMAGPART (exp));
return;
- }
- else if (code == CONSTRUCTOR)
- {
- register tree link;
- int length = list_length (CONSTRUCTOR_ELTS (exp));
- tree type;
-
- obstack_grow (&permanent_obstack, (char *) &length, 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;
- obstack_grow (&permanent_obstack, (char *) &type, sizeof type);
-
- /* 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));
- obstack_grow (&permanent_obstack, (char *) &size, sizeof size);
+ int nbytes = int_size_in_bytes (TREE_TYPE (exp));
+ obstack_grow (&permanent_obstack, &nbytes, sizeof (nbytes));
+ obstack_blank (&permanent_obstack, nbytes);
+ get_set_constructor_bytes
+ (exp, (unsigned char *) permanent_obstack.next_free, nbytes);
+ return;
}
-
- for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
+ else
{
- if (TREE_VALUE (link))
- record_constant_1 (TREE_VALUE (link));
+ register tree link;
+ int length = list_length (CONSTRUCTOR_ELTS (exp));
+ tree type;
+
+ obstack_grow (&permanent_obstack, (char *) &length, 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;
+ obstack_grow (&permanent_obstack, (char *) &type, sizeof type);
+
+ /* For arrays, insist that the size in bytes match. */
+ if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE)
{
- tree zero = 0;
+ int size = int_size_in_bytes (TREE_TYPE (exp));
+ obstack_grow (&permanent_obstack, (char *) &size, sizeof size);
+ }
+
+ for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
+ {
+ if (TREE_VALUE (link))
+ record_constant_1 (TREE_VALUE (link));
+ else
+ {
+ tree zero = 0;
- obstack_grow (&permanent_obstack, (char *) &zero, sizeof zero);
+ obstack_grow (&permanent_obstack,
+ (char *) &zero, sizeof zero);
+ }
}
}
-
return;
- }
- else if (code == ADDR_EXPR)
- {
- struct addr_const value;
- decode_addr_const (exp, &value);
- /* Record the offset. */
- obstack_grow (&permanent_obstack,
- (char *) &value.offset, sizeof value.offset);
- /* Record the symbol name. */
- obstack_grow (&permanent_obstack, XSTR (value.base, 0),
- strlen (XSTR (value.base, 0)) + 1);
+
+ case ADDR_EXPR:
+ {
+ struct addr_const value;
+
+ decode_addr_const (exp, &value);
+ /* Record the offset. */
+ obstack_grow (&permanent_obstack,
+ (char *) &value.offset, sizeof value.offset);
+ /* Record the symbol name. */
+ obstack_grow (&permanent_obstack, XSTR (value.base, 0),
+ strlen (XSTR (value.base, 0)) + 1);
+ }
return;
- }
- else if (code == PLUS_EXPR || code == MINUS_EXPR)
- {
+
+ case PLUS_EXPR:
+ case MINUS_EXPR:
record_constant_1 (TREE_OPERAND (exp, 0));
record_constant_1 (TREE_OPERAND (exp, 1));
return;
- }
- else if (code == NOP_EXPR || code == CONVERT_EXPR)
- {
+
+ case NOP_EXPR:
+ case CONVERT_EXPR:
+ case NON_LVALUE_EXPR:
record_constant_1 (TREE_OPERAND (exp, 0));
return;
+
+ default:
+ abort ();
}
/* Record constant contents. */
{
switch (TREE_CODE (exp))
{
+ case ADDR_EXPR:
+ /* For ADDR_EXPR, we do not want to copy the decl whose address
+ is requested. We do want to copy constants though. */
+ if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 0))) == 'c')
+ return build1 (TREE_CODE (exp), TREE_TYPE (exp),
+ copy_constant (TREE_OPERAND (exp, 0)));
+ else
+ return copy_node (exp);
+
case INTEGER_CST:
case REAL_CST:
case STRING_CST:
- case ADDR_EXPR:
- /* For ADDR_EXPR, we do not want to copy the decl
- whose address is requested. */
return copy_node (exp);
case COMPLEX_CST:
tree list = copy_list (CONSTRUCTOR_ELTS (exp));
tree tail;
- CONSTRUCTOR_ELTS (exp) = list;
+ CONSTRUCTOR_ELTS (copy) = list;
for (tail = list; tail; tail = TREE_CHAIN (tail))
TREE_VALUE (tail) = copy_constant (TREE_VALUE (tail));
+ if (TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
+ for (tail = list; tail; tail = TREE_CHAIN (tail))
+ TREE_PURPOSE (tail) = copy_constant (TREE_PURPOSE (tail));
return copy;
}
TREE_CST_RTL (exp)
= gen_rtx (MEM, TYPE_MODE (TREE_TYPE (exp)), def);
RTX_UNCHANGING_P (TREE_CST_RTL (exp)) = 1;
- if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE
- || TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE)
+ if (AGGREGATE_TYPE_P (TREE_TYPE (exp)))
MEM_IN_STRUCT_P (TREE_CST_RTL (exp)) = 1;
pop_obstacks ();
int align;
if (IN_NAMED_SECTION (exp))
- named_section (TREE_STRING_POINTER (DECL_SECTION_NAME (exp)));
+ named_section (exp, NULL);
else
{
/* First switch to text section, except for writable strings. */
const_rtx_sym_hash_table
= ((struct pool_sym **)
oballoc (MAX_RTX_HASH_TABLE * sizeof (struct pool_sym *)));
- bzero (const_rtx_hash_table,
+ bzero ((char *) const_rtx_hash_table,
MAX_RTX_HASH_TABLE * sizeof (struct constant_descriptor *));
- bzero (const_rtx_sym_hash_table,
+ bzero ((char *) const_rtx_sym_hash_table,
MAX_RTX_HASH_TABLE * sizeof (struct pool_sym *));
first_pool = last_pool = 0;
pool_offset = 0;
}
-/* Save and restore it for a nested function. */
+/* Save and restore status for a nested function. */
void
save_varasm_status (p)
value->kind = RTX_DOUBLE;
if (GET_MODE (x) != VOIDmode)
value->mode = GET_MODE (x);
- bcopy (&CONST_DOUBLE_LOW (x), &value->un.du, sizeof value->un.du);
+ bcopy ((char *) &CONST_DOUBLE_LOW (x),
+ (char *) &value->un.du, sizeof value->un.du);
break;
case CONST_INT:
/* Compute a hash code for a constant RTL expression. */
-int
+static int
const_hash_rtx (mode, x)
enum machine_mode mode;
rtx x;
decode_rtx_const (mode, x, &value);
- obstack_grow (current_obstack, &ptr, sizeof ptr);
- obstack_grow (current_obstack, &label, sizeof label);
+ /* Put these things in the saveable obstack so we can ensure it won't
+ be freed if we are called from combine or some other phase that discards
+ memory allocated from function_obstack (current_obstack). */
+ obstack_grow (saveable_obstack, &ptr, sizeof ptr);
+ obstack_grow (saveable_obstack, &label, sizeof label);
/* Record constant contents. */
- obstack_grow (current_obstack, &value, sizeof value);
+ obstack_grow (saveable_obstack, &value, sizeof value);
- return (struct constant_descriptor *) obstack_finish (current_obstack);
+ return (struct constant_descriptor *) obstack_finish (saveable_obstack);
}
\f
/* Given a constant rtx X, make (or find) a memory constant for its value
pool_offset += align - 1;
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. */
+ if (rtl_obstack != saveable_obstack
+ && GET_CODE (x) == CONST)
+ {
+ 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)));
+ pop_obstacks ();
+ }
+
/* Allocate a pool constant descriptor, fill it in, and chain it in. */
- pool = (struct pool_constant *) oballoc (sizeof (struct pool_constant));
+ pool = (struct pool_constant *) savealloc (sizeof (struct pool_constant));
pool->desc = desc;
pool->constant = x;
pool->mode = mode;
/* Add label to symbol hash table. */
hash = SYMHASH (found);
- sym = (struct pool_sym *) oballoc (sizeof (struct pool_sym));
+ sym = (struct pool_sym *) savealloc (sizeof (struct pool_sym));
sym->label = found;
sym->pool = pool;
sym->next = const_rtx_sym_hash_table[hash];
if (GET_CODE (x) != CONST_DOUBLE)
abort ();
- bcopy (&CONST_DOUBLE_LOW (x), &u, sizeof u);
+ bcopy ((char *) &CONST_DOUBLE_LOW (x), (char *) &u, sizeof u);
assemble_real (u.d, pool->mode);
break;
and make sure assembler code with a label has been output for each one.
Indicate whether an ADDR_EXPR has been encountered. */
-int
+static int
output_addressed_constants (exp)
tree exp;
{
}
return reloc;
}
-
-
-/* Output assembler for byte constant */
-void
-output_byte_asm (byte)
- int byte;
-{
- if (output_bytecode)
- bc_emit_const ((char *) &byte, sizeof (char));
-#ifdef ASM_OUTPUT_BYTE
- else
- {
- ASM_OUTPUT_BYTE (asm_out_file, byte);
- }
-#endif
-}
\f
/* Output assembler code for constant EXP to FILE, with no label.
This includes the pseudo-op such as ".int" or ".byte", and a newline.
return;
/* Eliminate the NON_LVALUE_EXPR_EXPR that makes a cast not be an lvalue.
- That way we get the constant (we hope) inside it. Also, strip
- off any NOP_EXPR that converts between two record or union types. */
+ That way we get the constant (we hope) inside it. Also, strip off any
+ NOP_EXPR that converts between two record, union, array, or set types. */
while ((TREE_CODE (exp) == NOP_EXPR
&& (TREE_TYPE (exp) == TREE_TYPE (TREE_OPERAND (exp, 0))
- || TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE
- || TREE_CODE (TREE_TYPE (exp)) == UNION_TYPE
- || TREE_CODE (TREE_TYPE (exp)) == QUAL_UNION_TYPE))
+ || AGGREGATE_TYPE_P (TREE_TYPE (exp))))
|| TREE_CODE (exp) == NON_LVALUE_EXPR)
exp = TREE_OPERAND (exp, 0);
else
abort ();
return;
+
+ case SET_TYPE:
+ if (TREE_CODE (exp) == INTEGER_CST)
+ assemble_integer (expand_expr (exp, NULL_RTX,
+ VOIDmode, EXPAND_INITIALIZER),
+ size, 1);
+ else if (TREE_CODE (exp) == CONSTRUCTOR)
+ {
+ unsigned char *buffer = (unsigned char *) alloca (size);
+ if (get_set_constructor_bytes (exp, buffer, size))
+ abort ();
+ assemble_string ((char *) buffer, size);
+ }
+ else
+ error ("unknown set constructor type");
+ return;
}
if (size > 0)
assemble_zeros (size);
}
-
/* Bytecode specific code to output assembler for integer. */
+
static void
bc_assemble_integer (exp, size)
tree exp;
}
else if (size == 8)
{
-#if WORDS_BIG_ENDIAN
- int i = TREE_INT_CST_HIGH (const_part);
- bc_emit ((char *) &i, 4);
- i = TREE_INT_CST_LOW (const_part);
- bc_emit ((char *) &i, 4);
-#else
- int i = TREE_INT_CST_LOW (const_part);
- bc_emit ((char *) &i, 4);
- i = TREE_INT_CST_HIGH (const_part);
- bc_emit ((char *) &i, 4);
-#endif
+ if (WORDS_BIG_ENDIAN)
+ {
+ int i = TREE_INT_CST_HIGH (const_part);
+ bc_emit ((char *) &i, 4);
+ i = TREE_INT_CST_LOW (const_part);
+ bc_emit ((char *) &i, 4);
+ }
+ else
+ {
+ int i = TREE_INT_CST_LOW (const_part);
+ bc_emit ((char *) &i, 4);
+ i = TREE_INT_CST_HIGH (const_part);
+ bc_emit ((char *) &i, 4);
+ }
size -= 8;
}
}
(aggregate constants).
Generate at least SIZE bytes, padding if necessary. */
-void
+static void
output_constructor (exp, size)
tree exp;
int size;
while (next_offset < end_offset)
{
int this_time;
- int shift, value;
+ int shift;
+ HOST_WIDE_INT value;
int next_byte = next_offset / BITS_PER_UNIT;
int next_bit = next_offset % BITS_PER_UNIT;
(all part of the same byte). */
this_time = MIN (end_offset - next_offset,
BITS_PER_UNIT - next_bit);
-#if BYTES_BIG_ENDIAN
- /* On big-endian machine, take the most significant bits
- first (of the bits that are significant)
- and put them into bytes from the most significant end. */
- shift = end_offset - next_offset - this_time;
- /* Don't try to take a bunch of bits that cross
- the word boundary in the INTEGER_CST. */
- if (shift < HOST_BITS_PER_WIDE_INT
- && shift + this_time > HOST_BITS_PER_WIDE_INT)
- {
- this_time -= (HOST_BITS_PER_WIDE_INT - shift);
- shift = HOST_BITS_PER_WIDE_INT;
- }
-
- /* Now get the bits from the appropriate constant word. */
- if (shift < HOST_BITS_PER_WIDE_INT)
- {
- value = TREE_INT_CST_LOW (val);
- }
- else if (shift < 2 * HOST_BITS_PER_WIDE_INT)
+ if (BYTES_BIG_ENDIAN)
{
- value = TREE_INT_CST_HIGH (val);
- shift -= HOST_BITS_PER_WIDE_INT;
+ /* On big-endian machine, take the most significant bits
+ first (of the bits that are significant)
+ and put them into bytes from the most significant end. */
+ shift = end_offset - next_offset - this_time;
+ /* Don't try to take a bunch of bits that cross
+ the word boundary in the INTEGER_CST. */
+ if (shift < HOST_BITS_PER_WIDE_INT
+ && shift + this_time > HOST_BITS_PER_WIDE_INT)
+ {
+ this_time -= (HOST_BITS_PER_WIDE_INT - shift);
+ shift = HOST_BITS_PER_WIDE_INT;
+ }
+
+ /* Now get the bits from the appropriate constant word. */
+ if (shift < HOST_BITS_PER_WIDE_INT)
+ {
+ value = TREE_INT_CST_LOW (val);
+ }
+ else if (shift < 2 * HOST_BITS_PER_WIDE_INT)
+ {
+ value = TREE_INT_CST_HIGH (val);
+ shift -= HOST_BITS_PER_WIDE_INT;
+ }
+ else
+ abort ();
+ byte |= (((value >> shift)
+ & (((HOST_WIDE_INT) 1 << this_time) - 1))
+ << (BITS_PER_UNIT - this_time - next_bit));
}
else
- abort ();
- byte |= (((value >> shift)
- & (((HOST_WIDE_INT) 1 << this_time) - 1))
- << (BITS_PER_UNIT - this_time - next_bit));
-#else
- /* On little-endian machines,
- take first the least significant bits of the value
- and pack them starting at the least significant
- bits of the bytes. */
- shift = (next_offset
- - TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field)));
- /* Don't try to take a bunch of bits that cross
- the word boundary in the INTEGER_CST. */
- if (shift < HOST_BITS_PER_WIDE_INT
- && shift + this_time > HOST_BITS_PER_WIDE_INT)
{
- this_time -= (HOST_BITS_PER_WIDE_INT - shift);
- shift = HOST_BITS_PER_WIDE_INT;
+ /* On little-endian machines,
+ take first the least significant bits of the value
+ and pack them starting at the least significant
+ bits of the bytes. */
+ shift = (next_offset
+ - TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field)));
+ /* Don't try to take a bunch of bits that cross
+ the word boundary in the INTEGER_CST. */
+ if (shift < HOST_BITS_PER_WIDE_INT
+ && shift + this_time > HOST_BITS_PER_WIDE_INT)
+ {
+ this_time -= (HOST_BITS_PER_WIDE_INT - shift);
+ shift = HOST_BITS_PER_WIDE_INT;
+ }
+
+ /* Now get the bits from the appropriate constant word. */
+ if (shift < HOST_BITS_PER_INT)
+ value = TREE_INT_CST_LOW (val);
+ else if (shift < 2 * HOST_BITS_PER_WIDE_INT)
+ {
+ value = TREE_INT_CST_HIGH (val);
+ shift -= HOST_BITS_PER_WIDE_INT;
+ }
+ else
+ abort ();
+ byte |= (((value >> shift)
+ & (((HOST_WIDE_INT) 1 << this_time) - 1))
+ << next_bit);
}
-
- /* Now get the bits from the appropriate constant word. */
- if (shift < HOST_BITS_PER_INT)
- value = TREE_INT_CST_LOW (val);
- else if (shift < 2 * HOST_BITS_PER_WIDE_INT)
- {
- value = TREE_INT_CST_HIGH (val);
- shift -= HOST_BITS_PER_WIDE_INT;
- }
- else
- abort ();
- byte |= ((value >> shift)
- & (((HOST_WIDE_INT) 1 << this_time) - 1)) << next_bit;
-#endif
next_offset += this_time;
byte_buffer_in_use = 1;
}