📄 stor-layout.c
字号:
/* 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 modifyit under the terms of the GNU General Public License as published bythe 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 ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU CC; see the file COPYING. If not, write tothe 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;treeget_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. */treevariable_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_modemode_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. */treeround_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. */voidlayout_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 treelayout_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. */ register int var_align = BITS_PER_UNIT; for (field = TYPE_FIELDS (rec); field; field = TREE_CHAIN (field)) { register int desired_align; /* If FIELD is static, then treat it like a separate variable, not really like a structure field. If it is a FUNCTION_DECL, it's a method. In both cases, all we do is lay out the decl, and we do it *after* the record is laid out. */ if (TREE_STATIC (field)) { pending_statics = tree_cons (NULL_TREE, field, pending_statics); continue; } /* Enumerators and enum types which are local to this class need not be laid out. Likewise for initialized constant fields. */ if (TREE_CODE (field) != FIELD_DECL) continue; /* Lay out the field so we know what alignment it needs. For KNOWN_ALIGN, pass the number of bits from start of record or some divisor of it. */ /* For a packed field, use the alignment as specified, disregarding what the type would want. */ if (DECL_PACKED (field)) desired_align = DECL_ALIGN (field); layout_decl (field, var_size ? var_align : const_size); if (! DECL_PACKED (field)) desired_align = DECL_ALIGN (field); /* Some targets (i.e. VMS) limit struct field alignment to a lower boundary than alignment of variables. */#ifdef BIGGEST_FIELD_ALIGNMENT desired_align = MIN (desired_align, BIGGEST_FIELD_ALIGNMENT);#endif /* Record must have at least as much alignment as any field. Otherwise, the alignment of the field within the record is meaningless. */#ifndef PCC_BITFIELD_TYPE_MATTERS record_align = MAX (record_align, desired_align);#else if (PCC_BITFIELD_TYPE_MATTERS && TREE_TYPE (field) != error_mark_node && DECL_BIT_FIELD_TYPE (field) && ! integer_zerop (TYPE_SIZE (TREE_TYPE (field)))) { /* For these machines, a zero-length field does not affect the alignment of the structure as a whole. It does, however, affect the alignment of the next field within the structure. */ if (! integer_zerop (DECL_SIZE (field))) record_align = MAX (record_align, desired_align); else if (! DECL_PACKED (field)) desired_align = TYPE_ALIGN (TREE_TYPE (field)); /* A named bit field of declared type `int' forces the entire structure to have `int' alignment. */ if (DECL_NAME (field) != 0) { int type_align = TYPE_ALIGN (TREE_TYPE (field)); if (maximum_field_alignment != 0) type_align = MIN (type_align, maximum_field_alignment); record_align = MAX (record_align, type_align); } } else record_align = MAX (record_align, desired_align);#endif /* Does this field automatically have alignment it needs by virtue of the fields that precede it and the record's own alignment? */ if (const_size % desired_align != 0 || (var_align % desired_align != 0 && var_size != 0)) { /* No, we need to skip space before this field. Bump the cumulative size to multiple of field alignment. */ if (var_size == 0 || var_align % desired_align == 0) const_size = CEIL (const_size, desired_align) * desired_align; else { if (const_size > 0) var_size = size_binop (PLUS_EXPR, var_size, size_int (const_size)); const_size = 0; var_size = round_up (var_size, desired_align); var_align = MIN (var_align, desired_align); } }#ifdef PCC_BITFIELD_TYPE_MATTERS if (PCC_BITFIELD_TYPE_MATTERS && TREE_CODE (field) == FIELD_DECL && TREE_TYPE (field) != error_mark_node && DECL_BIT_FIELD_TYPE (field) && !DECL_PACKED (field) && !integer_zerop (DECL_SIZE (field))) { int type_align = TYPE_ALIGN (TREE_TYPE (field));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -