aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog13
-rw-r--r--gcc/flow.c49
-rw-r--r--gcc/function.c100
-rw-r--r--gcc/function.h4
-rw-r--r--gcc/integrate.c7
-rw-r--r--gcc/stmt.c4
6 files changed, 103 insertions, 74 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 5384a68..c708a02 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,16 @@
+2000-02-04 Richard Henderson <rth@cygnus.com>
+
+ * function.c (diddle_return_value): Rework to use a callback function.
+ Use current_function_return_rtx if it's been set up.
+ (do_clobber_return_reg, clobber_return_register): New.
+ (do_use_return_reg, use_return_register): New.
+ (expand_function_end): Use them.
+ * stmt.c (expand_null_return): Likewise.
+ * function.h: Declare them.
+ * flow.c (mark_regs_live_at_end): Use diddle_return_value.
+ (mark_reg): Change arguments as appropriate for callback.
+ * integrate.c (expand_inline_function): Revert 19 Jan change.
+
Fri Feb 4 20:25:42 2000 Hans-Peter Nilsson <hp@bitrange.com>
* tm.texi (Values in Registers): Fix typo: "fo" "for".
diff --git a/gcc/flow.c b/gcc/flow.c
index c269261..aa87451 100644
--- a/gcc/flow.c
+++ b/gcc/flow.c
@@ -320,7 +320,7 @@ static int set_noop_p PARAMS ((rtx));
static int noop_move_p PARAMS ((rtx));
static void notice_stack_pointer_modification PARAMS ((rtx, rtx, void *));
static void record_volatile_insns PARAMS ((rtx));
-static void mark_reg PARAMS ((regset, rtx));
+static void mark_reg PARAMS ((rtx, void *));
static void mark_regs_live_at_end PARAMS ((regset));
static void life_analysis_1 PARAMS ((rtx, int, int));
static void calculate_global_regs_live PARAMS ((sbitmap, sbitmap, int));
@@ -2788,12 +2788,16 @@ record_volatile_insns (f)
/* Mark a register in SET. Hard registers in large modes get all
of their component registers set as well. */
static void
-mark_reg (set, reg)
- regset set;
+mark_reg (reg, xset)
rtx reg;
+ void *xset;
{
+ regset set = (regset) xset;
int regno = REGNO (reg);
+ if (GET_MODE (reg) == BLKmode)
+ abort ();
+
SET_REGNO_REG_SET (set, regno);
if (regno < FIRST_PSEUDO_REGISTER)
{
@@ -2867,44 +2871,7 @@ mark_regs_live_at_end (set)
}
/* Mark function return value. */
-
- result = DECL_RESULT (current_function_decl);
- type = TREE_TYPE (result);
- if (type != void_type_node)
- {
- rtx outgoing;
-
- /* ??? Share this code with expand_function_end. */
-#ifdef FUNCTION_OUTGOING_VALUE
- outgoing = FUNCTION_OUTGOING_VALUE (type, current_function_decl);
-#else
- outgoing = FUNCTION_VALUE (type, current_function_decl);
-#endif
- /* If this is a BLKmode structure being returned in registers,
- then use the mode computed in expand_return. */
- if (GET_MODE (outgoing) == BLKmode)
- PUT_MODE (outgoing, GET_MODE (DECL_RTL (result)));
-
- if (GET_CODE (outgoing) == REG)
- mark_reg (set, outgoing);
- else if (GET_CODE (outgoing) == PARALLEL)
- {
- int len = XVECLEN (outgoing, 0);
-
- /* Check for a NULL entry, used to indicate that the parameter
- goes on the stack and in registers. */
- i = (XEXP (XVECEXP (outgoing, 0, 0), 0) ? 0 : 1);
-
- for ( ; i < len; ++i)
- {
- rtx r = XVECEXP (outgoing, 0, i);
- if (GET_CODE (r) == REG)
- mark_reg (set, r);
- }
- }
- else
- abort ();
- }
+ diddle_return_value (mark_reg, set);
}
/* Determine which registers are live at the start of each
diff --git a/gcc/function.c b/gcc/function.c
index 960fd1c..d466db8 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -286,7 +286,8 @@ static void mark_temp_slot PARAMS ((struct temp_slot *));
static void mark_function_status PARAMS ((struct function *));
static void mark_function_chain PARAMS ((void *));
static void prepare_function_start PARAMS ((void));
-
+static void do_clobber_return_reg PARAMS ((rtx, void *));
+static void do_use_return_reg PARAMS ((rtx, void *));
/* Pointer to chain of `struct function' for containing functions. */
struct function *outer_function_chain;
@@ -6120,44 +6121,79 @@ expand_dummy_function_end ()
cfun = 0;
}
-/* Emit CODE for each register of the return value. Useful values for
- code are USE and CLOBBER. */
+/* Call DOIT for each hard register used as a return value from
+ the current function. */
void
-diddle_return_value (code)
- enum rtx_code code;
+diddle_return_value (doit, arg)
+ void (*doit) PARAMS ((rtx, void *));
+ void *arg;
{
- tree decl_result = DECL_RESULT (current_function_decl);
- rtx return_reg = DECL_RTL (decl_result);
+ rtx outgoing = current_function_return_rtx;
- if (return_reg)
+ if (! outgoing)
+ return;
+
+ if (GET_CODE (outgoing) == REG
+ && REGNO (outgoing) >= FIRST_PSEUDO_REGISTER)
{
- if (GET_CODE (return_reg) == REG
- && REGNO (return_reg) < FIRST_PSEUDO_REGISTER)
- {
- /* Use hard_function_value to avoid creating a reference to a BLKmode
- register in the USE/CLOBBER insn. */
- return_reg = hard_function_value (TREE_TYPE (decl_result),
- current_function_decl, 1);
- REG_FUNCTION_VALUE_P (return_reg) = 1;
- emit_insn (gen_rtx_fmt_e (code, VOIDmode, return_reg));
- }
- else if (GET_CODE (return_reg) == PARALLEL)
- {
- int i;
+ tree type = TREE_TYPE (DECL_RESULT (current_function_decl));
+#ifdef FUNCTION_OUTGOING_VALUE
+ outgoing = FUNCTION_OUTGOING_VALUE (type, current_function_decl);
+#else
+ outgoing = FUNCTION_VALUE (type, current_function_decl);
+#endif
+ /* If this is a BLKmode structure being returned in registers, then use
+ the mode computed in expand_return. */
+ if (GET_MODE (outgoing) == BLKmode)
+ PUT_MODE (outgoing,
+ GET_MODE (DECL_RTL (DECL_RESULT (current_function_decl))));
+ }
- for (i = 0; i < XVECLEN (return_reg, 0); i++)
- {
- rtx x = XEXP (XVECEXP (return_reg, 0, i), 0);
+ if (GET_CODE (outgoing) == REG)
+ (*doit) (outgoing, arg);
+ else if (GET_CODE (outgoing) == PARALLEL)
+ {
+ int i;
- if (GET_CODE (x) == REG
- && REGNO (x) < FIRST_PSEUDO_REGISTER)
- emit_insn (gen_rtx_fmt_e (code, VOIDmode, x));
- }
+ for (i = 0; i < XVECLEN (outgoing, 0); i++)
+ {
+ rtx x = XEXP (XVECEXP (outgoing, 0, i), 0);
+
+ if (GET_CODE (x) == REG && REGNO (x) < FIRST_PSEUDO_REGISTER)
+ (*doit) (x, arg);
}
}
}
+static void
+do_clobber_return_reg (reg, arg)
+ rtx reg;
+ void *arg ATTRIBUTE_UNUSED;
+{
+ emit_insn (gen_rtx_CLOBBER (VOIDmode, reg));
+}
+
+void
+clobber_return_register ()
+{
+ diddle_return_value (do_clobber_return_reg, NULL);
+}
+
+static void
+do_use_return_reg (reg, arg)
+ rtx reg;
+ void *arg ATTRIBUTE_UNUSED;
+{
+ emit_insn (gen_rtx_USE (VOIDmode, reg));
+}
+
+void
+use_return_register ()
+{
+ diddle_return_value (do_use_return_reg, NULL);
+}
+
/* Generate RTL for the end of the current function.
FILENAME and LINE are the current position in the source file.
@@ -6324,7 +6360,7 @@ expand_function_end (filename, line, end_bindings)
can only happen with functions that drop through; if there had
been a return statement, there would have either been a return
rtx, or a jump to the return label. */
- diddle_return_value (CLOBBER);
+ clobber_return_register ();
emit_label (return_label);
}
@@ -6444,6 +6480,12 @@ expand_function_end (filename, line, end_bindings)
emit_move_insn (outgoing, value_address);
}
+ /* ??? This should no longer be necessary since stupid is no longer with
+ us, but there are some parts of the compiler (eg reload_combine, and
+ sh mach_dep_reorg) that still try and compute their own lifetime info
+ instead of using the general framework. */
+ use_return_register ();
+
/* If this is an implementation of __throw, do what's necessary to
communicate between __builtin_eh_return and the epilogue. */
expand_eh_return ();
diff --git a/gcc/function.h b/gcc/function.h
index 35d26bd..1a94f94 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -585,7 +585,9 @@ extern void free_expr_status PARAMS ((struct function *));
extern rtx get_first_block_beg PARAMS ((void));
#ifdef RTX_CODE
-extern void diddle_return_value PARAMS ((enum rtx_code));
+extern void diddle_return_value PARAMS ((void (*)(rtx, void*), void*));
+extern void clobber_return_register PARAMS ((void));
+extern void use_return_register PARAMS ((void));
#endif
extern void init_virtual_regs PARAMS ((struct emit_status *));
diff --git a/gcc/integrate.c b/gcc/integrate.c
index 8b3fff7..0cbff9d 100644
--- a/gcc/integrate.c
+++ b/gcc/integrate.c
@@ -1099,6 +1099,13 @@ expand_inline_function (fndecl, parms, target, ignore, type,
pattern = PATTERN (insn);
set = single_set (insn);
copy = 0;
+ if (GET_CODE (pattern) == USE
+ && GET_CODE (XEXP (pattern, 0)) == REG
+ && REG_FUNCTION_VALUE_P (XEXP (pattern, 0)))
+ /* The (USE (REG n)) at return from the function should
+ be ignored since we are changing (REG n) into
+ inline_target. */
+ break;
/* If the inline fn needs eh context, make sure that
the current fn has one. */
diff --git a/gcc/stmt.c b/gcc/stmt.c
index 8650953..8c76b3b 100644
--- a/gcc/stmt.c
+++ b/gcc/stmt.c
@@ -2676,11 +2676,9 @@ expand_null_return ()
/* If this function was declared to return a value, but we
didn't, clobber the return registers so that they are not
propogated live to the rest of the function. */
-
- diddle_return_value (CLOBBER);
+ clobber_return_register ();
/* Does any pending block have cleanups? */
-
while (block && block->data.block.cleanups == 0)
block = block->next;