diff options
Diffstat (limited to 'gcc-4.2.1-5666.3/gcc/cfgexpand.c')
-rw-r--r-- | gcc-4.2.1-5666.3/gcc/cfgexpand.c | 1736 |
1 files changed, 0 insertions, 1736 deletions
diff --git a/gcc-4.2.1-5666.3/gcc/cfgexpand.c b/gcc-4.2.1-5666.3/gcc/cfgexpand.c deleted file mode 100644 index 4622167cd..000000000 --- a/gcc-4.2.1-5666.3/gcc/cfgexpand.c +++ /dev/null @@ -1,1736 +0,0 @@ -/* A pass for lowering trees to RTL. - Copyright (C) 2004, 2005 Free Software Foundation, Inc. - -This file is part of GCC. - -GCC 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. - -GCC 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 GCC; see the file COPYING. If not, write to -the Free Software Foundation, 51 Franklin Street, Fifth Floor, -Boston, MA 02110-1301, USA. */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "tm.h" -#include "tree.h" -#include "rtl.h" -#include "tm_p.h" -#include "basic-block.h" -#include "function.h" -#include "expr.h" -#include "langhooks.h" -#include "tree-flow.h" -#include "timevar.h" -#include "tree-dump.h" -#include "tree-pass.h" -#include "except.h" -#include "flags.h" -#include "diagnostic.h" -#include "toplev.h" -#include "debug.h" -#include "params.h" - -/* Verify that there is exactly single jump instruction since last and attach - REG_BR_PROB note specifying probability. - ??? We really ought to pass the probability down to RTL expanders and let it - re-distribute it when the conditional expands into multiple conditionals. - This is however difficult to do. */ -static void -add_reg_br_prob_note (rtx last, int probability) -{ - if (profile_status == PROFILE_ABSENT) - return; - for (last = NEXT_INSN (last); last && NEXT_INSN (last); last = NEXT_INSN (last)) - if (JUMP_P (last)) - { - /* It is common to emit condjump-around-jump sequence when we don't know - how to reverse the conditional. Special case this. */ - if (!any_condjump_p (last) - || !JUMP_P (NEXT_INSN (last)) - || !simplejump_p (NEXT_INSN (last)) - || !NEXT_INSN (NEXT_INSN (last)) - || !BARRIER_P (NEXT_INSN (NEXT_INSN (last))) - || !NEXT_INSN (NEXT_INSN (NEXT_INSN (last))) - || !LABEL_P (NEXT_INSN (NEXT_INSN (NEXT_INSN (last)))) - || NEXT_INSN (NEXT_INSN (NEXT_INSN (NEXT_INSN (last))))) - goto failed; - gcc_assert (!find_reg_note (last, REG_BR_PROB, 0)); - REG_NOTES (last) - = gen_rtx_EXPR_LIST (REG_BR_PROB, - GEN_INT (REG_BR_PROB_BASE - probability), - REG_NOTES (last)); - return; - } - if (!last || !JUMP_P (last) || !any_condjump_p (last)) - goto failed; - gcc_assert (!find_reg_note (last, REG_BR_PROB, 0)); - REG_NOTES (last) - = gen_rtx_EXPR_LIST (REG_BR_PROB, - GEN_INT (probability), REG_NOTES (last)); - return; -failed: - if (dump_file) - fprintf (dump_file, "Failed to add probability note\n"); -} - - -#ifndef LOCAL_ALIGNMENT -#define LOCAL_ALIGNMENT(TYPE, ALIGNMENT) ALIGNMENT -#endif - -#ifndef STACK_ALIGNMENT_NEEDED -#define STACK_ALIGNMENT_NEEDED 1 -#endif - - -/* This structure holds data relevant to one variable that will be - placed in a stack slot. */ -struct stack_var -{ - /* The Variable. */ - tree decl; - - /* The offset of the variable. During partitioning, this is the - offset relative to the partition. After partitioning, this - is relative to the stack frame. */ - HOST_WIDE_INT offset; - - /* Initially, the size of the variable. Later, the size of the partition, - if this variable becomes it's partition's representative. */ - HOST_WIDE_INT size; - - /* The *byte* alignment required for this variable. Or as, with the - size, the alignment for this partition. */ - unsigned int alignb; - - /* The partition representative. */ - size_t representative; - - /* The next stack variable in the partition, or EOC. */ - size_t next; -}; - -#define EOC ((size_t)-1) - -/* We have an array of such objects while deciding allocation. */ -static struct stack_var *stack_vars; -static size_t stack_vars_alloc; -static size_t stack_vars_num; - -/* An array of indicies such that stack_vars[stack_vars_sorted[i]].size - is non-decreasing. */ -static size_t *stack_vars_sorted; - -/* We have an interference graph between such objects. This graph - is lower triangular. */ -static bool *stack_vars_conflict; -static size_t stack_vars_conflict_alloc; - -/* The phase of the stack frame. This is the known misalignment of - virtual_stack_vars_rtx from PREFERRED_STACK_BOUNDARY. That is, - (frame_offset+frame_phase) % PREFERRED_STACK_BOUNDARY == 0. */ -static int frame_phase; - -/* Used during expand_used_vars to remember if we saw any decls for - which we'd like to enable stack smashing protection. */ -static bool has_protected_decls; - -/* Used during expand_used_vars. Remember if we say a character buffer - smaller than our cutoff threshold. Used for -Wstack-protector. */ -static bool has_short_buffer; - -/* Discover the byte alignment to use for DECL. Ignore alignment - we can't do with expected alignment of the stack boundary. */ - -static unsigned int -get_decl_align_unit (tree decl) -{ - unsigned int align; - - align = DECL_ALIGN (decl); - align = LOCAL_ALIGNMENT (TREE_TYPE (decl), align); - if (align > PREFERRED_STACK_BOUNDARY) - align = PREFERRED_STACK_BOUNDARY; - if (cfun->stack_alignment_needed < align) - cfun->stack_alignment_needed = align; - - return align / BITS_PER_UNIT; -} - -/* Allocate SIZE bytes at byte alignment ALIGN from the stack frame. - Return the frame offset. */ - -static HOST_WIDE_INT -alloc_stack_frame_space (HOST_WIDE_INT size, HOST_WIDE_INT align) -{ - HOST_WIDE_INT offset, new_frame_offset; - - new_frame_offset = frame_offset; - if (FRAME_GROWS_DOWNWARD) - { - new_frame_offset -= size + frame_phase; - new_frame_offset &= -align; - new_frame_offset += frame_phase; - offset = new_frame_offset; - } - else - { - new_frame_offset -= frame_phase; - new_frame_offset += align - 1; - new_frame_offset &= -align; - new_frame_offset += frame_phase; - offset = new_frame_offset; - new_frame_offset += size; - } - frame_offset = new_frame_offset; - - if (frame_offset_overflow (frame_offset, cfun->decl)) - frame_offset = offset = 0; - - return offset; -} - -/* Accumulate DECL into STACK_VARS. */ - -static void -add_stack_var (tree decl) -{ - if (stack_vars_num >= stack_vars_alloc) - { - if (stack_vars_alloc) - stack_vars_alloc = stack_vars_alloc * 3 / 2; - else - stack_vars_alloc = 32; - stack_vars - = XRESIZEVEC (struct stack_var, stack_vars, stack_vars_alloc); - } - stack_vars[stack_vars_num].decl = decl; - stack_vars[stack_vars_num].offset = 0; - stack_vars[stack_vars_num].size = tree_low_cst (DECL_SIZE_UNIT (decl), 1); - stack_vars[stack_vars_num].alignb = get_decl_align_unit (decl); - - /* All variables are initially in their own partition. */ - stack_vars[stack_vars_num].representative = stack_vars_num; - stack_vars[stack_vars_num].next = EOC; - - /* Ensure that this decl doesn't get put onto the list twice. */ - SET_DECL_RTL (decl, pc_rtx); - - stack_vars_num++; -} - -/* Compute the linear index of a lower-triangular coordinate (I, J). */ - -static size_t -triangular_index (size_t i, size_t j) -{ - if (i < j) - { - size_t t; - t = i, i = j, j = t; - } - return (i * (i + 1)) / 2 + j; -} - -/* Ensure that STACK_VARS_CONFLICT is large enough for N objects. */ - -static void -resize_stack_vars_conflict (size_t n) -{ - size_t size = triangular_index (n-1, n-1) + 1; - - if (size <= stack_vars_conflict_alloc) - return; - - stack_vars_conflict = XRESIZEVEC (bool, stack_vars_conflict, size); - memset (stack_vars_conflict + stack_vars_conflict_alloc, 0, - (size - stack_vars_conflict_alloc) * sizeof (bool)); - stack_vars_conflict_alloc = size; -} - -/* Make the decls associated with luid's X and Y conflict. */ - -static void -add_stack_var_conflict (size_t x, size_t y) -{ - size_t index = triangular_index (x, y); - gcc_assert (index < stack_vars_conflict_alloc); - stack_vars_conflict[index] = true; -} - -/* Check whether the decls associated with luid's X and Y conflict. */ - -static bool -stack_var_conflict_p (size_t x, size_t y) -{ - size_t index = triangular_index (x, y); - gcc_assert (index < stack_vars_conflict_alloc); - return stack_vars_conflict[index]; -} - -/* Returns true if TYPE is or contains a union type. */ - -static bool -aggregate_contains_union_type (tree type) -{ - tree field; - - if (TREE_CODE (type) == UNION_TYPE - || TREE_CODE (type) == QUAL_UNION_TYPE) - return true; - if (TREE_CODE (type) == ARRAY_TYPE) - return aggregate_contains_union_type (TREE_TYPE (type)); - if (TREE_CODE (type) != RECORD_TYPE) - return false; - - for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) - if (TREE_CODE (field) == FIELD_DECL) - if (aggregate_contains_union_type (TREE_TYPE (field))) - return true; - - return false; -} - -/* A subroutine of expand_used_vars. If two variables X and Y have alias - sets that do not conflict, then do add a conflict for these variables - in the interference graph. We also need to make sure to add conflicts - for union containing structures. Else RTL alias analysis comes along - and due to type based aliasing rules decides that for two overlapping - union temporaries { short s; int i; } accesses to the same mem through - different types may not alias and happily reorders stores across - life-time boundaries of the temporaries (See PR25654). - We also have to mind MEM_IN_STRUCT_P and MEM_SCALAR_P. */ - -static void -add_alias_set_conflicts (void) -{ - size_t i, j, n = stack_vars_num; - - for (i = 0; i < n; ++i) - { - tree type_i = TREE_TYPE (stack_vars[i].decl); - bool aggr_i = AGGREGATE_TYPE_P (type_i); - bool contains_union; - - contains_union = aggregate_contains_union_type (type_i); - for (j = 0; j < i; ++j) - { - tree type_j = TREE_TYPE (stack_vars[j].decl); - bool aggr_j = AGGREGATE_TYPE_P (type_j); - if (aggr_i != aggr_j - /* Either the objects conflict by means of type based - aliasing rules, or we need to add a conflict. */ - || !objects_must_conflict_p (type_i, type_j) - /* In case the types do not conflict ensure that access - to elements will conflict. In case of unions we have - to be careful as type based aliasing rules may say - access to the same memory does not conflict. So play - safe and add a conflict in this case. */ - || contains_union) - add_stack_var_conflict (i, j); - } - } -} - -/* A subroutine of partition_stack_vars. A comparison function for qsort, - sorting an array of indicies by the size of the object. */ - -static int -stack_var_size_cmp (const void *a, const void *b) -{ - HOST_WIDE_INT sa = stack_vars[*(const size_t *)a].size; - HOST_WIDE_INT sb = stack_vars[*(const size_t *)b].size; - unsigned int uida = DECL_UID (stack_vars[*(const size_t *)a].decl); - unsigned int uidb = DECL_UID (stack_vars[*(const size_t *)b].decl); - - if (sa < sb) - return -1; - if (sa > sb) - return 1; - /* For stack variables of the same size use the uid of the decl - to make the sort stable. */ - if (uida < uidb) - return -1; - if (uida > uidb) - return 1; - return 0; -} - -/* A subroutine of partition_stack_vars. The UNION portion of a UNION/FIND - partitioning algorithm. Partitions A and B are known to be non-conflicting. - Merge them into a single partition A. - - At the same time, add OFFSET to all variables in partition B. At the end - of the partitioning process we've have a nice block easy to lay out within - the stack frame. */ - -static void -union_stack_vars (size_t a, size_t b, HOST_WIDE_INT offset) -{ - size_t i, last; - - /* Update each element of partition B with the given offset, - and merge them into partition A. */ - for (last = i = b; i != EOC; last = i, i = stack_vars[i].next) - { - stack_vars[i].offset += offset; - stack_vars[i].representative = a; - } - stack_vars[last].next = stack_vars[a].next; - stack_vars[a].next = b; - - /* Update the required alignment of partition A to account for B. */ - if (stack_vars[a].alignb < stack_vars[b].alignb) - stack_vars[a].alignb = stack_vars[b].alignb; - - /* Update the interference graph and merge the conflicts. */ - for (last = stack_vars_num, i = 0; i < last; ++i) - if (stack_var_conflict_p (b, i)) - add_stack_var_conflict (a, i); -} - -/* A subroutine of expand_used_vars. Binpack the variables into - partitions constrained by the interference graph. The overall - algorithm used is as follows: - - Sort the objects by size. - For each object A { - S = size(A) - O = 0 - loop { - Look for the largest non-conflicting object B with size <= S. - UNION (A, B) - offset(B) = O - O += size(B) - S -= size(B) - } - } -*/ - -static void -partition_stack_vars (void) -{ - size_t si, sj, n = stack_vars_num; - - stack_vars_sorted = XNEWVEC (size_t, stack_vars_num); - for (si = 0; si < n; ++si) - stack_vars_sorted[si] = si; - - if (n == 1) - return; - - qsort (stack_vars_sorted, n, sizeof (size_t), stack_var_size_cmp); - - /* Special case: detect when all variables conflict, and thus we can't - do anything during the partitioning loop. It isn't uncommon (with - C code at least) to declare all variables at the top of the function, - and if we're not inlining, then all variables will be in the same scope. - Take advantage of very fast libc routines for this scan. */ - gcc_assert (sizeof(bool) == sizeof(char)); - if (memchr (stack_vars_conflict, false, stack_vars_conflict_alloc) == NULL) - return; - - for (si = 0; si < n; ++si) - { - size_t i = stack_vars_sorted[si]; - HOST_WIDE_INT isize = stack_vars[i].size; - HOST_WIDE_INT offset = 0; - - for (sj = si; sj-- > 0; ) - { - size_t j = stack_vars_sorted[sj]; - HOST_WIDE_INT jsize = stack_vars[j].size; - unsigned int jalign = stack_vars[j].alignb; - - /* Ignore objects that aren't partition representatives. */ - if (stack_vars[j].representative != j) - continue; - - /* Ignore objects too large for the remaining space. */ - if (isize < jsize) - continue; - - /* Ignore conflicting objects. */ - if (stack_var_conflict_p (i, j)) - continue; - - /* Refine the remaining space check to include alignment. */ - if (offset & (jalign - 1)) - { - HOST_WIDE_INT toff = offset; - toff += jalign - 1; - toff &= -(HOST_WIDE_INT)jalign; - if (isize - (toff - offset) < jsize) - continue; - - isize -= toff - offset; - offset = toff; - } - - /* UNION the objects, placing J at OFFSET. */ - union_stack_vars (i, j, offset); - - isize -= jsize; - if (isize == 0) - break; - } - } -} - -/* A debugging aid for expand_used_vars. Dump the generated partitions. */ - -static void -dump_stack_var_partition (void) -{ - size_t si, i, j, n = stack_vars_num; - - for (si = 0; si < n; ++si) - { - i = stack_vars_sorted[si]; - - /* Skip variables that aren't partition representatives, for now. */ - if (stack_vars[i].representative != i) - continue; - - fprintf (dump_file, "Partition %lu: size " HOST_WIDE_INT_PRINT_DEC - " align %u\n", (unsigned long) i, stack_vars[i].size, - stack_vars[i].alignb); - - for (j = i; j != EOC; j = stack_vars[j].next) - { - fputc ('\t', dump_file); - print_generic_expr (dump_file, stack_vars[j].decl, dump_flags); - fprintf (dump_file, ", offset " HOST_WIDE_INT_PRINT_DEC "\n", - stack_vars[i].offset); - } - } -} - -/* Assign rtl to DECL at frame offset OFFSET. */ - -static void -expand_one_stack_var_at (tree decl, HOST_WIDE_INT offset) -{ - HOST_WIDE_INT align; - rtx x; - - /* If this fails, we've overflowed the stack frame. Error nicely? */ - gcc_assert (offset == trunc_int_for_mode (offset, Pmode)); - - x = plus_constant (virtual_stack_vars_rtx, offset); - x = gen_rtx_MEM (DECL_MODE (decl), x); - - /* Set alignment we actually gave this decl. */ - offset -= frame_phase; - align = offset & -offset; - align *= BITS_PER_UNIT; - if (align > STACK_BOUNDARY || align == 0) - align = STACK_BOUNDARY; - DECL_ALIGN (decl) = align; - DECL_USER_ALIGN (decl) = 0; - - set_mem_attributes (x, decl, true); - SET_DECL_RTL (decl, x); -} - -/* A subroutine of expand_used_vars. Give each partition representative - a unique location within the stack frame. Update each partition member - with that location. */ - -static void -expand_stack_vars (bool (*pred) (tree)) -{ - size_t si, i, j, n = stack_vars_num; - - for (si = 0; si < n; ++si) - { - HOST_WIDE_INT offset; - - i = stack_vars_sorted[si]; - - /* Skip variables that aren't partition representatives, for now. */ - if (stack_vars[i].representative != i) - continue; - - /* Skip variables that have already had rtl assigned. See also - add_stack_var where we perpetrate this pc_rtx hack. */ - if (DECL_RTL (stack_vars[i].decl) != pc_rtx) - continue; - - /* Check the predicate to see whether this variable should be - allocated in this pass. */ - if (pred && !pred (stack_vars[i].decl)) - continue; - - offset = alloc_stack_frame_space (stack_vars[i].size, - stack_vars[i].alignb); - - /* Create rtl for each variable based on their location within the - partition. */ - for (j = i; j != EOC; j = stack_vars[j].next) - expand_one_stack_var_at (stack_vars[j].decl, - stack_vars[j].offset + offset); - } -} - -/* A subroutine of expand_one_var. Called to immediately assign rtl - to a variable to be allocated in the stack frame. */ - -static void -expand_one_stack_var (tree var) -{ - HOST_WIDE_INT size, offset, align; - - size = tree_low_cst (DECL_SIZE_UNIT (var), 1); - align = get_decl_align_unit (var); - offset = alloc_stack_frame_space (size, align); - - expand_one_stack_var_at (var, offset); -} - -/* A subroutine of expand_one_var. Called to assign rtl - to a TREE_STATIC VAR_DECL. */ - -static void -expand_one_static_var (tree var) -{ - /* In unit-at-a-time all the static variables are expanded at the end - of compilation process. */ - if (flag_unit_at_a_time) - return; - /* If this is an inlined copy of a static local variable, - look up the original. */ - var = DECL_ORIGIN (var); - - /* If we've already processed this variable because of that, do nothing. */ - if (TREE_ASM_WRITTEN (var)) - return; - - /* Give the front end a chance to do whatever. In practice, this is - resolving duplicate names for IMA in C. */ - if (lang_hooks.expand_decl (var)) - return; - - /* Otherwise, just emit the variable. */ - rest_of_decl_compilation (var, 0, 0); -} - -/* A subroutine of expand_one_var. Called to assign rtl to a VAR_DECL - that will reside in a hard register. */ - -static void -expand_one_hard_reg_var (tree var) -{ - rest_of_decl_compilation (var, 0, 0); -} - -/* A subroutine of expand_one_var. Called to assign rtl to a VAR_DECL - that will reside in a pseudo register. */ - -static void -expand_one_register_var (tree var) -{ - tree type = TREE_TYPE (var); - int unsignedp = TYPE_UNSIGNED (type); - enum machine_mode reg_mode - = promote_mode (type, DECL_MODE (var), &unsignedp, 0); - rtx x = gen_reg_rtx (reg_mode); - - SET_DECL_RTL (var, x); - - /* Note if the object is a user variable. */ - if (!DECL_ARTIFICIAL (var)) - { - mark_user_reg (x); - - /* Trust user variables which have a pointer type to really - be pointers. Do not trust compiler generated temporaries - as our type system is totally busted as it relates to - pointer arithmetic which translates into lots of compiler - generated objects with pointer types, but which are not really - pointers. */ - if (POINTER_TYPE_P (type)) - mark_reg_pointer (x, TYPE_ALIGN (TREE_TYPE (TREE_TYPE (var)))); - } -} - -/* A subroutine of expand_one_var. Called to assign rtl to a VAR_DECL that - has some associated error, e.g. its type is error-mark. We just need - to pick something that won't crash the rest of the compiler. */ - -static void -expand_one_error_var (tree var) -{ - enum machine_mode mode = DECL_MODE (var); - rtx x; - - if (mode == BLKmode) - x = gen_rtx_MEM (BLKmode, const0_rtx); - else if (mode == VOIDmode) - x = const0_rtx; - else - x = gen_reg_rtx (mode); - - SET_DECL_RTL (var, x); -} - -/* A subroutine of expand_one_var. VAR is a variable that will be - allocated to the local stack frame. Return true if we wish to - add VAR to STACK_VARS so that it will be coalesced with other - variables. Return false to allocate VAR immediately. - - This function is used to reduce the number of variables considered - for coalescing, which reduces the size of the quadratic problem. */ - -static bool -defer_stack_allocation (tree var, bool toplevel) -{ - /* If stack protection is enabled, *all* stack variables must be deferred, - so that we can re-order the strings to the top of the frame. */ - if (flag_stack_protect) - return true; - - /* Variables in the outermost scope automatically conflict with - every other variable. The only reason to want to defer them - at all is that, after sorting, we can more efficiently pack - small variables in the stack frame. Continue to defer at -O2. */ - if (toplevel && optimize < 2) - return false; - - /* Without optimization, *most* variables are allocated from the - stack, which makes the quadratic problem large exactly when we - want compilation to proceed as quickly as possible. On the - other hand, we don't want the function's stack frame size to - get completely out of hand. So we avoid adding scalars and - "small" aggregates to the list at all. */ - if (optimize == 0 && tree_low_cst (DECL_SIZE_UNIT (var), 1) < 32) - return false; - - return true; -} - -/* A subroutine of expand_used_vars. Expand one variable according to - its flavor. Variables to be placed on the stack are not actually - expanded yet, merely recorded. */ - -static void -expand_one_var (tree var, bool toplevel) -{ - if (TREE_CODE (var) != VAR_DECL) - lang_hooks.expand_decl (var); - else if (DECL_EXTERNAL (var)) - ; - else if (DECL_HAS_VALUE_EXPR_P (var)) - ; - else if (TREE_STATIC (var)) - expand_one_static_var (var); - else if (DECL_RTL_SET_P (var)) - ; - else if (TREE_TYPE (var) == error_mark_node) - expand_one_error_var (var); - else if (DECL_HARD_REGISTER (var)) - expand_one_hard_reg_var (var); - else if (use_register_for_decl (var)) - expand_one_register_var (var); - else if (defer_stack_allocation (var, toplevel)) - add_stack_var (var); - else - expand_one_stack_var (var); -} - -/* A subroutine of expand_used_vars. Walk down through the BLOCK tree - expanding variables. Those variables that can be put into registers - are allocated pseudos; those that can't are put on the stack. - - TOPLEVEL is true if this is the outermost BLOCK. */ - -static void -expand_used_vars_for_block (tree block, bool toplevel) -{ - size_t i, j, old_sv_num, this_sv_num, new_sv_num; - tree t; - - old_sv_num = toplevel ? 0 : stack_vars_num; - - /* Expand all variables at this level. */ - for (t = BLOCK_VARS (block); t ; t = TREE_CHAIN (t)) - if (TREE_USED (t) - /* Force local static variables to be output when marked by - used attribute. For unit-at-a-time, cgraph code already takes - care of this. */ - || (!flag_unit_at_a_time && TREE_STATIC (t) - && DECL_PRESERVE_P (t))) - expand_one_var (t, toplevel); - - this_sv_num = stack_vars_num; - - /* Expand all variables at containing levels. */ - for (t = BLOCK_SUBBLOCKS (block); t ; t = BLOCK_CHAIN (t)) - expand_used_vars_for_block (t, false); - - /* Since we do not track exact variable lifetimes (which is not even - possible for variables whose address escapes), we mirror the block - tree in the interference graph. Here we cause all variables at this - level, and all sublevels, to conflict. Do make certain that a - variable conflicts with itself. */ - if (old_sv_num < this_sv_num) - { - new_sv_num = stack_vars_num; - resize_stack_vars_conflict (new_sv_num); - - for (i = old_sv_num; i < new_sv_num; ++i) - for (j = i < this_sv_num ? i+1 : this_sv_num; j-- > old_sv_num ;) - add_stack_var_conflict (i, j); - } -} - -/* A subroutine of expand_used_vars. Walk down through the BLOCK tree - and clear TREE_USED on all local variables. */ - -static void -clear_tree_used (tree block) -{ - tree t; - - for (t = BLOCK_VARS (block); t ; t = TREE_CHAIN (t)) - /* if (!TREE_STATIC (t) && !DECL_EXTERNAL (t)) */ - TREE_USED (t) = 0; - - for (t = BLOCK_SUBBLOCKS (block); t ; t = BLOCK_CHAIN (t)) - clear_tree_used (t); -} - -/* Examine TYPE and determine a bit mask of the following features. */ - -#define SPCT_HAS_LARGE_CHAR_ARRAY 1 -#define SPCT_HAS_SMALL_CHAR_ARRAY 2 -#define SPCT_HAS_ARRAY 4 -#define SPCT_HAS_AGGREGATE 8 - -static unsigned int -stack_protect_classify_type (tree type) -{ - unsigned int ret = 0; - tree t; - - switch (TREE_CODE (type)) - { - case ARRAY_TYPE: - t = TYPE_MAIN_VARIANT (TREE_TYPE (type)); - if (t == char_type_node - || t == signed_char_type_node - || t == unsigned_char_type_node) - { - unsigned HOST_WIDE_INT max = PARAM_VALUE (PARAM_SSP_BUFFER_SIZE); - unsigned HOST_WIDE_INT len; - - if (!TYPE_SIZE_UNIT (type) - || !host_integerp (TYPE_SIZE_UNIT (type), 1)) - len = max; - else - len = tree_low_cst (TYPE_SIZE_UNIT (type), 1); - - if (len < max) - ret = SPCT_HAS_SMALL_CHAR_ARRAY | SPCT_HAS_ARRAY; - else - ret = SPCT_HAS_LARGE_CHAR_ARRAY | SPCT_HAS_ARRAY; - } - else - ret = SPCT_HAS_ARRAY; - break; - - case UNION_TYPE: - case QUAL_UNION_TYPE: - case RECORD_TYPE: - ret = SPCT_HAS_AGGREGATE; - for (t = TYPE_FIELDS (type); t ; t = TREE_CHAIN (t)) - if (TREE_CODE (t) == FIELD_DECL) - ret |= stack_protect_classify_type (TREE_TYPE (t)); - break; - - default: - break; - } - - return ret; -} - -/* Return nonzero if DECL should be segregated into the "vulnerable" upper - part of the local stack frame. Remember if we ever return nonzero for - any variable in this function. The return value is the phase number in - which the variable should be allocated. */ - -static int -stack_protect_decl_phase (tree decl) -{ - unsigned int bits = stack_protect_classify_type (TREE_TYPE (decl)); - int ret = 0; - - if (bits & SPCT_HAS_SMALL_CHAR_ARRAY) - has_short_buffer = true; - - if (flag_stack_protect == 2) - { - if ((bits & (SPCT_HAS_SMALL_CHAR_ARRAY | SPCT_HAS_LARGE_CHAR_ARRAY)) - && !(bits & SPCT_HAS_AGGREGATE)) - ret = 1; - else if (bits & SPCT_HAS_ARRAY) - ret = 2; - } - else - ret = (bits & SPCT_HAS_LARGE_CHAR_ARRAY) != 0; - - if (ret) - has_protected_decls = true; - - return ret; -} - -/* Two helper routines that check for phase 1 and phase 2. These are used - as callbacks for expand_stack_vars. */ - -static bool -stack_protect_decl_phase_1 (tree decl) -{ - return stack_protect_decl_phase (decl) == 1; -} - -static bool -stack_protect_decl_phase_2 (tree decl) -{ - return stack_protect_decl_phase (decl) == 2; -} - -/* Ensure that variables in different stack protection phases conflict - so that they are not merged and share the same stack slot. */ - -static void -add_stack_protection_conflicts (void) -{ - size_t i, j, n = stack_vars_num; - unsigned char *phase; - - phase = XNEWVEC (unsigned char, n); - for (i = 0; i < n; ++i) - phase[i] = stack_protect_decl_phase (stack_vars[i].decl); - - for (i = 0; i < n; ++i) - { - unsigned char ph_i = phase[i]; - for (j = 0; j < i; ++j) - if (ph_i != phase[j]) - add_stack_var_conflict (i, j); - } - - XDELETEVEC (phase); -} - -/* Create a decl for the guard at the top of the stack frame. */ - -static void -create_stack_guard (void) -{ - tree guard = build_decl (VAR_DECL, NULL, ptr_type_node); - TREE_THIS_VOLATILE (guard) = 1; - TREE_USED (guard) = 1; - expand_one_stack_var (guard); - cfun->stack_protect_guard = guard; -} - -/* Expand all variables used in the function. */ - -static void -expand_used_vars (void) -{ - tree t, outer_block = DECL_INITIAL (current_function_decl); - - /* Compute the phase of the stack frame for this function. */ - { - int align = PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT; - int off = STARTING_FRAME_OFFSET % align; - frame_phase = off ? align - off : 0; - } - - /* Set TREE_USED on all variables in the unexpanded_var_list. */ - for (t = cfun->unexpanded_var_list; t; t = TREE_CHAIN (t)) - TREE_USED (TREE_VALUE (t)) = 1; - - /* Clear TREE_USED on all variables associated with a block scope. */ - clear_tree_used (outer_block); - - /* Initialize local stack smashing state. */ - has_protected_decls = false; - has_short_buffer = false; - - /* At this point all variables on the unexpanded_var_list with TREE_USED - set are not associated with any block scope. Lay them out. */ - for (t = cfun->unexpanded_var_list; t; t = TREE_CHAIN (t)) - { - tree var = TREE_VALUE (t); - bool expand_now = false; - - /* We didn't set a block for static or extern because it's hard - to tell the difference between a global variable (re)declared - in a local scope, and one that's really declared there to - begin with. And it doesn't really matter much, since we're - not giving them stack space. Expand them now. */ - if (TREE_STATIC (var) || DECL_EXTERNAL (var)) - expand_now = true; - - /* Any variable that could have been hoisted into an SSA_NAME - will have been propagated anywhere the optimizers chose, - i.e. not confined to their original block. Allocate them - as if they were defined in the outermost scope. */ - else if (is_gimple_reg (var)) - expand_now = true; - - /* If the variable is not associated with any block, then it - was created by the optimizers, and could be live anywhere - in the function. */ - else if (TREE_USED (var)) - expand_now = true; - - /* Finally, mark all variables on the list as used. We'll use - this in a moment when we expand those associated with scopes. */ - TREE_USED (var) = 1; - - if (expand_now) - expand_one_var (var, true); - } - cfun->unexpanded_var_list = NULL_TREE; - - /* At this point, all variables within the block tree with TREE_USED - set are actually used by the optimized function. Lay them out. */ - expand_used_vars_for_block (outer_block, true); - - if (stack_vars_num > 0) - { - /* Due to the way alias sets work, no variables with non-conflicting - alias sets may be assigned the same address. Add conflicts to - reflect this. */ - add_alias_set_conflicts (); - - /* If stack protection is enabled, we don't share space between - vulnerable data and non-vulnerable data. */ - if (flag_stack_protect) - add_stack_protection_conflicts (); - - /* Now that we have collected all stack variables, and have computed a - minimal interference graph, attempt to save some stack space. */ - partition_stack_vars (); - if (dump_file) - dump_stack_var_partition (); - } - - /* There are several conditions under which we should create a - stack guard: protect-all, alloca used, protected decls present. */ - /* APPLE LOCAL begin CW asm */ - /* Don't create a guard for iasm functions. */ - if ((flag_stack_protect == 2 - || (flag_stack_protect - && (current_function_calls_alloca || has_protected_decls))) - && !cfun->iasm_asm_function) - create_stack_guard (); - /* APPLE LOCAL end CW asm */ - - /* Assign rtl to each variable based on these partitions. */ - if (stack_vars_num > 0) - { - /* Reorder decls to be protected by iterating over the variables - array multiple times, and allocating out of each phase in turn. */ - /* ??? We could probably integrate this into the qsort we did - earlier, such that we naturally see these variables first, - and thus naturally allocate things in the right order. */ - if (has_protected_decls) - { - /* Phase 1 contains only character arrays. */ - expand_stack_vars (stack_protect_decl_phase_1); - - /* Phase 2 contains other kinds of arrays. */ - if (flag_stack_protect == 2) - expand_stack_vars (stack_protect_decl_phase_2); - } - - expand_stack_vars (NULL); - - /* Free up stack variable graph data. */ - XDELETEVEC (stack_vars); - XDELETEVEC (stack_vars_sorted); - XDELETEVEC (stack_vars_conflict); - stack_vars = NULL; - stack_vars_alloc = stack_vars_num = 0; - stack_vars_conflict = NULL; - stack_vars_conflict_alloc = 0; - } - - /* If the target requires that FRAME_OFFSET be aligned, do it. */ - if (STACK_ALIGNMENT_NEEDED) - { - HOST_WIDE_INT align = PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT; - if (!FRAME_GROWS_DOWNWARD) - frame_offset += align - 1; - frame_offset &= -align; - } -} - - -/* If we need to produce a detailed dump, print the tree representation - for STMT to the dump file. SINCE is the last RTX after which the RTL - generated for STMT should have been appended. */ - -static void -maybe_dump_rtl_for_tree_stmt (tree stmt, rtx since) -{ - if (dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, "\n;; "); - print_generic_expr (dump_file, stmt, TDF_SLIM); - fprintf (dump_file, "\n"); - - print_rtl (dump_file, since ? NEXT_INSN (since) : since); - } -} - -/* A subroutine of expand_gimple_basic_block. Expand one COND_EXPR. - Returns a new basic block if we've terminated the current basic - block and created a new one. */ - -static basic_block -expand_gimple_cond_expr (basic_block bb, tree stmt) -{ - basic_block new_bb, dest; - edge new_edge; - edge true_edge; - edge false_edge; - tree pred = COND_EXPR_COND (stmt); - tree then_exp = COND_EXPR_THEN (stmt); - tree else_exp = COND_EXPR_ELSE (stmt); - rtx last2, last; - - last2 = last = get_last_insn (); - - extract_true_false_edges_from_block (bb, &true_edge, &false_edge); - if (EXPR_LOCUS (stmt)) - { - emit_line_note (*(EXPR_LOCUS (stmt))); - record_block_change (TREE_BLOCK (stmt)); - } - - /* These flags have no purpose in RTL land. */ - true_edge->flags &= ~EDGE_TRUE_VALUE; - false_edge->flags &= ~EDGE_FALSE_VALUE; - - /* We can either have a pure conditional jump with one fallthru edge or - two-way jump that needs to be decomposed into two basic blocks. */ - if (TREE_CODE (then_exp) == GOTO_EXPR && IS_EMPTY_STMT (else_exp)) - { - jumpif (pred, label_rtx (GOTO_DESTINATION (then_exp))); - add_reg_br_prob_note (last, true_edge->probability); - maybe_dump_rtl_for_tree_stmt (stmt, last); - if (EXPR_LOCUS (then_exp)) - emit_line_note (*(EXPR_LOCUS (then_exp))); - return NULL; - } - if (TREE_CODE (else_exp) == GOTO_EXPR && IS_EMPTY_STMT (then_exp)) - { - jumpifnot (pred, label_rtx (GOTO_DESTINATION (else_exp))); - add_reg_br_prob_note (last, false_edge->probability); - maybe_dump_rtl_for_tree_stmt (stmt, last); - if (EXPR_LOCUS (else_exp)) - emit_line_note (*(EXPR_LOCUS (else_exp))); - return NULL; - } - gcc_assert (TREE_CODE (then_exp) == GOTO_EXPR - && TREE_CODE (else_exp) == GOTO_EXPR); - - jumpif (pred, label_rtx (GOTO_DESTINATION (then_exp))); - add_reg_br_prob_note (last, true_edge->probability); - last = get_last_insn (); - expand_expr (else_exp, const0_rtx, VOIDmode, 0); - - BB_END (bb) = last; - if (BARRIER_P (BB_END (bb))) - BB_END (bb) = PREV_INSN (BB_END (bb)); - update_bb_for_insn (bb); - - new_bb = create_basic_block (NEXT_INSN (last), get_last_insn (), bb); - dest = false_edge->dest; - redirect_edge_succ (false_edge, new_bb); - false_edge->flags |= EDGE_FALLTHRU; - new_bb->count = false_edge->count; - new_bb->frequency = EDGE_FREQUENCY (false_edge); - new_edge = make_edge (new_bb, dest, 0); - new_edge->probability = REG_BR_PROB_BASE; - new_edge->count = new_bb->count; - if (BARRIER_P (BB_END (new_bb))) - BB_END (new_bb) = PREV_INSN (BB_END (new_bb)); - update_bb_for_insn (new_bb); - - maybe_dump_rtl_for_tree_stmt (stmt, last2); - - if (EXPR_LOCUS (else_exp)) - emit_line_note (*(EXPR_LOCUS (else_exp))); - - return new_bb; -} - -/* A subroutine of expand_gimple_basic_block. Expand one CALL_EXPR - that has CALL_EXPR_TAILCALL set. Returns non-null if we actually - generated a tail call (something that might be denied by the ABI - rules governing the call; see calls.c). - - Sets CAN_FALLTHRU if we generated a *conditional* tail call, and - can still reach the rest of BB. The case here is __builtin_sqrt, - where the NaN result goes through the external function (with a - tailcall) and the normal result happens via a sqrt instruction. */ - -static basic_block -expand_gimple_tailcall (basic_block bb, tree stmt, bool *can_fallthru) -{ - rtx last2, last; - edge e; - edge_iterator ei; - int probability; - gcov_type count; - - last2 = last = get_last_insn (); - - expand_expr_stmt (stmt); - - for (last = NEXT_INSN (last); last; last = NEXT_INSN (last)) - if (CALL_P (last) && SIBLING_CALL_P (last)) - goto found; - - maybe_dump_rtl_for_tree_stmt (stmt, last2); - - *can_fallthru = true; - return NULL; - - found: - /* ??? Wouldn't it be better to just reset any pending stack adjust? - Any instructions emitted here are about to be deleted. */ - do_pending_stack_adjust (); - - /* Remove any non-eh, non-abnormal edges that don't go to exit. */ - /* ??? I.e. the fallthrough edge. HOWEVER! If there were to be - EH or abnormal edges, we shouldn't have created a tail call in - the first place. So it seems to me we should just be removing - all edges here, or redirecting the existing fallthru edge to - the exit block. */ - - probability = 0; - count = 0; - - for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); ) - { - if (!(e->flags & (EDGE_ABNORMAL | EDGE_EH))) - { - if (e->dest != EXIT_BLOCK_PTR) - { - e->dest->count -= e->count; - e->dest->frequency -= EDGE_FREQUENCY (e); - if (e->dest->count < 0) - e->dest->count = 0; - if (e->dest->frequency < 0) - e->dest->frequency = 0; - } - count += e->count; - probability += e->probability; - remove_edge (e); - } - else - ei_next (&ei); - } - - /* This is somewhat ugly: the call_expr expander often emits instructions - after the sibcall (to perform the function return). These confuse the - find_many_sub_basic_blocks code, so we need to get rid of these. */ - last = NEXT_INSN (last); - gcc_assert (BARRIER_P (last)); - - *can_fallthru = false; - while (NEXT_INSN (last)) - { - /* For instance an sqrt builtin expander expands if with - sibcall in the then and label for `else`. */ - if (LABEL_P (NEXT_INSN (last))) - { - *can_fallthru = true; - break; - } - delete_insn (NEXT_INSN (last)); - } - - e = make_edge (bb, EXIT_BLOCK_PTR, EDGE_ABNORMAL | EDGE_SIBCALL); - e->probability += probability; - e->count += count; - BB_END (bb) = last; - update_bb_for_insn (bb); - - if (NEXT_INSN (last)) - { - bb = create_basic_block (NEXT_INSN (last), get_last_insn (), bb); - - last = BB_END (bb); - if (BARRIER_P (last)) - BB_END (bb) = PREV_INSN (last); - } - - maybe_dump_rtl_for_tree_stmt (stmt, last2); - - return bb; -} - -/* Expand basic block BB from GIMPLE trees to RTL. */ - -static basic_block -expand_gimple_basic_block (basic_block bb) -{ - block_stmt_iterator bsi = bsi_start (bb); - tree stmt = NULL; - rtx note, last; - edge e; - edge_iterator ei; - - if (dump_file) - { - fprintf (dump_file, - "\n;; Generating RTL for tree basic block %d\n", - bb->index); - } - - init_rtl_bb_info (bb); - bb->flags |= BB_RTL; - - if (!bsi_end_p (bsi)) - stmt = bsi_stmt (bsi); - - if (stmt && TREE_CODE (stmt) == LABEL_EXPR) - { - last = get_last_insn (); - - expand_expr_stmt (stmt); - - /* Java emits line number notes in the top of labels. - ??? Make this go away once line number notes are obsoleted. */ - BB_HEAD (bb) = NEXT_INSN (last); - if (NOTE_P (BB_HEAD (bb))) - BB_HEAD (bb) = NEXT_INSN (BB_HEAD (bb)); - bsi_next (&bsi); - note = emit_note_after (NOTE_INSN_BASIC_BLOCK, BB_HEAD (bb)); - - maybe_dump_rtl_for_tree_stmt (stmt, last); - } - else - note = BB_HEAD (bb) = emit_note (NOTE_INSN_BASIC_BLOCK); - - NOTE_BASIC_BLOCK (note) = bb; - - for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); ) - { - /* Clear EDGE_EXECUTABLE. This flag is never used in the backend. */ - e->flags &= ~EDGE_EXECUTABLE; - - /* At the moment not all abnormal edges match the RTL representation. - It is safe to remove them here as find_many_sub_basic_blocks will - rediscover them. In the future we should get this fixed properly. */ - if (e->flags & EDGE_ABNORMAL) - remove_edge (e); - else - ei_next (&ei); - } - - for (; !bsi_end_p (bsi); bsi_next (&bsi)) - { - tree stmt = bsi_stmt (bsi); - basic_block new_bb; - - if (!stmt) - continue; - - /* Expand this statement, then evaluate the resulting RTL and - fixup the CFG accordingly. */ - if (TREE_CODE (stmt) == COND_EXPR) - { - new_bb = expand_gimple_cond_expr (bb, stmt); - if (new_bb) - return new_bb; - } - else - { - tree call = get_call_expr_in (stmt); - if (call && CALL_EXPR_TAILCALL (call)) - { - bool can_fallthru; - new_bb = expand_gimple_tailcall (bb, stmt, &can_fallthru); - if (new_bb) - { - if (can_fallthru) - bb = new_bb; - else - return new_bb; - } - } - else - { - last = get_last_insn (); - expand_expr_stmt (stmt); - maybe_dump_rtl_for_tree_stmt (stmt, last); - } - } - } - - do_pending_stack_adjust (); - - /* Find the block tail. The last insn in the block is the insn - before a barrier and/or table jump insn. */ - last = get_last_insn (); - if (BARRIER_P (last)) - last = PREV_INSN (last); - if (JUMP_TABLE_DATA_P (last)) - last = PREV_INSN (PREV_INSN (last)); - BB_END (bb) = last; - - update_bb_for_insn (bb); - - return bb; -} - - -/* Create a basic block for initialization code. */ - -static basic_block -construct_init_block (void) -{ - basic_block init_block, first_block; - edge e = NULL; - int flags; - - /* Multiple entry points not supported yet. */ - gcc_assert (EDGE_COUNT (ENTRY_BLOCK_PTR->succs) == 1); - init_rtl_bb_info (ENTRY_BLOCK_PTR); - init_rtl_bb_info (EXIT_BLOCK_PTR); - ENTRY_BLOCK_PTR->flags |= BB_RTL; - EXIT_BLOCK_PTR->flags |= BB_RTL; - - e = EDGE_SUCC (ENTRY_BLOCK_PTR, 0); - - /* When entry edge points to first basic block, we don't need jump, - otherwise we have to jump into proper target. */ - if (e && e->dest != ENTRY_BLOCK_PTR->next_bb) - { - tree label = tree_block_label (e->dest); - - emit_jump (label_rtx (label)); - flags = 0; - } - else - flags = EDGE_FALLTHRU; - - init_block = create_basic_block (NEXT_INSN (get_insns ()), - get_last_insn (), - ENTRY_BLOCK_PTR); - init_block->frequency = ENTRY_BLOCK_PTR->frequency; - init_block->count = ENTRY_BLOCK_PTR->count; - if (e) - { - first_block = e->dest; - redirect_edge_succ (e, init_block); - e = make_edge (init_block, first_block, flags); - } - else - e = make_edge (init_block, EXIT_BLOCK_PTR, EDGE_FALLTHRU); - e->probability = REG_BR_PROB_BASE; - e->count = ENTRY_BLOCK_PTR->count; - - update_bb_for_insn (init_block); - return init_block; -} - - -/* Create a block containing landing pads and similar stuff. */ - -static void -construct_exit_block (void) -{ - rtx head = get_last_insn (); - rtx end; - basic_block exit_block; - edge e, e2; - unsigned ix; - edge_iterator ei; - - /* Make sure the locus is set to the end of the function, so that - epilogue line numbers and warnings are set properly. */ -#ifdef USE_MAPPED_LOCATION - if (cfun->function_end_locus != UNKNOWN_LOCATION) -#else - if (cfun->function_end_locus.file) -#endif - input_location = cfun->function_end_locus; - - /* The following insns belong to the top scope. */ - record_block_change (DECL_INITIAL (current_function_decl)); - - /* Generate rtl for function exit. */ - expand_function_end (); - - end = get_last_insn (); - if (head == end) - return; - while (NEXT_INSN (head) && NOTE_P (NEXT_INSN (head))) - head = NEXT_INSN (head); - exit_block = create_basic_block (NEXT_INSN (head), end, - EXIT_BLOCK_PTR->prev_bb); - exit_block->frequency = EXIT_BLOCK_PTR->frequency; - exit_block->count = EXIT_BLOCK_PTR->count; - - ix = 0; - while (ix < EDGE_COUNT (EXIT_BLOCK_PTR->preds)) - { - e = EDGE_PRED (EXIT_BLOCK_PTR, ix); - if (!(e->flags & EDGE_ABNORMAL)) - redirect_edge_succ (e, exit_block); - else - ix++; - } - - e = make_edge (exit_block, EXIT_BLOCK_PTR, EDGE_FALLTHRU); - e->probability = REG_BR_PROB_BASE; - e->count = EXIT_BLOCK_PTR->count; - FOR_EACH_EDGE (e2, ei, EXIT_BLOCK_PTR->preds) - if (e2 != e) - { - e->count -= e2->count; - exit_block->count -= e2->count; - exit_block->frequency -= EDGE_FREQUENCY (e2); - } - if (e->count < 0) - e->count = 0; - if (exit_block->count < 0) - exit_block->count = 0; - if (exit_block->frequency < 0) - exit_block->frequency = 0; - update_bb_for_insn (exit_block); -} - -/* Helper function for discover_nonconstant_array_refs. - Look for ARRAY_REF nodes with non-constant indexes and mark them - addressable. */ - -static tree -discover_nonconstant_array_refs_r (tree * tp, int *walk_subtrees, - void *data ATTRIBUTE_UNUSED) -{ - tree t = *tp; - - if (IS_TYPE_OR_DECL_P (t)) - *walk_subtrees = 0; - else if (TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF) - { - while (((TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF) - && is_gimple_min_invariant (TREE_OPERAND (t, 1)) - && (!TREE_OPERAND (t, 2) - || is_gimple_min_invariant (TREE_OPERAND (t, 2)))) - || (TREE_CODE (t) == COMPONENT_REF - && (!TREE_OPERAND (t,2) - || is_gimple_min_invariant (TREE_OPERAND (t, 2)))) - || TREE_CODE (t) == BIT_FIELD_REF - || TREE_CODE (t) == REALPART_EXPR - || TREE_CODE (t) == IMAGPART_EXPR - || TREE_CODE (t) == VIEW_CONVERT_EXPR - || TREE_CODE (t) == NOP_EXPR - || TREE_CODE (t) == CONVERT_EXPR) - t = TREE_OPERAND (t, 0); - - if (TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF) - { - t = get_base_address (t); - if (t && DECL_P (t)) - TREE_ADDRESSABLE (t) = 1; - } - - *walk_subtrees = 0; - } - - return NULL_TREE; -} - -/* RTL expansion is not able to compile array references with variable - offsets for arrays stored in single register. Discover such - expressions and mark variables as addressable to avoid this - scenario. */ - -static void -discover_nonconstant_array_refs (void) -{ - basic_block bb; - block_stmt_iterator bsi; - - FOR_EACH_BB (bb) - { - for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) - walk_tree (bsi_stmt_ptr (bsi), discover_nonconstant_array_refs_r, - NULL , NULL); - } -} - -/* Translate the intermediate representation contained in the CFG - from GIMPLE trees to RTL. - - We do conversion per basic block and preserve/update the tree CFG. - This implies we have to do some magic as the CFG can simultaneously - consist of basic blocks containing RTL and GIMPLE trees. This can - confuse the CFG hooks, so be careful to not manipulate CFG during - the expansion. */ - -static unsigned int -tree_expand_cfg (void) -{ - basic_block bb, init_block; - sbitmap blocks; - edge_iterator ei; - edge e; - - /* Some backends want to know that we are expanding to RTL. */ - currently_expanding_to_rtl = 1; - - /* Prepare the rtl middle end to start recording block changes. */ - reset_block_changes (); - - /* Mark arrays indexed with non-constant indices with TREE_ADDRESSABLE. */ - discover_nonconstant_array_refs (); - - /* Expand the variables recorded during gimple lowering. */ - expand_used_vars (); - - /* Honor stack protection warnings. */ - if (warn_stack_protect) - { - if (current_function_calls_alloca) - warning (0, "not protecting local variables: variable length buffer"); - if (has_short_buffer && !cfun->stack_protect_guard) - warning (0, "not protecting function: no buffer at least %d bytes long", - (int) PARAM_VALUE (PARAM_SSP_BUFFER_SIZE)); - } - - /* Set up parameters and prepare for return, for the function. */ - expand_function_start (current_function_decl); - - /* If this function is `main', emit a call to `__main' - to run global initializers, etc. */ - if (DECL_NAME (current_function_decl) - && MAIN_NAME_P (DECL_NAME (current_function_decl)) - && DECL_FILE_SCOPE_P (current_function_decl)) - expand_main_function (); - - /* Initialize the stack_protect_guard field. This must happen after the - call to __main (if any) so that the external decl is initialized. */ - if (cfun->stack_protect_guard) - stack_protect_prologue (); - - /* Register rtl specific functions for cfg. */ - rtl_register_cfg_hooks (); - - init_block = construct_init_block (); - - /* Clear EDGE_EXECUTABLE on the entry edge(s). It is cleaned from the - remaining edges in expand_gimple_basic_block. */ - FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR->succs) - e->flags &= ~EDGE_EXECUTABLE; - - FOR_BB_BETWEEN (bb, init_block->next_bb, EXIT_BLOCK_PTR, next_bb) - bb = expand_gimple_basic_block (bb); - - construct_exit_block (); - - /* We're done expanding trees to RTL. */ - currently_expanding_to_rtl = 0; - - /* Convert tree EH labels to RTL EH labels, and clean out any unreachable - EH regions. */ - convert_from_eh_region_ranges (); - - rebuild_jump_labels (get_insns ()); - find_exception_handler_labels (); - - blocks = sbitmap_alloc (last_basic_block); - sbitmap_ones (blocks); - find_many_sub_basic_blocks (blocks); - purge_all_dead_edges (); - sbitmap_free (blocks); - - compact_blocks (); -#ifdef ENABLE_CHECKING - verify_flow_info(); -#endif - - /* There's no need to defer outputting this function any more; we - know we want to output it. */ - DECL_DEFER_OUTPUT (current_function_decl) = 0; - - /* Now that we're done expanding trees to RTL, we shouldn't have any - more CONCATs anywhere. */ - generating_concat_p = 0; - - finalize_block_changes (); - - if (dump_file) - { - fprintf (dump_file, - "\n\n;;\n;; Full RTL generated for this function:\n;;\n"); - /* And the pass manager will dump RTL for us. */ - } - - /* If we're emitting a nested function, make sure its parent gets - emitted as well. Doing otherwise confuses debug info. */ - { - tree parent; - for (parent = DECL_CONTEXT (current_function_decl); - parent != NULL_TREE; - parent = get_containing_scope (parent)) - if (TREE_CODE (parent) == FUNCTION_DECL) - TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (parent)) = 1; - } - - /* We are now committed to emitting code for this function. Do any - preparation, such as emitting abstract debug info for the inline - before it gets mangled by optimization. */ - if (cgraph_function_possibly_inlined_p (current_function_decl)) - (*debug_hooks->outlining_inline_function) (current_function_decl); - - TREE_ASM_WRITTEN (current_function_decl) = 1; - - /* After expanding, the return labels are no longer needed. */ - return_label = NULL; - naked_return_label = NULL; - return 0; -} - -struct tree_opt_pass pass_expand = -{ - "expand", /* name */ - NULL, /* gate */ - tree_expand_cfg, /* execute */ - NULL, /* sub */ - NULL, /* next */ - 0, /* static_pass_number */ - TV_EXPAND, /* tv_id */ - /* ??? If TER is enabled, we actually receive GENERIC. */ - PROP_gimple_leh | PROP_cfg, /* properties_required */ - PROP_rtl, /* properties_provided */ - PROP_trees, /* properties_destroyed */ - 0, /* todo_flags_start */ - TODO_dump_func, /* todo_flags_finish */ - 'r' /* letter */ -}; |