This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
PATCH: Fix handling of return values handled in PARALLELs
- From: "John David Anglin" <dave at hiauly1 dot hia dot nrc dot ca>
- To: gcc-patches at gcc dot gnu dot org
- Date: Tue, 26 Nov 2002 17:40:17 -0500 (EST)
- Subject: PATCH: Fix handling of return values handled in PARALLELs
The enclosed patch fixes a problem in returning function values in
PARALLELs wherein a call to unregister the function context for sjlj
exceptions clobbered the return value stored in the real (hard) return
register.
I have examined the code generated with this patch in a few small
test cases and seems much better than the other alternative that
that I examined (saving the return value in a stack local). It
also has the advantage of not unnecessarily creating a stack frame.
I created two new functions for the patch and put them in expr.c
as I thought they might be useful in other areas at some time in
the future.
Tested with a full bootstrap on hppa64-hp-hpux11.11 with modifications
for returning small aggregates in PARALLELs. Also tested and again
with no regressions on hppa-unknown-linux-gnu. Bootstrap is near
completion on hppa2.0w-hp-hpux11.00.
This is needed to obtain the correct justification for small aggregates
on hppa64.
Ok for main?
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2002-11-26 John David Anglin <dave@hiauly1.hia.nrc.ca>
* expr.c (gen_group_rtx, emit_group_move): New functions.
* expr.h (gen_group_rtx, emit_group_move): Prototype.
* function.c (expand_function_start): Use gen_group_rtx to create a
PARALLEL rtx to hold the return value when the real return rtx is a
PARALLEL.
(expand_function_end): Use emit_group_move to move the return value
from a PARALLEL to the real return registers.
* rtl.h (REG_FUNCTION_VALUE_P): Allow function values to be returned
in PARALLELs.
Index: expr.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/expr.c,v
retrieving revision 1.493
diff -u -3 -p -r1.493 expr.c
--- expr.c 20 Nov 2002 21:52:58 -0000 1.493
+++ expr.c 26 Nov 2002 17:32:42 -0000
@@ -2203,6 +2203,37 @@ move_block_from_reg (regno, x, nregs, si
}
}
+/* Generate a PARALLEL rtx for a new non-consecutive group of registers from
+ ORIG, where ORIG is a non-consecutive group of registers represented by
+ a PARALLEL. The clone is identical to the original except in that the
+ original set of registers is replaced by a new set of pseudo registers.
+ The new set has the same modes as the original set. */
+
+rtx
+gen_group_rtx (orig)
+ rtx orig;
+{
+ int i, length;
+ rtx *tmps;
+
+ if (GET_CODE (orig) != PARALLEL)
+ abort ();
+
+ length = XVECLEN (orig, 0);
+ tmps = (rtx *) alloca (sizeof (rtx) * length);
+
+ /* Skip a NULL entry in first slot. */
+ for (i = XEXP (XVECEXP (orig, 0, 0), 0) ? 0 : 1; i < length; i++)
+ {
+ enum machine_mode mode = GET_MODE (XEXP (XVECEXP (orig, 0, i), 0));
+ rtx offset = XEXP (XVECEXP (orig, 0, i), 1);
+
+ tmps[i] = gen_rtx_EXPR_LIST (VOIDmode, gen_reg_rtx (mode), offset);
+ }
+
+ return gen_rtx_PARALLEL (GET_MODE (orig), gen_rtvec_v (length, tmps));
+}
+
/* Emit code to move a block SRC to a block DST, where DST is non-consecutive
registers represented by a PARALLEL. SSIZE represents the total size of
block SRC in bytes, or -1 if not known. */
@@ -2322,6 +2353,26 @@ emit_group_load (dst, orig_src, ssize)
/* Copy the extracted pieces into the proper (probable) hard regs. */
for (i = start; i < XVECLEN (dst, 0); i++)
emit_move_insn (XEXP (XVECEXP (dst, 0, i), 0), tmps[i]);
+}
+
+/* Emit code to move a block SRC to block DST, where SRC and DST are
+ non-consecutive groups of registers, each represented by a PARALLEL. */
+
+void
+emit_group_move (dst, src)
+ rtx dst, src;
+{
+ int i;
+
+ if (GET_CODE (src) != PARALLEL
+ || GET_CODE (dst) != PARALLEL
+ || XVECLEN (src, 0) != XVECLEN (dst, 0))
+ abort ();
+
+ /* Skip first entry if NULL. */
+ for (i = XEXP (XVECEXP (src, 0, 0), 0) ? 0 : 1; i < XVECLEN (src, 0); i++)
+ emit_move_insn (XEXP (XVECEXP (dst, 0, i), 0),
+ XEXP (XVECEXP (src, 0, i), 0));
}
/* Emit code to move a block SRC to a block DST, where SRC is non-consecutive
Index: expr.h
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/expr.h,v
retrieving revision 1.123
diff -u -3 -p -r1.123 expr.h
--- expr.h 22 Sep 2002 14:09:31 -0000 1.123
+++ expr.h 26 Nov 2002 17:32:42 -0000
@@ -412,9 +412,16 @@ extern void move_block_to_reg PARAMS ((i
The number of registers to be filled is NREGS. */
extern void move_block_from_reg PARAMS ((int, rtx, int, int));
+/* Generate a non-consecutive group of registers represented by a PARALLEL. */
+extern rtx gen_group_rtx PARAMS ((rtx));
+
/* Load a BLKmode value into non-consecutive registers represented by a
PARALLEL. */
extern void emit_group_load PARAMS ((rtx, rtx, int));
+
+/* Move a non-consecutive group of registers represented by a PARALLEL into
+ a non-consecutive group of registers represented by a PARALLEL. */
+extern void emit_group_move PARAMS ((rtx, rtx));
/* Store a BLKmode value from non-consecutive registers represented by a
PARALLEL. */
Index: function.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/function.c,v
retrieving revision 1.387
diff -u -3 -p -r1.387 function.c
--- function.c 14 Oct 2002 21:19:04 -0000 1.387
+++ function.c 26 Nov 2002 17:32:45 -0000
@@ -6559,18 +6559,17 @@ expand_function_start (subr, parms_have_
subr, 1);
/* Structures that are returned in registers are not aggregate_value_p,
- so we may see a PARALLEL. Don't play pseudo games with this. */
- if (! REG_P (hard_reg))
- SET_DECL_RTL (DECL_RESULT (subr), hard_reg);
+ so we may see a PARALLEL or a REG. */
+ if (REG_P (hard_reg))
+ SET_DECL_RTL (DECL_RESULT (subr), gen_reg_rtx (GET_MODE (hard_reg)));
+ else if (GET_CODE (hard_reg) == PARALLEL)
+ SET_DECL_RTL (DECL_RESULT (subr), gen_group_rtx (hard_reg));
else
- {
- /* Create the pseudo. */
- SET_DECL_RTL (DECL_RESULT (subr), gen_reg_rtx (GET_MODE (hard_reg)));
+ abort ();
- /* Needed because we may need to move this to memory
- in case it's a named return value whose address is taken. */
- DECL_REGISTER (DECL_RESULT (subr)) = 1;
- }
+ /* Set DECL_REGISTER flag so that expand_function_end will copy the
+ result to the real return register(s). */
+ DECL_REGISTER (DECL_RESULT (subr)) = 1;
}
/* Initialize rtx for parameters and local variables.
@@ -6998,8 +6997,16 @@ expand_function_end (filename, line, end
convert_move (real_decl_rtl, decl_rtl, unsignedp);
}
else if (GET_CODE (real_decl_rtl) == PARALLEL)
- emit_group_load (real_decl_rtl, decl_rtl,
- int_size_in_bytes (TREE_TYPE (decl_result)));
+ {
+ /* If expand_function_start has created a PARALLEL for decl_rtl,
+ move the result to the real return registers. Otherwise, do
+ a group load from decl_rtl for a named return. */
+ if (GET_CODE (decl_rtl) == PARALLEL)
+ emit_group_move (real_decl_rtl, decl_rtl);
+ else
+ emit_group_load (real_decl_rtl, decl_rtl,
+ int_size_in_bytes (TREE_TYPE (decl_result)));
+ }
else
emit_move_insn (real_decl_rtl, decl_rtl);
}
Index: rtl.h
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/rtl.h,v
retrieving revision 1.374
diff -u -3 -p -r1.374 rtl.h
--- rtl.h 4 Nov 2002 16:57:03 -0000 1.374
+++ rtl.h 26 Nov 2002 17:32:46 -0000
@@ -185,7 +185,7 @@ struct rtx_def GTY((chain_next ("RTX_NEX
has used it as the function. */
unsigned int used : 1;
/* Nonzero if this rtx came from procedure integration.
- 1 in a REG means this reg refers to the return value
+ 1 in a REG or PARALLEL means this rtx refers to the return value
of the current function.
1 in a SYMBOL_REF if the symbol is weak. */
unsigned integrated : 1;
@@ -988,9 +988,10 @@ enum label_kind
#define REGNO(RTX) XCUINT (RTX, 0, REG)
#define ORIGINAL_REGNO(RTX) X0UINT (RTX, 1)
-/* 1 if RTX is a reg that is the current function's return value. */
+/* 1 if RTX is a reg or parallel that is the current function's return
+ value. */
#define REG_FUNCTION_VALUE_P(RTX) \
- (RTL_FLAG_CHECK1("REG_FUNCTION_VALUE_P", (RTX), REG)->integrated)
+ (RTL_FLAG_CHECK2("REG_FUNCTION_VALUE_P", (RTX), REG, PARALLEL)->integrated)
/* 1 if RTX is a reg that corresponds to a variable declared by the user. */
#define REG_USERVAR_P(RTX) \