/* Expands front end tree to back end RTL for GCC.
Copyright (C) 1987, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
- 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+ 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
Free Software Foundation, Inc.
This file is part of GCC.
static void pad_to_arg_alignment (struct args_size *, int, struct args_size *);
static void pad_below (struct args_size *, enum machine_mode, tree);
static void reorder_blocks_1 (rtx, tree, VEC(tree,heap) **);
-static void reorder_fix_fragments (tree);
static int all_blocks (tree, tree *);
static tree *get_block_vector (tree, int *);
extern tree debug_find_var_in_block_tree (tree, tree);
tree type = (TYPE_P (exp)) ? exp : TREE_TYPE (exp);
+ /* DECL node associated with FNTYPE when relevant, which we might need to
+ check for by-invisible-reference returns, typically for CALL_EXPR input
+ EXPressions. */
+ tree fndecl = NULL_TREE;
+
if (fntype)
switch (TREE_CODE (fntype))
{
case CALL_EXPR:
- fntype = get_callee_fndecl (fntype);
- fntype = fntype ? TREE_TYPE (fntype) : 0;
+ fndecl = get_callee_fndecl (fntype);
+ fntype = fndecl ? TREE_TYPE (fndecl) : 0;
break;
case FUNCTION_DECL:
- fntype = TREE_TYPE (fntype);
+ fndecl = fntype;
+ fntype = TREE_TYPE (fndecl);
break;
case FUNCTION_TYPE:
case METHOD_TYPE:
if (TREE_CODE (type) == VOID_TYPE)
return 0;
+
/* If the front end has decided that this needs to be passed by
reference, do so. */
if ((TREE_CODE (exp) == PARM_DECL || TREE_CODE (exp) == RESULT_DECL)
&& DECL_BY_REFERENCE (exp))
return 1;
+
+ /* If the EXPression is a CALL_EXPR, honor DECL_BY_REFERENCE set on the
+ called function RESULT_DECL, meaning the function returns in memory by
+ invisible reference. This check lets front-ends not set TREE_ADDRESSABLE
+ on the function type, which used to be the way to request such a return
+ mechanism but might now be causing troubles at gimplification time if
+ temporaries with the function type need to be created. */
+ if (TREE_CODE (exp) == CALL_EXPR && fndecl && DECL_RESULT (fndecl)
+ && DECL_BY_REFERENCE (DECL_RESULT (fndecl)))
+ return 1;
+
if (targetm.calls.return_in_memory (type, fntype))
return 1;
/* Types that are TREE_ADDRESSABLE must be constructed in memory,
reorder_blocks_1 (get_insns (), block, &block_stack);
BLOCK_SUBBLOCKS (block) = blocks_nreverse (BLOCK_SUBBLOCKS (block));
- /* Remove deleted blocks from the block fragment chains. */
- reorder_fix_fragments (block);
-
VEC_free (tree, heap, block_stack);
}
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG)
{
tree block = NOTE_BLOCK (insn);
+ tree origin;
+
+ origin = (BLOCK_FRAGMENT_ORIGIN (block)
+ ? BLOCK_FRAGMENT_ORIGIN (block)
+ : block);
/* If we have seen this block before, that means it now
spans multiple address regions. Create a new fragment. */
if (TREE_ASM_WRITTEN (block))
{
tree new_block = copy_node (block);
- tree origin;
- origin = (BLOCK_FRAGMENT_ORIGIN (block)
- ? BLOCK_FRAGMENT_ORIGIN (block)
- : block);
BLOCK_FRAGMENT_ORIGIN (new_block) = origin;
BLOCK_FRAGMENT_CHAIN (new_block)
= BLOCK_FRAGMENT_CHAIN (origin);
will cause infinite recursion. */
if (block != current_block)
{
+ if (block != origin)
+ gcc_assert (BLOCK_SUPERCONTEXT (origin) == current_block);
+
BLOCK_SUPERCONTEXT (block) = current_block;
BLOCK_CHAIN (block) = BLOCK_SUBBLOCKS (current_block);
BLOCK_SUBBLOCKS (current_block) = block;
- current_block = block;
+ current_block = origin;
}
VEC_safe_push (tree, heap, *p_block_stack, block);
}
}
}
-/* Rationalize BLOCK_FRAGMENT_ORIGIN. If an origin block no longer
- appears in the block tree, select one of the fragments to become
- the new origin block. */
-
-static void
-reorder_fix_fragments (tree block)
-{
- while (block)
- {
- tree dup_origin = BLOCK_FRAGMENT_ORIGIN (block);
- tree new_origin = NULL_TREE;
-
- if (dup_origin)
- {
- if (! TREE_ASM_WRITTEN (dup_origin))
- {
- new_origin = BLOCK_FRAGMENT_CHAIN (dup_origin);
-
- /* Find the first of the remaining fragments. There must
- be at least one -- the current block. */
- while (! TREE_ASM_WRITTEN (new_origin))
- new_origin = BLOCK_FRAGMENT_CHAIN (new_origin);
- BLOCK_FRAGMENT_ORIGIN (new_origin) = NULL_TREE;
- }
- }
- else if (! dup_origin)
- new_origin = block;
-
- /* Re-root the rest of the fragments to the new origin. In the
- case that DUP_ORIGIN was null, that means BLOCK was the origin
- of a chain of fragments and we want to remove those fragments
- that didn't make it to the output. */
- if (new_origin)
- {
- tree *pp = &BLOCK_FRAGMENT_CHAIN (new_origin);
- tree chain = *pp;
-
- while (chain)
- {
- if (TREE_ASM_WRITTEN (chain))
- {
- BLOCK_FRAGMENT_ORIGIN (chain) = new_origin;
- *pp = chain;
- pp = &BLOCK_FRAGMENT_CHAIN (chain);
- }
- chain = BLOCK_FRAGMENT_CHAIN (chain);
- }
- *pp = NULL_TREE;
- }
-
- reorder_fix_fragments (BLOCK_SUBBLOCKS (block));
- block = BLOCK_CHAIN (block);
- }
-}
-
/* Reverse the order of elements in the chain T of blocks,
and return the new head of the chain (old last element). */
}
/* Finishes record of boundaries. */
-void finalize_block_changes (void)
+void
+finalize_block_changes (void)
{
record_block_change (DECL_INITIAL (current_function_decl));
}