Commit 324c9b02 by Olivier Hainque Committed by Olivier Hainque

tree.h (CONSTRUCTOR_BITFIELD_P): True if NODE...

	* tree.h (CONSTRUCTOR_BITFIELD_P): True if NODE, a FIELD_DECL, is
	to be processed as a bitfield for constructor output purposes.
	* output.h (initializer_constant_valid_for_bitfield_p): Declare
	new function.
	* varasm.c (oc_local_state): New type, output_constructor
	local state to support communication with helpers.
	(oc_outer_state): New type, output_constructor outer state of
	relevance in recursive calls.
	(output_constructor_array_range): New output_constructor helper,
	extracted code for an array range element.
	(output_constructor_regular_field): New output_constructor helper,
	extracted code for an element that is not a bitfield.
	(output_constructor_bitfield): New output_constructor helper,
	extracted code for a bitfield element.  Accept an OUTER state
	argument for recursive processing.  Recurse on record or array
	CONSTRUCTOR values, possibly past noop conversions.
	(initializer_constant_valid_for_bitfield_p): New predicate. Whether
	VALUE is a valid constant-valued expression for use in a static
	bit-field initializer.
	(output_constructor): Rework to use helpers. Accept and honor an
	OUTER state argument for recursive calls. Return total size. Be
	prepared for nested constructors initializing bitfields.
	(output_constant): Feed OUTER in calls to output_constructor.

	ada/
	* gcc-interface/utils2.c (gnat_build_constructor): Factor
	out code. Use initializer_constant_valid_for_bitfield_p and
	CONSTRUCTOR_BITFIELD_P for bit-fields.

	testsuite/
	* gnat.dg/oconst[1-6].ad[bs]: New tests. Also support for ...
	* gnat.dg/test_oconst.adb: New test.


Co-Authored-By: Eric Botcazou <ebotcazou@adacore.com>

From-SVN: r148045
parent 0980d7fe
2009-06-01 Olivier Hainque <hainque@adacore.com>
Eric Botcazou <botcazou@adacore.com>
* tree.h (CONSTRUCTOR_BITFIELD_P): True if NODE, a FIELD_DECL, is
to be processed as a bitfield for constructor output purposes.
* output.h (initializer_constant_valid_for_bitfield_p): Declare
new function.
* varasm.c (oc_local_state): New type, output_constructor
local state to support communication with helpers.
(oc_outer_state): New type, output_constructor outer state of
relevance in recursive calls.
(output_constructor_array_range): New output_constructor helper,
extracted code for an array range element.
(output_constructor_regular_field): New output_constructor helper,
extracted code for an element that is not a bitfield.
(output_constructor_bitfield): New output_constructor helper,
extracted code for a bitfield element. Accept an OUTER state
argument for recursive processing. Recurse on record or array
CONSTRUCTOR values, possibly past noop conversions.
(initializer_constant_valid_for_bitfield_p): New predicate. Whether
VALUE is a valid constant-valued expression for use in a static
bit-field initializer.
(output_constructor): Rework to use helpers. Accept and honor an
OUTER state argument for recursive calls. Return total size. Be
prepared for nested constructors initializing bitfields.
(output_constant): Feed OUTER in calls to output_constructor.
2009-06-01 Maxim Kuvyrkov <maxim@codesourcery.com> 2009-06-01 Maxim Kuvyrkov <maxim@codesourcery.com>
* calls.c (emit_library_call_value_1): Don't force_operand for move * calls.c (emit_library_call_value_1): Don't force_operand for move
......
2009-06-01 Olivier Hainque <hainque@adacore.com>
Eric Botcazou <botcazou@adacore.com>
* gcc-interface/utils2.c (gnat_build_constructor): Factor
out code. Use initializer_constant_valid_for_bitfield_p and
CONSTRUCTOR_BITFIELD_P for bit-fields.
2009-05-26 Ian Lance Taylor <iant@google.com> 2009-05-26 Ian Lance Taylor <iant@google.com>
* gcc-interface/Makefile.in (COMPILER): Define. * gcc-interface/Makefile.in (COMPILER): Define.
......
...@@ -1623,34 +1623,35 @@ compare_elmt_bitpos (const PTR rt1, const PTR rt2) ...@@ -1623,34 +1623,35 @@ compare_elmt_bitpos (const PTR rt1, const PTR rt2)
tree tree
gnat_build_constructor (tree type, tree list) gnat_build_constructor (tree type, tree list)
{ {
tree elmt;
int n_elmts;
bool allconstant = (TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST); bool allconstant = (TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST);
bool side_effects = false; bool side_effects = false;
tree result; tree elmt, result;
int n_elmts;
/* Scan the elements to see if they are all constant or if any has side /* Scan the elements to see if they are all constant or if any has side
effects, to let us set global flags on the resulting constructor. Count effects, to let us set global flags on the resulting constructor. Count
the elements along the way for possible sorting purposes below. */ the elements along the way for possible sorting purposes below. */
for (n_elmts = 0, elmt = list; elmt; elmt = TREE_CHAIN (elmt), n_elmts ++) for (n_elmts = 0, elmt = list; elmt; elmt = TREE_CHAIN (elmt), n_elmts ++)
{ {
if (!TREE_CONSTANT (TREE_VALUE (elmt)) tree obj = TREE_PURPOSE (elmt);
tree val = TREE_VALUE (elmt);
/* The predicate must be in keeping with output_constructor. */
if (!TREE_CONSTANT (val)
|| (TREE_CODE (type) == RECORD_TYPE || (TREE_CODE (type) == RECORD_TYPE
&& DECL_BIT_FIELD (TREE_PURPOSE (elmt)) && CONSTRUCTOR_BITFIELD_P (obj)
&& TREE_CODE (TREE_VALUE (elmt)) != INTEGER_CST) && !initializer_constant_valid_for_bitfield_p (val))
|| !initializer_constant_valid_p (TREE_VALUE (elmt), || !initializer_constant_valid_p (val, TREE_TYPE (val)))
TREE_TYPE (TREE_VALUE (elmt))))
allconstant = false; allconstant = false;
if (TREE_SIDE_EFFECTS (TREE_VALUE (elmt))) if (TREE_SIDE_EFFECTS (val))
side_effects = true; side_effects = true;
/* Propagate an NULL_EXPR from the size of the type. We won't ever /* Propagate an NULL_EXPR from the size of the type. We won't ever
be executing the code we generate here in that case, but handle it be executing the code we generate here in that case, but handle it
specially to avoid the compiler blowing up. */ specially to avoid the compiler blowing up. */
if (TREE_CODE (type) == RECORD_TYPE if (TREE_CODE (type) == RECORD_TYPE
&& (0 != (result && (result = contains_null_expr (DECL_SIZE (obj))) != NULL_TREE)
= contains_null_expr (DECL_SIZE (TREE_PURPOSE (elmt))))))
return build1 (NULL_EXPR, type, TREE_OPERAND (result, 0)); return build1 (NULL_EXPR, type, TREE_OPERAND (result, 0));
} }
......
...@@ -303,6 +303,11 @@ extern bool constructor_static_from_elts_p (const_tree); ...@@ -303,6 +303,11 @@ extern bool constructor_static_from_elts_p (const_tree);
arithmetic-combinations of integers. */ arithmetic-combinations of integers. */
extern tree initializer_constant_valid_p (tree, tree); extern tree initializer_constant_valid_p (tree, tree);
/* Return true if VALUE is a valid constant-valued expression
for use in initializing a static bit-field; one that can be
an element of a "constant" initializer. */
extern bool initializer_constant_valid_for_bitfield_p (tree);
/* Output assembler code for constant EXP to FILE, with no label. /* Output assembler code for constant EXP to FILE, with no label.
This includes the pseudo-op such as ".int" or ".byte", and a newline. This includes the pseudo-op such as ".int" or ".byte", and a newline.
Assumes output_addressed_constants has been done on EXP already. Assumes output_addressed_constants has been done on EXP already.
......
2009-06-01 Olivier Hainque <hainque@adacore.com>
Eric Botcazou <botcazou@adacore.com>
* gnat.dg/oconst[1-6].ad[bs]: New tests. Also support for ...
* gnat.dg/test_oconst.adb: New test.
2009-05-31 Basile Starynkevitch <basile@starynkevitch.net> 2009-05-31 Basile Starynkevitch <basile@starynkevitch.net>
......
-- { dg-do compile }
-- { dg-final { scan-assembler-not "elabs" } }
package body OCONST1 is
procedure check (arg : R) is
begin
if arg.u /= 1
or else arg.b.i1 /= 2
or else arg.b.i2 /= 3
or else arg.b.i3 /= 4
then
raise Program_Error;
end if;
end;
end;
package OCONST1 is
type u8 is mod 2**8;
type Base is record
i1 : Integer;
i2 : Integer;
i3 : Integer;
end Record;
type R is record
u : u8;
b : Base;
end record;
for R use record
u at 0 range 0 .. 7;
b at 1 range 0 .. 95; -- BLKmode bitfield
end record;
My_R : constant R := (u=>1, b=>(2, 3, 4));
procedure check (arg : R);
end;
-- { dg-do compile }
-- { dg-final { scan-assembler-not "elabs" } }
package body OCONST2 is
procedure check (arg : R) is
begin
if arg.u /= 1
or else arg.b.i1 /= 2
then
raise Program_Error;
end if;
end;
end;
package OCONST2 is
type u8 is mod 2**8;
type Base is record
i1 : Integer;
end Record;
type R is record
u : u8;
b : Base;
end record;
for R use record
u at 0 range 0 .. 7;
b at 1 range 0 .. 31; -- aligned SImode bitfield
end record;
My_R : constant R := (u=>1, b=>(i1=>2));
procedure check (arg : R);
end;
-- { dg-do compile }
-- { dg-final { scan-assembler-not "elabs" } }
package body OCONST3 is
procedure check (arg : R) is
begin
if arg.u /= 1
or else arg.f /= one
or else arg.b.i1 /= 3
then
raise Program_Error;
end if;
end;
end;
package OCONST3 is
type bit is (zero, one);
type u8 is mod 2**8;
type Base is record
i1 : Integer;
end Record;
type R is record
u : u8;
f : bit;
b : Base;
end record;
for R use record
u at 0 range 0 .. 7;
f at 1 range 0 .. 0;
b at 1 range 1 .. 32; -- unaligned SImode bitfield
end record;
My_R : constant R := (u=>1, f=>one, b=>(i1=>3));
procedure check (arg : R);
end;
-- { dg-do compile }
-- { dg-final { scan-assembler-not "elabs" } }
package body OCONST4 is
procedure check (arg : R) is
begin
if arg.u /= 1
or else arg.d.f1 /= 17
or else arg.d.b.f1 /= one
or else arg.d.b.f2 /= 2
or else arg.d.b.f3 /= 17
or else arg.d.b.f4 /= 42
or else arg.d.f2 /= one
or else arg.d.f3 /= 1
or else arg.d.f4 /= 111
or else arg.d.i1 /= 2
or else arg.d.i2 /= 3
then
raise Program_Error;
end if;
end;
end;
package OCONST4 is
type bit is (zero, one);
type u2 is mod 2**2;
type u5 is mod 2**5;
type u8 is mod 2**8;
type Base is record
f1 : bit;
f2 : u2;
f3 : u5;
f4 : u8;
end record;
for Base use record
f1 at 0 range 0 .. 0;
f2 at 0 range 1 .. 2;
f3 at 0 range 3 .. 7;
f4 at 1 range 0 .. 7;
end record;
type Derived is record
f1 : u5;
b : Base;
f2 : bit;
f3 : u2;
f4 : u8;
i1 : Integer;
i2 : Integer;
end record;
for Derived use record
f1 at 0 range 0 .. 4;
b at 0 range 5 .. 20; -- unaligned HImode bitfield
f2 at 0 range 21 .. 21;
f3 at 0 range 22 .. 23;
f4 at 0 range 24 .. 31;
i1 at 4 range 0 .. 31;
i2 at 8 range 0 .. 31;
end record;
type R is record
u : u8;
d : Derived;
end record;
for R use record
u at 0 range 0 .. 7;
d at 1 range 0 .. 95; -- BLKmode bitfield
end record;
My_R : constant R := (u=>1,
d=>(f1=>17,
b=>(f1=>one,
f2=>2,
f3=>17,
f4=>42),
f2=>one,
f3=>1,
f4=>111,
i1=>2,
i2=>3));
procedure check (arg : R);
end;
-- { dg-do compile }
-- { dg-final { scan-assembler-not "elabs" } }
package body OCONST5 is
procedure Check (Arg : R; Bit : U1) is
begin
if Arg.Bit /= Bit
or else Arg.Agg.A /= 3
or else Arg.Agg.B /= 7
then
raise Program_Error;
end if;
end;
end;
package OCONST5 is
type u1 is mod 2**1;
type u8 is mod 2**8;
type HI_Record is record
A, B : U8;
end record;
pragma Suppress_Initialization (HI_Record);
type R is record
Bit : U1;
Agg : HI_Record;
end record;
pragma Suppress_Initialization (R);
for R use record
Bit at 0 range 0 .. 0;
Agg at 0 range 1 .. 16;
end record;
My_R0 : R := (Bit => 0, Agg => (A => 3, B => 7));
My_R1 : R := (Bit => 1, Agg => (A => 3, B => 7));
procedure Check (Arg : R; Bit : U1);
end;
-- { dg-do compile }
-- { dg-final { scan-assembler-not "elabs" } }
package OCONST6 is
type Sequence is array (1 .. 1) of Natural;
type Message is record
Data : Sequence;
end record;
for Message'Alignment use 1;
pragma PACK (Message);
ACK : Message := (Data => (others => 1));
end;
-- { dg-do run }
with OCONST1, OCONST2, OCONST3, OCONST4, OCONST5;
procedure Test_Oconst is
begin
OCONST1.check (OCONST1.My_R);
OCONST2.check (OCONST2.My_R);
OCONST3.check (OCONST3.My_R);
OCONST4.check (OCONST4.My_R);
OCONST5.check (OCONST5.My_R0, 0);
OCONST5.check (OCONST5.My_R1, 1);
end;
...@@ -1502,6 +1502,11 @@ struct GTY(()) tree_vec { ...@@ -1502,6 +1502,11 @@ struct GTY(()) tree_vec {
_ce___->value = VALUE; \ _ce___->value = VALUE; \
} while (0) } while (0)
/* True if NODE, a FIELD_DECL, is to be processed as a bitfield for
constructor output purposes. */
#define CONSTRUCTOR_BITFIELD_P(NODE) \
(DECL_BIT_FIELD (FIELD_DECL_CHECK (NODE)) && DECL_MODE (NODE) != BLKmode)
/* A single element of a CONSTRUCTOR. VALUE holds the actual value of the /* A single element of a CONSTRUCTOR. VALUE holds the actual value of the
element. INDEX can optionally design the position of VALUE: in arrays, element. INDEX can optionally design the position of VALUE: in arrays,
it is the index where VALUE has to be placed; in structures, it is the it is the index where VALUE has to be placed; in structures, it is the
......
...@@ -114,7 +114,6 @@ static void output_constant_def_contents (rtx); ...@@ -114,7 +114,6 @@ static void output_constant_def_contents (rtx);
static void output_addressed_constants (tree); static void output_addressed_constants (tree);
static unsigned HOST_WIDE_INT array_size_for_constructor (tree); static unsigned HOST_WIDE_INT array_size_for_constructor (tree);
static unsigned min_align (unsigned, unsigned); static unsigned min_align (unsigned, unsigned);
static void output_constructor (tree, unsigned HOST_WIDE_INT, unsigned int);
static void globalize_decl (tree); static void globalize_decl (tree);
#ifdef BSS_SECTION_ASM_OP #ifdef BSS_SECTION_ASM_OP
#ifdef ASM_OUTPUT_BSS #ifdef ASM_OUTPUT_BSS
...@@ -4366,6 +4365,55 @@ initializer_constant_valid_p (tree value, tree endtype) ...@@ -4366,6 +4365,55 @@ initializer_constant_valid_p (tree value, tree endtype)
return 0; return 0;
} }
/* Return true if VALUE is a valid constant-valued expression
for use in initializing a static bit-field; one that can be
an element of a "constant" initializer. */
bool
initializer_constant_valid_for_bitfield_p (tree value)
{
/* For bitfields we support integer constants or possibly nested aggregates
of such. */
switch (TREE_CODE (value))
{
case CONSTRUCTOR:
{
unsigned HOST_WIDE_INT idx;
tree elt;
FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (value), idx, elt)
if (!initializer_constant_valid_for_bitfield_p (elt))
return false;
return true;
}
case INTEGER_CST:
return true;
case VIEW_CONVERT_EXPR:
case NON_LVALUE_EXPR:
return
initializer_constant_valid_for_bitfield_p (TREE_OPERAND (value, 0));
default:
break;
}
return false;
}
/* output_constructor outer state of relevance in recursive calls, typically
for nested aggregate bitfields. */
typedef struct {
unsigned int bit_offset; /* current position in ... */
int byte; /* ... the outer byte buffer. */
} oc_outer_state;
static unsigned HOST_WIDE_INT
output_constructor (tree, unsigned HOST_WIDE_INT, unsigned int,
oc_outer_state *);
/* Output assembler code for constant EXP to FILE, with no label. /* Output assembler code for constant EXP to FILE, with no label.
This includes the pseudo-op such as ".int" or ".byte", and a newline. This includes the pseudo-op such as ".int" or ".byte", and a newline.
Assumes output_addressed_constants has been done on EXP already. Assumes output_addressed_constants has been done on EXP already.
...@@ -4504,7 +4552,7 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align) ...@@ -4504,7 +4552,7 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align)
switch (TREE_CODE (exp)) switch (TREE_CODE (exp))
{ {
case CONSTRUCTOR: case CONSTRUCTOR:
output_constructor (exp, size, align); output_constructor (exp, size, align, NULL);
return; return;
case STRING_CST: case STRING_CST:
thissize = MIN ((unsigned HOST_WIDE_INT)TREE_STRING_LENGTH (exp), thissize = MIN ((unsigned HOST_WIDE_INT)TREE_STRING_LENGTH (exp),
...@@ -4542,7 +4590,7 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align) ...@@ -4542,7 +4590,7 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align)
case RECORD_TYPE: case RECORD_TYPE:
case UNION_TYPE: case UNION_TYPE:
gcc_assert (TREE_CODE (exp) == CONSTRUCTOR); gcc_assert (TREE_CODE (exp) == CONSTRUCTOR);
output_constructor (exp, size, align); output_constructor (exp, size, align, NULL);
return; return;
case ERROR_MARK: case ERROR_MARK:
...@@ -4598,316 +4646,462 @@ array_size_for_constructor (tree val) ...@@ -4598,316 +4646,462 @@ array_size_for_constructor (tree val)
return tree_low_cst (i, 1); return tree_low_cst (i, 1);
} }
/* Subroutine of output_constant, used for CONSTRUCTORs (aggregate constants). /* Other datastructures + helpers for output_constructor. */
Generate at least SIZE bytes, padding if necessary. */
static void /* output_constructor local state to support interaction with helpers. */
output_constructor (tree exp, unsigned HOST_WIDE_INT size,
unsigned int align)
{
tree type = TREE_TYPE (exp);
tree field = 0;
tree min_index = 0;
/* Number of bytes output or skipped so far.
In other words, current position within the constructor. */
HOST_WIDE_INT total_bytes = 0;
/* Nonzero means BYTE contains part of a byte, to be output. */
int byte_buffer_in_use = 0;
int byte = 0;
unsigned HOST_WIDE_INT cnt;
constructor_elt *ce;
gcc_assert (HOST_BITS_PER_WIDE_INT >= BITS_PER_UNIT); typedef struct {
if (TREE_CODE (type) == RECORD_TYPE) /* Received arguments. */
field = TYPE_FIELDS (type); tree exp; /* Constructor expression. */
unsigned HOST_WIDE_INT size; /* # bytes to output - pad if necessary. */
unsigned int align; /* Known initial alignment. */
if (TREE_CODE (type) == ARRAY_TYPE /* Constructor expression data. */
&& TYPE_DOMAIN (type) != 0) tree type; /* Expression type. */
min_index = TYPE_MIN_VALUE (TYPE_DOMAIN (type)); tree field; /* Current field decl in a record. */
tree min_index; /* Lower bound if specified for an array. */
/* As LINK goes through the elements of the constant, /* Output processing state. */
FIELD goes through the structure fields, if the constant is a structure. HOST_WIDE_INT total_bytes; /* # bytes output so far / current position. */
if the constant is a union, then we override this, bool byte_buffer_in_use; /* Whether byte ... */
by getting the field from the TREE_LIST element. int byte; /* ... contains part of a bitfield byte yet to
But the constant could also be an array. Then FIELD is zero. be output. */
There is always a maximum of one element in the chain LINK for unions int last_relative_index; /* Implicit or explicit index of the last
(even if the initializer in a source program incorrectly contains array element output within a bitfield. */
more one). */ /* Current element. */
for (cnt = 0; tree val; /* Current element value. */
VEC_iterate (constructor_elt, CONSTRUCTOR_ELTS (exp), cnt, ce); tree index; /* Current element index. */
cnt++, field = field ? TREE_CHAIN (field) : 0)
} oc_local_state;
/* Helper for output_constructor. From the current LOCAL state, output a
RANGE_EXPR element. */
static void
output_constructor_array_range (oc_local_state *local)
{
unsigned HOST_WIDE_INT fieldsize
= int_size_in_bytes (TREE_TYPE (local->type));
HOST_WIDE_INT lo_index
= tree_low_cst (TREE_OPERAND (local->index, 0), 0);
HOST_WIDE_INT hi_index
= tree_low_cst (TREE_OPERAND (local->index, 1), 0);
HOST_WIDE_INT index;
unsigned int align2
= min_align (local->align, fieldsize * BITS_PER_UNIT);
for (index = lo_index; index <= hi_index; index++)
{ {
tree val = ce->value; /* Output the element's initial value. */
tree index = 0; if (local->val == NULL_TREE)
assemble_zeros (fieldsize);
else
output_constant (local->val, fieldsize, align2);
/* Count its size. */
local->total_bytes += fieldsize;
}
}
/* The element in a union constructor specifies the proper field /* Helper for output_constructor. From the current LOCAL state, output a
or index. */ field element that is not true bitfield or part of an outer one. */
if ((TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE
|| TREE_CODE (type) == QUAL_UNION_TYPE)
&& ce->index != 0)
field = ce->index;
else if (TREE_CODE (type) == ARRAY_TYPE) static void
index = ce->index; output_constructor_regular_field (oc_local_state *local)
{
/* Field size and position. Since this structure is static, we know the
positions are constant. */
unsigned HOST_WIDE_INT fieldsize;
HOST_WIDE_INT fieldpos;
#ifdef ASM_COMMENT_START unsigned int align2;
if (field && flag_verbose_asm)
fprintf (asm_out_file, "%s %s:\n",
ASM_COMMENT_START,
DECL_NAME (field)
? IDENTIFIER_POINTER (DECL_NAME (field))
: "<anonymous>");
#endif
/* Eliminate the marker that makes a cast not be an lvalue. */ if (local->index != NULL_TREE)
if (val != 0) fieldpos = (tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (local->val)), 1)
STRIP_NOPS (val); * ((tree_low_cst (local->index, 0)
- tree_low_cst (local->min_index, 0))));
else if (local->field != NULL_TREE)
fieldpos = int_byte_position (local->field);
else
fieldpos = 0;
/* Output any buffered-up bit-fields preceding this element. */
if (local->byte_buffer_in_use)
{
assemble_integer (GEN_INT (local->byte), 1, BITS_PER_UNIT, 1);
local->total_bytes++;
local->byte_buffer_in_use = false;
}
/* Advance to offset of this element.
Note no alignment needed in an array, since that is guaranteed
if each element has the proper size. */
if ((local->field != NULL_TREE || local->index != NULL_TREE)
&& fieldpos != local->total_bytes)
{
gcc_assert (fieldpos >= local->total_bytes);
assemble_zeros (fieldpos - local->total_bytes);
local->total_bytes = fieldpos;
}
/* Find the alignment of this element. */
align2 = min_align (local->align, BITS_PER_UNIT * fieldpos);
if (index && TREE_CODE (index) == RANGE_EXPR) /* Determine size this element should occupy. */
if (local->field)
{
fieldsize = 0;
/* If this is an array with an unspecified upper bound,
the initializer determines the size. */
/* ??? This ought to only checked if DECL_SIZE_UNIT is NULL,
but we cannot do this until the deprecated support for
initializing zero-length array members is removed. */
if (TREE_CODE (TREE_TYPE (local->field)) == ARRAY_TYPE
&& TYPE_DOMAIN (TREE_TYPE (local->field))
&& ! TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (local->field))))
{ {
unsigned HOST_WIDE_INT fieldsize fieldsize = array_size_for_constructor (local->val);
= int_size_in_bytes (TREE_TYPE (type)); /* Given a non-empty initialization, this field had
HOST_WIDE_INT lo_index = tree_low_cst (TREE_OPERAND (index, 0), 0); better be last. */
HOST_WIDE_INT hi_index = tree_low_cst (TREE_OPERAND (index, 1), 0); gcc_assert (!fieldsize || !TREE_CHAIN (local->field));
HOST_WIDE_INT index;
unsigned int align2 = min_align (align, fieldsize * BITS_PER_UNIT);
for (index = lo_index; index <= hi_index; index++)
{
/* Output the element's initial value. */
if (val == 0)
assemble_zeros (fieldsize);
else
output_constant (val, fieldsize, align2);
/* Count its size. */
total_bytes += fieldsize;
}
} }
else if (field == 0 || !DECL_BIT_FIELD (field)) else if (DECL_SIZE_UNIT (local->field))
{ {
/* An element that is not a bit-field. */ /* ??? This can't be right. If the decl size overflows
a host integer we will silently emit no data. */
if (host_integerp (DECL_SIZE_UNIT (local->field), 1))
fieldsize = tree_low_cst (DECL_SIZE_UNIT (local->field), 1);
}
}
else
fieldsize = int_size_in_bytes (TREE_TYPE (local->type));
/* Output the element's initial value. */
if (local->val == NULL_TREE)
assemble_zeros (fieldsize);
else
output_constant (local->val, fieldsize, align2);
unsigned HOST_WIDE_INT fieldsize; /* Count its size. */
/* Since this structure is static, local->total_bytes += fieldsize;
we know the positions are constant. */ }
HOST_WIDE_INT pos = field ? int_byte_position (field) : 0;
unsigned int align2;
if (index != 0) /* Helper for output_constructor. From the current LOCAL and OUTER states,
pos = (tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (val)), 1) output an element that is a true bitfield or part of an outer one. */
* (tree_low_cst (index, 0) - tree_low_cst (min_index, 0)));
/* Output any buffered-up bit-fields preceding this element. */ static void
if (byte_buffer_in_use) output_constructor_bitfield (oc_local_state *local, oc_outer_state *outer)
{ {
assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1); /* Bit size of this element. */
total_bytes++; HOST_WIDE_INT ebitsize
byte_buffer_in_use = 0; = (local->field
} ? tree_low_cst (DECL_SIZE (local->field), 1)
: tree_low_cst (TYPE_SIZE (TREE_TYPE (local->type)), 1));
/* Advance to offset of this element.
Note no alignment needed in an array, since that is guaranteed /* Relative index of this element if this is an array component. */
if each element has the proper size. */ HOST_WIDE_INT relative_index
if ((field != 0 || index != 0) && pos != total_bytes) = (!local->field
{ ? (local->index
gcc_assert (pos >= total_bytes); ? (tree_low_cst (local->index, 0)
assemble_zeros (pos - total_bytes); - tree_low_cst (local->min_index, 0))
total_bytes = pos; : local->last_relative_index + 1)
} : 0);
/* Bit position of this element from the start of the containing
constructor. */
HOST_WIDE_INT constructor_relative_ebitpos
= (local->field
? int_bit_position (local->field)
: ebitsize * relative_index);
/* Bit position of this element from the start of a possibly ongoing
outer byte buffer. */
HOST_WIDE_INT byte_relative_ebitpos
= ((outer ? outer->bit_offset : 0) + constructor_relative_ebitpos);
/* From the start of a possibly ongoing outer byte buffer, offsets to
the first bit of this element and to the first bit past the end of
this element. */
HOST_WIDE_INT next_offset = byte_relative_ebitpos;
HOST_WIDE_INT end_offset = byte_relative_ebitpos + ebitsize;
local->last_relative_index = relative_index;
if (local->val == NULL_TREE)
local->val = integer_zero_node;
while (TREE_CODE (local->val) == VIEW_CONVERT_EXPR
|| TREE_CODE (local->val) == NON_LVALUE_EXPR)
local->val = TREE_OPERAND (local->val, 0);
if (TREE_CODE (local->val) != INTEGER_CST
&& TREE_CODE (local->val) != CONSTRUCTOR)
{
error ("invalid initial value for member %qE", DECL_NAME (local->field));
return;
}
/* Find the alignment of this element. */ /* If this field does not start in this (or, next) byte,
align2 = min_align (align, BITS_PER_UNIT * pos); skip some bytes. */
if (next_offset / BITS_PER_UNIT != local->total_bytes)
{
/* Output remnant of any bit field in previous bytes. */
if (local->byte_buffer_in_use)
{
assemble_integer (GEN_INT (local->byte), 1, BITS_PER_UNIT, 1);
local->total_bytes++;
local->byte_buffer_in_use = false;
}
/* If still not at proper byte, advance to there. */
if (next_offset / BITS_PER_UNIT != local->total_bytes)
{
gcc_assert (next_offset / BITS_PER_UNIT >= local->total_bytes);
assemble_zeros (next_offset / BITS_PER_UNIT - local->total_bytes);
local->total_bytes = next_offset / BITS_PER_UNIT;
}
}
/* Set up the buffer if necessary. */
if (!local->byte_buffer_in_use)
{
local->byte = 0;
if (ebitsize > 0)
local->byte_buffer_in_use = true;
}
/* If this is nested constructor, recurse passing the bit offset and the
pending data, then retrieve the new pending data afterwards. */
if (TREE_CODE (local->val) == CONSTRUCTOR)
{
oc_outer_state output_state;
/* Determine size this element should occupy. */ output_state.bit_offset = next_offset % BITS_PER_UNIT;
if (field) output_state.byte = local->byte;
local->total_bytes
+= output_constructor (local->val, 0, 0, &output_state);
local->byte = output_state.byte;
return;
}
/* Otherwise, we must split the element into pieces that fall within
separate bytes, and combine each byte with previous or following
bit-fields. */
while (next_offset < end_offset)
{
int this_time;
int shift;
HOST_WIDE_INT value;
HOST_WIDE_INT next_byte = next_offset / BITS_PER_UNIT;
HOST_WIDE_INT next_bit = next_offset % BITS_PER_UNIT;
/* Advance from byte to byte
within this element when necessary. */
while (next_byte != local->total_bytes)
{
assemble_integer (GEN_INT (local->byte), 1, BITS_PER_UNIT, 1);
local->total_bytes++;
local->byte = 0;
}
/* Number of bits we can process at once
(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. We can
only select bits from the LOW or HIGH part
not from both. */
if (shift < HOST_BITS_PER_WIDE_INT
&& shift + this_time > HOST_BITS_PER_WIDE_INT)
{ {
fieldsize = 0; this_time = shift + this_time - HOST_BITS_PER_WIDE_INT;
shift = HOST_BITS_PER_WIDE_INT;
/* If this is an array with an unspecified upper bound,
the initializer determines the size. */
/* ??? This ought to only checked if DECL_SIZE_UNIT is NULL,
but we cannot do this until the deprecated support for
initializing zero-length array members is removed. */
if (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE
&& TYPE_DOMAIN (TREE_TYPE (field))
&& ! TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (field))))
{
fieldsize = array_size_for_constructor (val);
/* Given a non-empty initialization, this field had
better be last. */
gcc_assert (!fieldsize || !TREE_CHAIN (field));
}
else if (DECL_SIZE_UNIT (field))
{
/* ??? This can't be right. If the decl size overflows
a host integer we will silently emit no data. */
if (host_integerp (DECL_SIZE_UNIT (field), 1))
fieldsize = tree_low_cst (DECL_SIZE_UNIT (field), 1);
}
} }
/* Now get the bits from the appropriate constant word. */
if (shift < HOST_BITS_PER_WIDE_INT)
value = TREE_INT_CST_LOW (local->val);
else else
fieldsize = int_size_in_bytes (TREE_TYPE (type)); {
gcc_assert (shift < 2 * HOST_BITS_PER_WIDE_INT);
/* Output the element's initial value. */ value = TREE_INT_CST_HIGH (local->val);
if (val == 0) shift -= HOST_BITS_PER_WIDE_INT;
assemble_zeros (fieldsize); }
else
output_constant (val, fieldsize, align2); /* Get the result. This works only when:
1 <= this_time <= HOST_BITS_PER_WIDE_INT. */
/* Count its size. */ local->byte |= (((value >> shift)
total_bytes += fieldsize; & (((HOST_WIDE_INT) 2 << (this_time - 1)) - 1))
<< (BITS_PER_UNIT - this_time - next_bit));
} }
else if (val != 0 && TREE_CODE (val) != INTEGER_CST)
error ("invalid initial value for member %qE",
DECL_NAME (field));
else else
{ {
/* Element that is a bit-field. */ /* 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 - byte_relative_ebitpos;
/* Don't try to take a bunch of bits that cross
the word boundary in the INTEGER_CST. We can
only select bits from the LOW or HIGH part
not from both. */
if (shift < HOST_BITS_PER_WIDE_INT
&& shift + this_time > HOST_BITS_PER_WIDE_INT)
this_time = (HOST_BITS_PER_WIDE_INT - shift);
/* Now get the bits from the appropriate constant word. */
if (shift < HOST_BITS_PER_WIDE_INT)
value = TREE_INT_CST_LOW (local->val);
else
{
gcc_assert (shift < 2 * HOST_BITS_PER_WIDE_INT);
value = TREE_INT_CST_HIGH (local->val);
shift -= HOST_BITS_PER_WIDE_INT;
}
/* Get the result. This works only when:
1 <= this_time <= HOST_BITS_PER_WIDE_INT. */
local->byte |= (((value >> shift)
& (((HOST_WIDE_INT) 2 << (this_time - 1)) - 1))
<< next_bit);
}
next_offset += this_time;
local->byte_buffer_in_use = true;
}
}
HOST_WIDE_INT next_offset = int_bit_position (field); /* Subroutine of output_constant, used for CONSTRUCTORs (aggregate constants).
HOST_WIDE_INT end_offset Generate at least SIZE bytes, padding if necessary. OUTER designates the
= (next_offset + tree_low_cst (DECL_SIZE (field), 1)); caller output state of relevance in recursive invocations. */
if (val == 0) static unsigned HOST_WIDE_INT
val = integer_zero_node; output_constructor (tree exp, unsigned HOST_WIDE_INT size,
unsigned int align, oc_outer_state * outer)
{
unsigned HOST_WIDE_INT cnt;
constructor_elt *ce;
/* If this field does not start in this (or, next) byte, oc_local_state local;
skip some bytes. */
if (next_offset / BITS_PER_UNIT != total_bytes)
{
/* Output remnant of any bit field in previous bytes. */
if (byte_buffer_in_use)
{
assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1);
total_bytes++;
byte_buffer_in_use = 0;
}
/* If still not at proper byte, advance to there. */ /* Setup our local state to communicate with helpers. */
if (next_offset / BITS_PER_UNIT != total_bytes) local.exp = exp;
{ local.size = size;
gcc_assert (next_offset / BITS_PER_UNIT >= total_bytes); local.align = align;
assemble_zeros (next_offset / BITS_PER_UNIT - total_bytes);
total_bytes = next_offset / BITS_PER_UNIT;
}
}
if (! byte_buffer_in_use) local.total_bytes = 0;
byte = 0; local.byte_buffer_in_use = outer != NULL;
local.byte = outer ? outer->byte : 0;
/* We must split the element into pieces that fall within local.type = TREE_TYPE (exp);
separate bytes, and combine each byte with previous or
following bit-fields. */
/* next_offset is the offset n fbits from the beginning of local.last_relative_index = -1;
the structure to the next bit of this element to be processed.
end_offset is the offset of the first bit past the end of
this element. */
while (next_offset < end_offset)
{
int this_time;
int shift;
HOST_WIDE_INT value;
HOST_WIDE_INT next_byte = next_offset / BITS_PER_UNIT;
HOST_WIDE_INT next_bit = next_offset % BITS_PER_UNIT;
/* Advance from byte to byte
within this element when necessary. */
while (next_byte != total_bytes)
{
assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1);
total_bytes++;
byte = 0;
}
/* Number of bits we can process at once local.min_index = NULL_TREE;
(all part of the same byte). */ if (TREE_CODE (local.type) == ARRAY_TYPE
this_time = MIN (end_offset - next_offset, && TYPE_DOMAIN (local.type) != NULL_TREE)
BITS_PER_UNIT - next_bit); local.min_index = TYPE_MIN_VALUE (TYPE_DOMAIN (local.type));
if (BYTES_BIG_ENDIAN)
{ gcc_assert (HOST_BITS_PER_WIDE_INT >= BITS_PER_UNIT);
/* 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. We can
only select bits from the LOW or HIGH part
not from both. */
if (shift < HOST_BITS_PER_WIDE_INT
&& shift + this_time > HOST_BITS_PER_WIDE_INT)
{
this_time = shift + this_time - HOST_BITS_PER_WIDE_INT;
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
{
gcc_assert (shift < 2 * HOST_BITS_PER_WIDE_INT);
value = TREE_INT_CST_HIGH (val);
shift -= HOST_BITS_PER_WIDE_INT;
}
/* Get the result. This works only when:
1 <= this_time <= HOST_BITS_PER_WIDE_INT. */
byte |= (((value >> shift)
& (((HOST_WIDE_INT) 2 << (this_time - 1)) - 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 - int_bit_position (field);
/* Don't try to take a bunch of bits that cross
the word boundary in the INTEGER_CST. We can
only select bits from the LOW or HIGH part
not from both. */
if (shift < HOST_BITS_PER_WIDE_INT
&& shift + this_time > HOST_BITS_PER_WIDE_INT)
this_time = (HOST_BITS_PER_WIDE_INT - shift);
/* Now get the bits from the appropriate constant word. */
if (shift < HOST_BITS_PER_WIDE_INT)
value = TREE_INT_CST_LOW (val);
else
{
gcc_assert (shift < 2 * HOST_BITS_PER_WIDE_INT);
value = TREE_INT_CST_HIGH (val);
shift -= HOST_BITS_PER_WIDE_INT;
}
/* Get the result. This works only when:
1 <= this_time <= HOST_BITS_PER_WIDE_INT. */
byte |= (((value >> shift)
& (((HOST_WIDE_INT) 2 << (this_time - 1)) - 1))
<< next_bit);
}
next_offset += this_time; /* As CE goes through the elements of the constant, FIELD goes through the
byte_buffer_in_use = 1; structure fields if the constant is a structure. If the constant is a
} union, we override this by getting the field from the TREE_LIST element.
} But the constant could also be an array. Then FIELD is zero.
}
if (byte_buffer_in_use) There is always a maximum of one element in the chain LINK for unions
(even if the initializer in a source program incorrectly contains
more one). */
local.field = NULL_TREE;
if (TREE_CODE (local.type) == RECORD_TYPE)
local.field = TYPE_FIELDS (local.type);
for (cnt = 0;
VEC_iterate (constructor_elt, CONSTRUCTOR_ELTS (exp), cnt, ce);
cnt++, local.field = local.field ? TREE_CHAIN (local.field) : 0)
{ {
assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1); local.val = ce->value;
total_bytes++; local.index = NULL_TREE;
/* The element in a union constructor specifies the proper field
or index. */
if ((TREE_CODE (local.type) == RECORD_TYPE
|| TREE_CODE (local.type) == UNION_TYPE
|| TREE_CODE (local.type) == QUAL_UNION_TYPE)
&& ce->index != NULL_TREE)
local.field = ce->index;
else if (TREE_CODE (local.type) == ARRAY_TYPE)
local.index = ce->index;
#ifdef ASM_COMMENT_START
if (local.field && flag_verbose_asm)
fprintf (asm_out_file, "%s %s:\n",
ASM_COMMENT_START,
DECL_NAME (local.field)
? IDENTIFIER_POINTER (DECL_NAME (local.field))
: "<anonymous>");
#endif
/* Eliminate the marker that makes a cast not be an lvalue. */
if (local.val != NULL_TREE)
STRIP_NOPS (local.val);
/* Output the current element, using the appropriate helper ... */
/* For an array slice not part of an outer bitfield. */
if (!outer
&& local.index != NULL_TREE
&& TREE_CODE (local.index) == RANGE_EXPR)
output_constructor_array_range (&local);
/* For a field that is neither a true bitfield nor part of an outer one,
known to be at least byte aligned and multiple-of-bytes long. */
else if (!outer
&& (local.field == NULL_TREE
|| !CONSTRUCTOR_BITFIELD_P (local.field)))
output_constructor_regular_field (&local);
/* For a true bitfield or part of an outer one. */
else
output_constructor_bitfield (&local, outer);
} }
if ((unsigned HOST_WIDE_INT)total_bytes < size) /* If we are not at toplevel, save the pending data for our caller.
assemble_zeros (size - total_bytes); Otherwise output the pending data and padding zeros as needed. */
if (outer)
outer->byte = local.byte;
else
{
if (local.byte_buffer_in_use)
{
assemble_integer (GEN_INT (local.byte), 1, BITS_PER_UNIT, 1);
local.total_bytes++;
}
if ((unsigned HOST_WIDE_INT)local.total_bytes < local.size)
{
assemble_zeros (local.size - local.total_bytes);
local.total_bytes = local.size;
}
}
return local.total_bytes;
} }
/* Mark DECL as weak. */ /* Mark DECL as weak. */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment