aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2000-10-24 13:25:50 +0200
committerJakub Jelinek <jakub@gcc.gnu.org>2000-10-24 13:25:50 +0200
commitf85b5d6572247f12df1baadc1774245633783dad (patch)
tree037232bf933e48befd4183029b44ff79f9b53a1f /gcc
parent85d0c8b46e8f70ec127031f6bfb9dd1225283cee (diff)
downloadgcc-f85b5d6572247f12df1baadc1774245633783dad.zip
gcc-f85b5d6572247f12df1baadc1774245633783dad.tar.gz
gcc-f85b5d6572247f12df1baadc1774245633783dad.tar.bz2
sibcall.c (purge_mem_unchanging_flag): New function.
* sibcall.c (purge_mem_unchanging_flag): New function. (optimize_sibling_and_tail_recursive_calls): Call it. * g++.old-deja/g++.other/sibcall1.C: New test. From-SVN: r37033
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog5
-rw-r--r--gcc/sibcall.c83
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/g++.old-deja/g++.other/sibcall1.C13
4 files changed, 94 insertions, 11 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 9eba1ad..67586d8 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,8 @@
+2000-10-24 Jakub Jelinek <jakub@redhat.com>
+
+ * sibcall.c (purge_mem_unchanging_flag): New function.
+ (optimize_sibling_and_tail_recursive_calls): Call it.
+
2000-10-24 Philipp Thomas <pthomas@suse.de>
* Makefile.in (check-po): New target for doing checks in the po
diff --git a/gcc/sibcall.c b/gcc/sibcall.c
index eaf9ae7..730654a 100644
--- a/gcc/sibcall.c
+++ b/gcc/sibcall.c
@@ -41,6 +41,7 @@ static rtx skip_jump_insn PARAMS ((rtx));
static int uses_addressof PARAMS ((rtx));
static int sequence_uses_addressof PARAMS ((rtx));
static void purge_reg_equiv_notes PARAMS ((void));
+static void purge_mem_unchanging_flag PARAMS ((rtx));
/* Examine a CALL_PLACEHOLDER pattern and determine where the call's
return value is located. P_HARD_RETURN receives the hard register
@@ -362,6 +363,45 @@ purge_reg_equiv_notes ()
}
}
+/* Clear RTX_UNCHANGING_P flag of incoming argument MEMs. */
+
+static void
+purge_mem_unchanging_flag (x)
+ rtx x;
+{
+ RTX_CODE code;
+ int i, j;
+ const char *fmt;
+
+ if (x == NULL_RTX)
+ return;
+
+ code = GET_CODE (x);
+
+ if (code == MEM)
+ {
+ if (RTX_UNCHANGING_P (x)
+ && (XEXP (x, 0) == current_function_internal_arg_pointer
+ || (GET_CODE (XEXP (x, 0)) == PLUS
+ && XEXP (XEXP (x, 0), 0) ==
+ current_function_internal_arg_pointer
+ && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)))
+ RTX_UNCHANGING_P (x) = 0;
+ return;
+ }
+
+ /* Scan all subexpressions. */
+ fmt = GET_RTX_FORMAT (code);
+ for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
+ {
+ if (*fmt == 'e')
+ purge_mem_unchanging_flag (XEXP (x, i));
+ else if (*fmt == 'E')
+ for (j = 0; j < XVECLEN (x, i); j++)
+ purge_mem_unchanging_flag (XVECEXP (x, i, j));
+ }
+}
+
/* Replace the CALL_PLACEHOLDER with one of its children. INSN should be
the CALL_PLACEHOLDER insn; USE tells which child to use. */
@@ -593,18 +633,39 @@ success:
}
}
- /* A sibling call sequence invalidates any REG_EQUIV notes made for
- this function's incoming arguments.
-
- At the start of RTL generation we know the only REG_EQUIV notes
- in the rtl chain are those for incoming arguments, so we can safely
- flush any REG_EQUIV note.
-
- This is (slight) overkill. We could keep track of the highest argument
- we clobber and be more selective in removing notes, but it does not
- seem to be worth the effort. */
if (successful_sibling_call)
- purge_reg_equiv_notes ();
+ {
+ rtx insn;
+
+ /* A sibling call sequence invalidates any REG_EQUIV notes made for
+ this function's incoming arguments.
+
+ At the start of RTL generation we know the only REG_EQUIV notes
+ in the rtl chain are those for incoming arguments, so we can safely
+ flush any REG_EQUIV note.
+
+ This is (slight) overkill. We could keep track of the highest
+ argument we clobber and be more selective in removing notes, but it
+ does not seem to be worth the effort. */
+ purge_reg_equiv_notes ();
+
+ /* A sibling call sequence also may invalidate RTX_UNCHANGING_P
+ flag of some incoming arguments MEM RTLs, because it can write into
+ those slots. We clear all those bits now.
+
+ This is (slight) overkill, we could keep track of which arguments
+ we actually write into. */
+ for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ {
+ if (GET_CODE (insn) == NOTE)
+ {
+ if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG)
+ break;
+ }
+ else if (INSN_P (insn))
+ purge_mem_unchanging_flag (PATTERN (insn));
+ }
+ }
/* There may have been NOTE_INSN_BLOCK_{BEGIN,END} notes in the
CALL_PLACEHOLDER alternatives that we didn't emit. Rebuild the
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 4c24981..ac355b2 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2000-10-24 Jakub Jelinek <jakub@redhat.com>
+
+ * g++.old-deja/g++.other/sibcall1.C: New test.
+
2000-10-20 Jakub Jelinek <jakub@redhat.com>
* gcc.dg/noncompile/init-3.c: New test.
diff --git a/gcc/testsuite/g++.old-deja/g++.other/sibcall1.C b/gcc/testsuite/g++.old-deja/g++.other/sibcall1.C
new file mode 100644
index 0000000..8add4b8
--- /dev/null
+++ b/gcc/testsuite/g++.old-deja/g++.other/sibcall1.C
@@ -0,0 +1,13 @@
+// Special g++ Options: -O2
+
+#include <iostream>
+
+ostream& foo (char *x, ostream &y)
+{
+ return y << "" << x;
+}
+
+int main ()
+{
+ foo ("", cout);
+}