This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Fix AMD64 handling of functions with huge stack frames
- From: Jakub Jelinek <jakub at redhat dot com>
- To: Richard Henderson <rth at redhat dot com>, jh at suse dot cz
- Cc: gcc-patches at gcc dot gnu dot org
- Date: Thu, 23 Oct 2003 12:32:39 +0200
- Subject: [PATCH] Fix AMD64 handling of functions with huge stack frames
- Reply-to: Jakub Jelinek <jakub at redhat dot com>
Hi!
The following testcases ICE on AMD64.
I haven't handled indirect sibcall case with huge stack frames yet,
since current GCC cannot generate such functions (in such functions %r11
register is already used by the sibcall jump and thus cannot be used for the
temporary in epilogue).
The testcases are compile, not execute resp. gcc.dg, since in order to run
them, one needs (on 64-bit Linux) at least
echo 1 > /proc/sys/vm/overcommit_memory
and
ulimit -s unlimited
before executing the testcase.
Ok to commit?
2003-10-23 Jakub Jelinek <jakub@redhat.com>
* config/i386/i386.c (ix86_expand_prologue): Handle stack
adjustement bigger than 2GB.
(epilogue_adjust_stack): New function.
(ix86_expand_epilogue): Use it.
* config/i386/i386.c (ix86_expand_epilogue): Fix comment typo.
* config/i386/i386.c (ix86_expand_call): Replace 40 with
FIRST_REX_INT_REG + 3 /* R11 */.
* gcc.c-torture/compile/20031023-1.c: New test.
* gcc.c-torture/compile/20031023-2.c: New test.
* gcc.c-torture/compile/20031023-3.c: New test.
* gcc.c-torture/compile/20031023-4.c: New test.
--- gcc/config/i386/i386.c.jj 2003-10-23 09:55:03.000000000 +0200
+++ gcc/config/i386/i386.c 2003-10-23 13:59:26.000000000 +0200
@@ -5066,9 +5066,23 @@ ix86_expand_prologue (void)
;
else if (! TARGET_STACK_PROBE || allocate < CHECK_STACK_LIMIT)
{
- insn = emit_insn (gen_pro_epilogue_adjust_stack
- (stack_pointer_rtx, stack_pointer_rtx,
- GEN_INT (-allocate)));
+ rtx disp = GEN_INT (-allocate);
+ if (! TARGET_64BIT || x86_64_immediate_operand (disp, DImode))
+ {
+ insn = emit_insn (gen_pro_epilogue_adjust_stack
+ (stack_pointer_rtx, stack_pointer_rtx, disp));
+ }
+ else
+ {
+ /* Most of call used registers are used for parameter passing,
+ r10 is used for static chain but r11 shouldn't be live during
+ prologue. */
+ rtx r11 = gen_rtx_REG (DImode, FIRST_REX_INT_REG + 3 /* R11 */);
+ insn = emit_insn (gen_rtx_SET (DImode, r11, disp));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ insn = emit_insn (gen_pro_epilogue_adjust_stack_rex64
+ (stack_pointer_rtx, stack_pointer_rtx, r11));
+ }
RTX_FRAME_RELATED_P (insn) = 1;
}
else
@@ -5145,6 +5159,26 @@ ix86_emit_restore_regs_using_mov (rtx po
}
}
+static void
+epilogue_adjust_stack (rtx dest, rtx src, rtx offset, int style)
+{
+ if (! TARGET_64BIT || x86_64_immediate_operand (offset, DImode))
+ emit_insn (gen_pro_epilogue_adjust_stack (dest, src, offset));
+ else
+ {
+ rtx r11;
+ /* r11 is used by indirect sibcall return as well, set before the
+ epilogue and used after the epilogue. ATM indirect sibcall
+ shouldn't be used together with huge frame sizes in one
+ function because of the frame_size check in sibcall.c. */
+ if (style == 0)
+ abort ();
+ r11 = gen_rtx_REG (DImode, FIRST_REX_INT_REG + 3 /* R11 */);
+ emit_insn (gen_rtx_SET (DImode, r11, offset));
+ emit_insn (gen_pro_epilogue_adjust_stack_rex64 (dest, src, r11));
+ }
+}
+
/* Restore function stack, frame, and registers. */
void
@@ -5225,10 +5259,10 @@ ix86_expand_epilogue (int style)
}
}
else if (!frame_pointer_needed)
- emit_insn (gen_pro_epilogue_adjust_stack
- (stack_pointer_rtx, stack_pointer_rtx,
- GEN_INT (frame.to_allocate
- + frame.nregs * UNITS_PER_WORD)));
+ epilogue_adjust_stack (stack_pointer_rtx, stack_pointer_rtx,
+ GEN_INT (frame.to_allocate
+ + frame.nregs * UNITS_PER_WORD),
+ style);
/* If not an i386, mov & pop is faster than "leave". */
else if (TARGET_USE_LEAVE || optimize_size
|| !cfun->machine->use_fast_prologue_epilogue)
@@ -5252,14 +5286,12 @@ ix86_expand_epilogue (int style)
{
if (!frame_pointer_needed)
abort ();
- emit_insn (gen_pro_epilogue_adjust_stack (stack_pointer_rtx,
- hard_frame_pointer_rtx,
- GEN_INT (offset)));
+ epilogue_adjust_stack (stack_pointer_rtx, hard_frame_pointer_rtx,
+ GEN_INT (offset), style);
}
else if (frame.to_allocate)
- emit_insn (gen_pro_epilogue_adjust_stack
- (stack_pointer_rtx, stack_pointer_rtx,
- GEN_INT (frame.to_allocate)));
+ epilogue_adjust_stack (stack_pointer_rtx, stack_pointer_rtx,
+ GEN_INT (frame.to_allocate), style);
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
if (ix86_save_reg (regno, false))
@@ -5298,7 +5330,7 @@ ix86_expand_epilogue (int style)
{
rtx ecx = gen_rtx_REG (SImode, 2);
- /* There are is no "pascal" calling convention in 64bit ABI. */
+ /* There is no "pascal" calling convention in 64bit ABI. */
if (TARGET_64BIT)
abort ();
@@ -11541,7 +11573,7 @@ ix86_expand_call (rtx retval, rtx fnaddr
{
rtx addr;
addr = copy_to_mode_reg (Pmode, XEXP (fnaddr, 0));
- fnaddr = gen_rtx_REG (Pmode, 40);
+ fnaddr = gen_rtx_REG (Pmode, FIRST_REX_INT_REG + 3 /* R11 */);
emit_move_insn (fnaddr, addr);
fnaddr = gen_rtx_MEM (QImode, fnaddr);
}
--- gcc/config/i386/i386.md.jj 2003-10-23 09:55:07.000000000 +0200
+++ gcc/config/i386/i386.md 2003-10-23 11:39:41.000000000 +0200
@@ -17830,9 +17830,9 @@
(set_attr "mode" "SI")])
(define_insn "pro_epilogue_adjust_stack_rex64"
- [(set (match_operand:DI 0 "register_operand" "=r,r")
- (plus:DI (match_operand:DI 1 "register_operand" "0,r")
- (match_operand:DI 2 "x86_64_immediate_operand" "e,e")))
+ [(set (match_operand:DI 0 "register_operand" "=r,r,r")
+ (plus:DI (match_operand:DI 1 "register_operand" "0,r,r")
+ (match_operand:DI 2 "x86_64_general_operand" "e,e,r")))
(clobber (reg:CC 17))
(clobber (mem:BLK (scratch)))]
"TARGET_64BIT"
@@ -17862,7 +17862,7 @@
}
}
[(set (attr "type")
- (cond [(eq_attr "alternative" "0")
+ (cond [(eq_attr "alternative" "0,2")
(const_string "alu")
(match_operand:DI 2 "const0_operand" "")
(const_string "imov")
--- gcc/testsuite/gcc.c-torture/compile/20031023-1.c.jj 2003-10-23 14:19:10.000000000 +0200
+++ gcc/testsuite/gcc.c-torture/compile/20031023-1.c 2003-10-23 14:16:03.000000000 +0200
@@ -0,0 +1,65 @@
+#ifndef ASIZE
+# define ASIZE 0x10000000000UL
+#endif
+
+#include <limits.h>
+
+#if LONG_MAX < 8 * ASIZE
+# define ASIZE 4096
+#endif
+
+extern void abort (void);
+
+int __attribute__((noinline))
+foo (const char *s)
+{
+ if (!s)
+ return 1;
+ if (s[0] != 'a')
+ abort ();
+ s += ASIZE - 1;
+ if (s[0] != 'b')
+ abort ();
+ return 0;
+}
+
+int (*fn) (const char *) = foo;
+
+int __attribute__((noinline))
+bar (void)
+{
+ char s[ASIZE];
+ s[0] = 'a';
+ s[ASIZE - 1] = 'b';
+ foo (s);
+ foo (s);
+ return 0;
+}
+
+int __attribute__((noinline))
+baz (long i)
+{
+ if (i)
+ return fn (0);
+ else
+ {
+ char s[ASIZE];
+ s[0] = 'a';
+ s[ASIZE - 1] = 'b';
+ foo (s);
+ foo (s);
+ return fn (0);
+ }
+}
+
+int
+main (void)
+{
+ if (bar ())
+ abort ();
+ if (baz (0) != 1)
+ abort ();
+ if (baz (1) != 1)
+ abort ();
+ return 0;
+}
--- gcc/testsuite/gcc.c-torture/compile/20031023-2.c.jj 2003-10-23 14:19:25.000000000 +0200
+++ gcc/testsuite/gcc.c-torture/compile/20031023-2.c 2003-10-23 14:19:49.000000000 +0200
@@ -0,0 +1,2 @@
+#define ASIZE 0x1000000000UL
+#include "20031023-1.c"
--- gcc/testsuite/gcc.c-torture/compile/20031023-3.c.jj 2003-10-23 14:19:25.000000000 +0200
+++ gcc/testsuite/gcc.c-torture/compile/20031023-3.c 2003-10-23 14:20:28.000000000 +0200
@@ -0,0 +1,2 @@
+#define ASIZE 0x100000000UL
+#include "20031023-1.c"
--- gcc/testsuite/gcc.c-torture/compile/20031023-4.c.jj 2003-10-23 14:19:25.000000000 +0200
+++ gcc/testsuite/gcc.c-torture/compile/20031023-4.c 2003-10-23 14:20:51.000000000 +0200
@@ -0,0 +1,2 @@
+#define ASIZE 0x80000000UL
+#include "20031023-1.c"
Jakub