home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fresh Fish 7
/
FreshFishVol7.bin
/
bbs
/
gnu
/
gcc-2.3.3-src.lha
/
GNU
/
src
/
amiga
/
gcc-2.3.3
/
stor-layout.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-02-06
|
35KB
|
1,126 lines
/* C-compiler utilities for types and variables storage layout
Copyright (C) 1987, 1988, 1992 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "config.h"
#include <stdio.h>
#include "tree.h"
#include "function.h"
#define CEIL(x,y) (((x) + (y) - 1) / (y))
/* Data type for the expressions representing sizes of data types.
It is the first integer type laid out.
In C, this is int. */
tree sizetype;
/* An integer constant with value 0 whose type is sizetype. */
tree size_zero_node;
/* An integer constant with value 1 whose type is sizetype. */
tree size_one_node;
/* If nonzero, this is an upper limit on alignment of structure fields.
The value is measured in bits. */
int maximum_field_alignment;
#define GET_MODE_ALIGNMENT(MODE) \
MIN (BIGGEST_ALIGNMENT, \
MAX (1, (GET_MODE_UNIT_SIZE (MODE) * BITS_PER_UNIT)))
/* SAVE_EXPRs for sizes of types and decls, waiting to be expanded. */
static tree pending_sizes;
/* Nonzero means cannot safely call expand_expr now,
so put variable sizes onto `pending_sizes' instead. */
int immediate_size_expand;
tree
get_pending_sizes ()
{
tree chain = pending_sizes;
tree t;
/* Put each SAVE_EXPR into the current function. */
for (t = chain; t; t = TREE_CHAIN (t))
SAVE_EXPR_CONTEXT (TREE_VALUE (t)) = current_function_decl;
pending_sizes = 0;
return chain;
}
/* Given a size SIZE that isn't constant, return a SAVE_EXPR
to serve as the actual size-expression for a type or decl. */
tree
variable_size (size)
tree size;
{
size = save_expr (size);
if (global_bindings_p ())
{
error ("variable-size type declared outside of any function");
return size_int (1);
}
if (immediate_size_expand)
expand_expr (size, NULL_PTR, VOIDmode, 0);
else
pending_sizes = tree_cons (NULL_TREE, size, pending_sizes);
return size;
}
#ifndef MAX_FIXED_MODE_SIZE
#define MAX_FIXED_MODE_SIZE GET_MODE_BITSIZE (DImode)
#endif
/* Return the machine mode to use for a nonscalar of SIZE bits.
The mode must be in class CLASS, and have exactly that many bits.
If LIMIT is nonzero, modes of wider than MAX_FIXED_MODE_SIZE will not
be used. */
enum machine_mode
mode_for_size (size, class, limit)
unsigned int size;
enum mode_class class;
int limit;
{
register enum machine_mode mode;
if (limit && size > MAX_FIXED_MODE_SIZE)
return BLKmode;
/* Get the last mode which has this size, in the specified class. */
for (mode = GET_CLASS_NARROWEST_MODE (class); mode != VOIDmode;
mode = GET_MODE_WIDER_MODE (mode))
if (GET_MODE_BITSIZE (mode) == size)
return mode;
return BLKmode;
}
/* Return the value of VALUE, rounded up to a multiple of DIVISOR. */
tree
round_up (value, divisor)
tree value;
int divisor;
{
return size_binop (MULT_EXPR,
size_binop (CEIL_DIV_EXPR, value, size_int (divisor)),
size_int (divisor));
}
/* Set the size, mode and alignment of a ..._DECL node.
TYPE_DECL does need this for C++.
Note that LABEL_DECL and CONST_DECL nodes do not need this,
and FUNCTION_DECL nodes have them set up in a special (and simple) way.
Don't call layout_decl for them.
KNOWN_ALIGN is the amount of alignment we can assume this
decl has with no special effort. It is relevant only for FIELD_DECLs
and depends on the previous fields.
All that matters about KNOWN_ALIGN is which powers of 2 divide it.
If KNOWN_ALIGN is 0, it means, "as much alignment as you like":
the record will be aligned to suit. */
void
layout_decl (decl, known_align)
tree decl;
unsigned known_align;
{
register tree type = TREE_TYPE (decl);
register enum tree_code code = TREE_CODE (decl);
int spec_size = DECL_FIELD_SIZE (decl);
if (code == CONST_DECL)
return;
if (code != VAR_DECL && code != PARM_DECL && code != RESULT_DECL
&& code != FIELD_DECL && code != TYPE_DECL)
abort ();
if (type == error_mark_node)
{
type = void_type_node;
spec_size = 0;
}
/* Usually the size and mode come from the data type without change. */
DECL_MODE (decl) = TYPE_MODE (type);
DECL_SIZE (decl) = TYPE_SIZE (type);
TREE_UNSIGNED (decl) = TREE_UNSIGNED (type);
if (code == FIELD_DECL && DECL_BIT_FIELD (decl))
{
/* This is a bit-field. We don't know how to handle
them except for integers and enums, and front end should
never generate them otherwise. */
if (! (TREE_CODE (type) == INTEGER_TYPE
|| TREE_CODE (type) == ENUMERAL_TYPE))
abort ();
if (spec_size == 0 && DECL_NAME (decl) != 0)
abort ();
/* Size is specified number of bits. */
DECL_SIZE (decl) = size_int (spec_size);
}
/* Force alignment required for the data type.
But if the decl itself wants greater alignment, don't override that.
Likewise, if the decl is packed, don't override it. */
else if (DECL_ALIGN (decl) == 0
|| (! DECL_PACKED (decl) && TYPE_ALIGN (type) > DECL_ALIGN (decl)))
DECL_ALIGN (decl) = TYPE_ALIGN (type);
/* See if we can use an ordinary integer mode for a bit-field. */
/* Conditions are: a fixed size that is correct for another mode
and occupying a complete byte or bytes on proper boundary. */
if (code == FIELD_DECL)
{
DECL_BIT_FIELD_TYPE (decl) = DECL_BIT_FIELD (decl) ? type : 0;
if (maximum_field_alignment != 0)
DECL_ALIGN (decl) = MIN (DECL_ALIGN (decl), maximum_field_alignment);
}
if (DECL_BIT_FIELD (decl)
&& TYPE_SIZE (type) != 0
&& TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST)
{
register enum machine_mode xmode
= mode_for_size (TREE_INT_CST_LOW (DECL_SIZE (decl)), MODE_INT, 1);
if (xmode != BLKmode
&& known_align % GET_MODE_ALIGNMENT (xmode) == 0)
{
DECL_ALIGN (decl) = MAX (GET_MODE_ALIGNMENT (xmode),
DECL_ALIGN (decl));
DECL_MODE (decl) = xmode;
DECL_SIZE (decl) = size_int (GET_MODE_BITSIZE (xmode));
/* This no longer needs to be accessed as a bit field. */
DECL_BIT_FIELD (decl) = 0;
}
}
/* Evaluate nonconstant size only once, either now or as soon as safe. */
if (DECL_SIZE (decl) != 0 && TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST)
DECL_SIZE (decl) = variable_size (DECL_SIZE (decl));
}
/* Lay out a RECORD_TYPE type (a C struct).
This means laying out the fields, determining their positions,
and computing the overall size and required alignment of the record.
Note that if you set the TYPE_ALIGN before calling this
then the struct is aligned to at least that boundary.
If the type has basetypes, you must call layout_basetypes
before calling this function.
The return value is a list of static members of the record.
They still need to be laid out. */
static tree
layout_record (rec)
tree rec;
{
register tree field;
#ifdef STRUCTURE_SIZE_BOUNDARY
unsigned record_align = MAX (STRUCTURE_SIZE_BOUNDARY, TYPE_ALIGN (rec));
#else
unsigned record_align = MAX (BITS_PER_UNIT, TYPE_ALIGN (rec));
#endif
/* These must be laid out *after* the record is. */
tree pending_statics = NULL_TREE;
/* Record size so far is CONST_SIZE + VAR_SIZE bits,
where CONST_SIZE is an integer
and VAR_SIZE is a tree expression.
If VAR_SIZE is null, the size is just CONST_SIZE.
Naturally we try to avoid using VAR_SIZE. */
register int const_size = 0;
register tree var_size = 0;
/* Once we start using VAR_SIZE, this is the maximum alignment
that we know VAR_SIZE has. */