aboutsummaryrefslogtreecommitdiff
path: root/gcc/varasm.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/varasm.c')
-rw-r--r--gcc/varasm.c239
1 files changed, 150 insertions, 89 deletions
diff --git a/gcc/varasm.c b/gcc/varasm.c
index 8b34062..24380c2 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -161,7 +161,8 @@ static int mark_constant PARAMS ((rtx *current_rtx, void *data));
static int output_addressed_constants PARAMS ((tree));
static void output_after_function_constants PARAMS ((void));
static unsigned HOST_WIDE_INT array_size_for_constructor PARAMS ((tree));
-static void output_constructor PARAMS ((tree, int));
+static unsigned min_align PARAMS ((unsigned, unsigned));
+static void output_constructor PARAMS ((tree, int, unsigned));
#ifdef ASM_WEAKEN_LABEL
static void remove_from_pending_weak_list PARAMS ((const char *));
#endif
@@ -952,7 +953,7 @@ default_named_section_asm_out_destructor (symbol, priority)
named_section_flags (section, SECTION_WRITE);
assemble_align (POINTER_SIZE);
- assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, 1);
+ assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
}
#ifdef DTORS_SECTION_ASM_OP
@@ -973,7 +974,8 @@ default_dtor_section_asm_out_destructor (symbol, priority)
int priority ATTRIBUTE_UNUSED;
{
dtors_section ();
- assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, 1);
+ assemble_align (POINTER_SIZE);
+ assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
}
#endif
@@ -1012,7 +1014,8 @@ default_named_section_asm_out_constructor (symbol, priority)
}
named_section_flags (section, SECTION_WRITE);
- assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, 1);
+ assemble_align (POINTER_SIZE);
+ assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
}
#ifdef CTORS_SECTION_ASM_OP
@@ -1033,7 +1036,8 @@ default_ctor_section_asm_out_constructor (symbol, priority)
int priority ATTRIBUTE_UNUSED;
{
ctors_section ();
- assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, 1);
+ assemble_align (POINTER_SIZE);
+ assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
}
#endif
@@ -1172,29 +1176,8 @@ assemble_zeros (size)
if (ASM_NO_SKIP_IN_TEXT && in_text_section ())
{
int i;
-
- for (i = 0; i < size - 20; i += 20)
- {
-#ifdef ASM_BYTE_OP
- fprintf (asm_out_file,
- "%s0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n", ASM_BYTE_OP);
-#else
- fprintf (asm_out_file,
- "\tbyte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n");
-#endif
- }
- if (i < size)
- {
-#ifdef ASM_BYTE_OP
- fprintf (asm_out_file, "%s0", ASM_BYTE_OP);
-#else
- fprintf (asm_out_file, "\tbyte 0");
-#endif
- i++;
- for (; i < size; i++)
- fprintf (asm_out_file, ",0");
- fprintf (asm_out_file, "\n");
- }
+ for (i = 0; i < size; i++)
+ assemble_integer (const0_rtx, 1, BITS_PER_UNIT, 1);
}
else
#endif
@@ -1584,7 +1567,8 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
if (DECL_INITIAL (decl))
/* Output the actual data. */
output_constant (DECL_INITIAL (decl),
- tree_low_cst (DECL_SIZE_UNIT (decl), 1));
+ tree_low_cst (DECL_SIZE_UNIT (decl), 1),
+ align);
else
/* Leave space for it. */
assemble_zeros (tree_low_cst (DECL_SIZE_UNIT (decl), 1));
@@ -1801,52 +1785,90 @@ assemble_trampoline_template ()
}
#endif
-/* Assemble the integer constant X into an object of SIZE bytes.
- X must be either a CONST_INT or CONST_DOUBLE.
+/* A and B are either alignments or offsets. Return the minimum alignment
+ that may be assumed after adding the two together. */
+
+static inline unsigned
+min_align (a, b)
+ unsigned int a, b;
+{
+ return (a | b) & -(a | b);
+}
- Return 1 if we were able to output the constant, otherwise 0. If FORCE is
- non-zero, abort if we can't output the constant. */
+/* Assemble the integer constant X into an object of SIZE bytes. ALIGN is
+ the alignment of the integer in bits. Return 1 if we were able to output
+ the constant, otherwise 0. If FORCE is non-zero, abort if we can't output
+ the constant. */
int
-assemble_integer (x, size, force)
+assemble_integer (x, size, align, force)
rtx x;
- int size;
+ unsigned int size;
+ unsigned int align;
int force;
{
/* First try to use the standard 1, 2, 4, 8, and 16 byte
ASM_OUTPUT... macros. */
- switch (size)
- {
+ if (align >= size * BITS_PER_UNIT)
+ switch (size)
+ {
#ifdef ASM_OUTPUT_CHAR
- case 1:
- ASM_OUTPUT_CHAR (asm_out_file, x);
- return 1;
+ case 1:
+ ASM_OUTPUT_CHAR (asm_out_file, x);
+ return 1;
#endif
-
#ifdef ASM_OUTPUT_SHORT
- case 2:
- ASM_OUTPUT_SHORT (asm_out_file, x);
- return 1;
+ case 2:
+ ASM_OUTPUT_SHORT (asm_out_file, x);
+ return 1;
#endif
-
#ifdef ASM_OUTPUT_INT
- case 4:
- ASM_OUTPUT_INT (asm_out_file, x);
- return 1;
+ case 4:
+ ASM_OUTPUT_INT (asm_out_file, x);
+ return 1;
#endif
-
#ifdef ASM_OUTPUT_DOUBLE_INT
- case 8:
- ASM_OUTPUT_DOUBLE_INT (asm_out_file, x);
- return 1;
+ case 8:
+ ASM_OUTPUT_DOUBLE_INT (asm_out_file, x);
+ return 1;
#endif
-
#ifdef ASM_OUTPUT_QUADRUPLE_INT
- case 16:
- ASM_OUTPUT_QUADRUPLE_INT (asm_out_file, x);
- return 1;
+ case 16:
+ ASM_OUTPUT_QUADRUPLE_INT (asm_out_file, x);
+ return 1;
+#endif
+ }
+ else
+ {
+ const char *asm_op = NULL;
+
+ switch (size)
+ {
+#ifdef UNALIGNED_SHORT_ASM_OP
+ case 2:
+ asm_op = UNALIGNED_SHORT_ASM_OP;
+ break;
+#endif
+#ifdef UNALIGNED_INT_ASM_OP
+ case 4:
+ asm_op = UNALIGNED_INT_ASM_OP;
+ break;
+#endif
+#ifdef UNALIGNED_DOUBLE_INT_ASM_OP
+ case 8:
+ asm_op = UNALIGNED_DOUBLE_INT_ASM_OP;
+ break;
#endif
+ }
+
+ if (asm_op)
+ {
+ fputs (asm_op, asm_out_file);
+ output_addr_const (asm_out_file, x);
+ fputc ('\n', asm_out_file);
+ return 1;
+ }
}
/* If we couldn't do it that way, there are two other possibilities: First,
@@ -1861,24 +1883,22 @@ assemble_integer (x, size, force)
}
#endif
- /* Finally, if SIZE is larger than a single word, try to output the constant
+ /* If SIZE is larger than a single word, try to output the constant
one word at a time. */
if (size > UNITS_PER_WORD)
{
- int i;
enum machine_mode mode
= mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0);
- rtx word;
+ unsigned align2 = min_align (align, BITS_PER_WORD);
+ unsigned int i;
for (i = 0; i < size / UNITS_PER_WORD; i++)
{
- word = operand_subword (x, i, 0, mode);
-
+ rtx word = operand_subword (x, i, 0, mode);
if (word == 0)
break;
-
- if (! assemble_integer (word, UNITS_PER_WORD, 0))
+ if (! assemble_integer (word, UNITS_PER_WORD, align2, 0))
break;
}
@@ -1890,6 +1910,32 @@ assemble_integer (x, size, force)
abort ();
}
+ /* If unaligned, and this is a constant, emit it one byte at a time. */
+ if (align < size * BITS_PER_UNIT)
+ {
+ enum machine_mode omode, imode;
+ unsigned int i;
+
+ omode = mode_for_size (BITS_PER_UNIT, MODE_INT, 0);
+ imode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0);
+
+ for (i = 0; i < size; i++)
+ {
+ rtx byte = simplify_subreg (omode, x, imode, i);
+ if (byte == 0)
+ break;
+ if (! assemble_integer (byte, 1, BITS_PER_UNIT, 0))
+ break;
+ }
+
+ if (i == size)
+ return 1;
+ /* If we output at least one byte and then could not finish,
+ there is no valid way to continue. */
+ if (i > 0)
+ abort ();
+ }
+
if (force)
abort ();
@@ -1953,14 +1999,25 @@ assemble_real_1 (p)
}
void
-assemble_real (d, mode)
+assemble_real (d, mode, align)
REAL_VALUE_TYPE d;
enum machine_mode mode;
+ unsigned int align;
{
struct assemble_real_args args;
args.d = &d;
args.mode = mode;
+ /* We cannot emit unaligned floating point constants. This is slightly
+ complicated in that we don't know what "unaligned" means exactly. */
+#ifdef BIGGEST_FIELD_ALIGNMENT
+ if (align >= BIGGEST_FIELD_ALIGNMENT)
+ ;
+ else
+#endif
+ if (align < GET_MODE_ALIGNMENT (mode))
+ abort ();
+
if (do_float_handler (assemble_real_1, (PTR) &args))
return;
@@ -3280,7 +3337,8 @@ output_constant_def_contents (exp, reloc, labelno)
(TREE_CODE (exp) == STRING_CST
? MAX (TREE_STRING_LENGTH (exp),
int_size_in_bytes (TREE_TYPE (exp)))
- : int_size_in_bytes (TREE_TYPE (exp))));
+ : int_size_in_bytes (TREE_TYPE (exp))),
+ align);
}
@@ -3841,12 +3899,12 @@ output_constant_pool (fnname, fndecl)
abort ();
memcpy ((char *) &u, (char *) &CONST_DOUBLE_LOW (x), sizeof u);
- assemble_real (u.d, pool->mode);
+ assemble_real (u.d, pool->mode, pool->align);
break;
case MODE_INT:
case MODE_PARTIAL_INT:
- assemble_integer (x, GET_MODE_SIZE (pool->mode), 1);
+ assemble_integer (x, GET_MODE_SIZE (pool->mode), pool->align, 1);
break;
default:
@@ -3856,7 +3914,6 @@ output_constant_pool (fnname, fndecl)
#ifdef ASM_OUTPUT_SPECIAL_POOL_ENTRY
done: ;
#endif
-
}
#ifdef ASM_OUTPUT_POOL_EPILOGUE
@@ -4258,12 +4315,15 @@ initializer_constant_valid_p (value, endtype)
There a case in which we would fail to output exactly SIZE bytes:
for a structure constructor that wants to produce more than SIZE bytes.
- But such constructors will never be generated for any possible input. */
+ But such constructors will never be generated for any possible input.
+
+ ALIGN is the alignment of the data in bits. */
void
-output_constant (exp, size)
- register tree exp;
- register int size;
+output_constant (exp, size, align)
+ tree exp;
+ int size;
+ unsigned int align;
{
register enum tree_code code = TREE_CODE (TREE_TYPE (exp));
@@ -4318,7 +4378,7 @@ output_constant (exp, size)
if (! assemble_integer (expand_expr (exp, NULL_RTX, VOIDmode,
EXPAND_INITIALIZER),
- size, 0))
+ size, align, 0))
error ("initializer for integer value is too complicated");
size = 0;
break;
@@ -4328,20 +4388,22 @@ output_constant (exp, size)
error ("initializer for floating value is not a floating constant");
assemble_real (TREE_REAL_CST (exp),
- mode_for_size (size * BITS_PER_UNIT, MODE_FLOAT, 0));
+ mode_for_size (size * BITS_PER_UNIT, MODE_FLOAT, 0),
+ align);
size = 0;
break;
case COMPLEX_TYPE:
- output_constant (TREE_REALPART (exp), size / 2);
- output_constant (TREE_IMAGPART (exp), size / 2);
+ output_constant (TREE_REALPART (exp), size / 2, align);
+ output_constant (TREE_IMAGPART (exp), size / 2,
+ min_align (align, BITS_PER_UNIT * (size / 2)));
size -= (size / 2) * 2;
break;
case ARRAY_TYPE:
if (TREE_CODE (exp) == CONSTRUCTOR)
{
- output_constructor (exp, size);
+ output_constructor (exp, size, align);
return;
}
else if (TREE_CODE (exp) == STRING_CST)
@@ -4364,7 +4426,7 @@ output_constant (exp, size)
case RECORD_TYPE:
case UNION_TYPE:
if (TREE_CODE (exp) == CONSTRUCTOR)
- output_constructor (exp, size);
+ output_constructor (exp, size, align);
else
abort ();
return;
@@ -4373,7 +4435,7 @@ output_constant (exp, size)
if (TREE_CODE (exp) == INTEGER_CST)
assemble_integer (expand_expr (exp, NULL_RTX,
VOIDmode, EXPAND_INITIALIZER),
- size, 1);
+ size, align, 1);
else if (TREE_CODE (exp) == CONSTRUCTOR)
{
unsigned char *buffer = (unsigned char *) alloca (size);
@@ -4434,9 +4496,10 @@ array_size_for_constructor (val)
Generate at least SIZE bytes, padding if necessary. */
static void
-output_constructor (exp, size)
+output_constructor (exp, size, align)
tree exp;
int size;
+ unsigned int align;
{
tree type = TREE_TYPE (exp);
register tree link, field = 0;
@@ -4496,6 +4559,7 @@ output_constructor (exp, size)
HOST_WIDE_INT lo_index = tree_low_cst (TREE_OPERAND (index, 0), 0);
HOST_WIDE_INT hi_index = tree_low_cst (TREE_OPERAND (index, 1), 0);
HOST_WIDE_INT index;
+ unsigned int align2 = min_align (align, fieldsize * BITS_PER_UNIT);
for (index = lo_index; index <= hi_index; index++)
{
@@ -4503,7 +4567,7 @@ output_constructor (exp, size)
if (val == 0)
assemble_zeros (fieldsize);
else
- output_constant (val, fieldsize);
+ output_constant (val, fieldsize, align2);
/* Count its size. */
total_bytes += fieldsize;
@@ -4517,6 +4581,7 @@ output_constructor (exp, size)
/* Since this structure is static,
we know the positions are constant. */
HOST_WIDE_INT pos = field ? int_byte_position (field) : 0;
+ unsigned int align2;
if (index != 0)
pos = (tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (val)), 1)
@@ -4539,13 +4604,9 @@ output_constructor (exp, size)
total_bytes = pos;
}
- else if (field != 0 && DECL_PACKED (field))
- /* Some assemblers automaticallly align a datum according to its
- size if no align directive is specified. The datum, however,
- may be declared with 'packed' attribute, so we have to disable
- such a feature. */
- ASM_OUTPUT_ALIGN (asm_out_file, 0);
-
+ /* Find the alignment of this element. */
+ align2 = min_align (align, BITS_PER_UNIT * pos);
+
/* Determine size this element should occupy. */
if (field)
{
@@ -4581,7 +4642,7 @@ output_constructor (exp, size)
if (val == 0)
assemble_zeros (fieldsize);
else
- output_constant (val, fieldsize);
+ output_constant (val, fieldsize, align2);
/* Count its size. */
total_bytes += fieldsize;