aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.2.1-5666.3/gcc/cfgexpand.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.2.1-5666.3/gcc/cfgexpand.c')
-rw-r--r--gcc-4.2.1-5666.3/gcc/cfgexpand.c1736
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 */
-};