diff mbox

Add __builtin_stack_top

Message ID CAMe9rOqLxX3h_Pn2Rn1Ph-FH41e1DfEG1qPheDLBNdycPa=sNw@mail.gmail.com
State New
Headers show

Commit Message

H.J. Lu Aug. 19, 2015, 3:25 p.m. UTC
On Wed, Aug 19, 2015 at 6:00 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Wed, Aug 19, 2015 at 5:51 AM, Segher Boessenkool
> <segher@kernel.crashing.org> wrote:
>> On Wed, Aug 19, 2015 at 05:23:41AM -0700, H.J. Lu wrote:
>>> >>> >> > You might have a reason why you want the entry stack address instead of the
>>> >>> >> > frame address, but you didn't really explain I think?  Or I missed it.
>>> >>
>>> >> What would a C program do with this, that it cannot do with the frame
>>> >> address, that would be useful and cannot be much better done in straight
>>> >> assembler?  Do you actually want to expose the argument pointer, maybe?
>>> >
>>> > Yes, we want to use the argument pointer as shown in testcases
>>> > included in my patch.
>>>
>>> Where do we stand on this?  We need the hard stack address at
>>> function entry for x86 without using frame pointer.   I added
>>> __builtin_stack_top since __builtin_frame_address can't give
>>> us what we want.  Should __builtin_stack_top be added to
>>> middle-end or x86 backend?
>>
>> Sorry for not following up; I thought my suggestion was obvious.
>>
>> Can you do a __builtin_argument_pointer instead?  That should work
>> for all targets, afaics?
>
> To me, stack top is easier to understand and argument pointer isn't
> very clear.  Does argument pointer exist when there is no argument?
>
> But I can live with it.  I will update my patch.
>

Here is a patch to add __builtin_argument_pointer.  I only have

 -- Built-in Function: void * __builtin_argument_pointer (void)
     This function returns the argument pointer.

as documentation.  Can you suggest a better description so that it can
be implemented also by other compilers?

Thanks.

Comments

Segher Boessenkool Aug. 19, 2015, 4:58 p.m. UTC | #1
On Wed, Aug 19, 2015 at 08:25:49AM -0700, H.J. Lu wrote:
> Here is a patch to add __builtin_argument_pointer.  I only have

Sorry to be a pain but...  all the other builtins use _address
instead of _pointer, it's probably best to follow that.

>  -- Built-in Function: void * __builtin_argument_pointer (void)
>      This function returns the argument pointer.
> 
> as documentation.  Can you suggest a better description so that it can
> be implemented also by other compilers?

Maybe something like (heavily cut'n'pasted):


@deftypefn {Built-in Function} {void *} __builtin_argument_address (void)
This function is similar to @code{__builtin_frame_address} with an
argument of 0, but it returns the address of the incoming arguments to
the current function rather than the address of its frame.

The exact definition of this address depends upon the processor and the
calling convention.  Usually some arguments are passed in registers and
the rest on the stack, and this builtin returns the address of the first
argument that is on the stack.


> +      /* Can't use DRAP if the stack address has been taken.  */
> +      if (cfun->argument_pointer_taken)
> +	sorry ("%<__builtin_argument_pointer%> not supported with stack"
> +	       " realignment.  This may be worked around by adding"
> +	       " -maccumulate-outgoing-args.");

This doesn't work with DRAP?  Pity :-(

The patch looks plausible, but I of course can not approve it.

Thanks,


Segher
H.J. Lu Aug. 19, 2015, 5:08 p.m. UTC | #2
On Wed, Aug 19, 2015 at 9:58 AM, Segher Boessenkool
<segher@kernel.crashing.org> wrote:
> On Wed, Aug 19, 2015 at 08:25:49AM -0700, H.J. Lu wrote:
>> Here is a patch to add __builtin_argument_pointer.  I only have
>
> Sorry to be a pain but...  all the other builtins use _address
> instead of _pointer, it's probably best to follow that.
>
>>  -- Built-in Function: void * __builtin_argument_pointer (void)
>>      This function returns the argument pointer.
>>
>> as documentation.  Can you suggest a better description so that it can
>> be implemented also by other compilers?
>
> Maybe something like (heavily cut'n'pasted):
>
>
> @deftypefn {Built-in Function} {void *} __builtin_argument_address (void)
> This function is similar to @code{__builtin_frame_address} with an
> argument of 0, but it returns the address of the incoming arguments to
> the current function rather than the address of its frame.

This doesn't make senses when there is no argument or arguments
are passed in registers.  To me, argument pointer is a virtual concept
and an implementation detail internal to GCC.  I am not sure if another
compiler can implement it based on this description.

> The exact definition of this address depends upon the processor and the
> calling convention.  Usually some arguments are passed in registers and
> the rest on the stack, and this builtin returns the address of the first
> argument that is on the stack.
>
>
>> +      /* Can't use DRAP if the stack address has been taken.  */
>> +      if (cfun->argument_pointer_taken)
>> +     sorry ("%<__builtin_argument_pointer%> not supported with stack"
>> +            " realignment.  This may be worked around by adding"
>> +            " -maccumulate-outgoing-args.");
>
> This doesn't work with DRAP?  Pity :-(

With DRAP,  we do

      /* Replicate the return address on the stack so that return
         address can be reached via (argp - 1) slot.  This is needed
         to implement macro RETURN_ADDR_RTX and intrinsic function
         expand_builtin_return_addr etc.  */
      t = plus_constant (Pmode, crtl->drap_reg, -UNITS_PER_WORD);
      t = gen_frame_mem (word_mode, t);
      insn = emit_insn (gen_push (t));
      RTX_FRAME_RELATED_P (insn) = 1;

      /* For the purposes of frame and register save area addressing,
         we've started over with a new frame.  */
      m->fs.sp_offset = INCOMING_FRAME_SP_OFFSET;
      m->fs.realigned = true;

which doesn't work for __builtin_argument_pointer.

> The patch looks plausible, but I of course can not approve it.
>

Thanks.
Segher Boessenkool Aug. 19, 2015, 5:48 p.m. UTC | #3
On Wed, Aug 19, 2015 at 10:08:01AM -0700, H.J. Lu wrote:
> > Maybe something like (heavily cut'n'pasted):
> >
> >
> > @deftypefn {Built-in Function} {void *} __builtin_argument_address (void)
> > This function is similar to @code{__builtin_frame_address} with an
> > argument of 0, but it returns the address of the incoming arguments to
> > the current function rather than the address of its frame.
> 
> This doesn't make senses when there is no argument or arguments
> are passed in registers.

Sure, but see the weasel-words below ("The exact...")

> To me, argument pointer is a virtual concept
> and an implementation detail internal to GCC.  I am not sure if another
> compiler can implement it based on this description.

The same is true for frame_address, on many machines.

> > The exact definition of this address depends upon the processor and the
> > calling convention.  Usually some arguments are passed in registers and
> > the rest on the stack, and this builtin returns the address of the first
> > argument that is on the stack.


Segher
H.J. Lu Aug. 19, 2015, 5:53 p.m. UTC | #4
On Wed, Aug 19, 2015 at 10:48 AM, Segher Boessenkool
<segher@kernel.crashing.org> wrote:
> On Wed, Aug 19, 2015 at 10:08:01AM -0700, H.J. Lu wrote:
>> > Maybe something like (heavily cut'n'pasted):
>> >
>> >
>> > @deftypefn {Built-in Function} {void *} __builtin_argument_address (void)
>> > This function is similar to @code{__builtin_frame_address} with an
>> > argument of 0, but it returns the address of the incoming arguments to
>> > the current function rather than the address of its frame.
>>
>> This doesn't make senses when there is no argument or arguments
>> are passed in registers.
>
> Sure, but see the weasel-words below ("The exact...")
>
>> To me, argument pointer is a virtual concept
>> and an implementation detail internal to GCC.  I am not sure if another
>> compiler can implement it based on this description.
>
> The same is true for frame_address, on many machines.

Stack frame is well understood unlike argument pointer which is
pretty vague.

>> > The exact definition of this address depends upon the processor and the
>> > calling convention.  Usually some arguments are passed in registers and
>> > the rest on the stack, and this builtin returns the address of the first
>> > argument that is on the stack.
>
>
> Segher
H.J. Lu Aug. 19, 2015, 9:53 p.m. UTC | #5
On Wed, Aug 19, 2015 at 10:53 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Wed, Aug 19, 2015 at 10:48 AM, Segher Boessenkool
> <segher@kernel.crashing.org> wrote:
>> On Wed, Aug 19, 2015 at 10:08:01AM -0700, H.J. Lu wrote:
>>> > Maybe something like (heavily cut'n'pasted):
>>> >
>>> >
>>> > @deftypefn {Built-in Function} {void *} __builtin_argument_address (void)
>>> > This function is similar to @code{__builtin_frame_address} with an
>>> > argument of 0, but it returns the address of the incoming arguments to
>>> > the current function rather than the address of its frame.
>>>
>>> This doesn't make senses when there is no argument or arguments
>>> are passed in registers.
>>
>> Sure, but see the weasel-words below ("The exact...")
>>
>>> To me, argument pointer is a virtual concept
>>> and an implementation detail internal to GCC.  I am not sure if another
>>> compiler can implement it based on this description.
>>
>> The same is true for frame_address, on many machines.
>
> Stack frame is well understood unlike argument pointer which is
> pretty vague.
>

How about this

@deftypefn {Built-in Function} {void *} __builtin_argument_pointer (void)
This function is similar to @code{__builtin_frame_address} with an
argument of 0, but it returns the address of the incoming arguments to
the current function rather than the address of its frame.  Unlike
@code{__builtin_frame_address}, the frame pointer register isn't
required.

The exact definition of this address depends upon the processor and the
calling convention.  Usually some arguments are passed in registers and
the rest on the stack, and this builtin returns the address of the
first argument which would be passed on the stack.
@end deftypefn
Segher Boessenkool Aug. 19, 2015, 10:10 p.m. UTC | #6
On Wed, Aug 19, 2015 at 02:53:47PM -0700, H.J. Lu wrote:
> How about this
> 
> @deftypefn {Built-in Function} {void *} __builtin_argument_pointer (void)
> This function is similar to @code{__builtin_frame_address} with an
> argument of 0, but it returns the address of the incoming arguments to
> the current function rather than the address of its frame.  Unlike
> @code{__builtin_frame_address}, the frame pointer register isn't
> required.

That last line isn't true, if your port uses INITIAL_FRAME_POINTER_RTX.
Maybe it shouldn't be true otherwise either (but currently a hard frame
pointer is forced, indeed).  Have we gone full circle now? ;-)

> The exact definition of this address depends upon the processor and the
> calling convention.  Usually some arguments are passed in registers and
> the rest on the stack, and this builtin returns the address of the
> first argument which would be passed on the stack.
> @end deftypefn


Segher
H.J. Lu Aug. 19, 2015, 10:18 p.m. UTC | #7
On Wed, Aug 19, 2015 at 3:10 PM, Segher Boessenkool
<segher@kernel.crashing.org> wrote:
> On Wed, Aug 19, 2015 at 02:53:47PM -0700, H.J. Lu wrote:
>> How about this
>>
>> @deftypefn {Built-in Function} {void *} __builtin_argument_pointer (void)
>> This function is similar to @code{__builtin_frame_address} with an
>> argument of 0, but it returns the address of the incoming arguments to
>> the current function rather than the address of its frame.  Unlike
>> @code{__builtin_frame_address}, the frame pointer register isn't
>> required.
>
> That last line isn't true, if your port uses INITIAL_FRAME_POINTER_RTX.
> Maybe it shouldn't be true otherwise either (but currently a hard frame
> pointer is forced, indeed).  Have we gone full circle now? ;-)

Let's drop it:


@deftypefn {Built-in Function} {void *} __builtin_argument_pointer (void)
This function is similar to @code{__builtin_frame_address} with an
argument of 0, but it returns the address of the incoming arguments to
the current function rather than the address of its frame.

The exact definition of this address depends upon the processor and the
calling convention.  Usually some arguments are passed in registers and
the rest on the stack, and this builtin returns the address of the
first argument which would be passed on the stack.
@end deftypefn
Segher Boessenkool Aug. 19, 2015, 10:35 p.m. UTC | #8
On Wed, Aug 19, 2015 at 03:18:46PM -0700, H.J. Lu wrote:
> @deftypefn {Built-in Function} {void *} __builtin_argument_pointer (void)
> This function is similar to @code{__builtin_frame_address} with an
> argument of 0, but it returns the address of the incoming arguments to
> the current function rather than the address of its frame.
> 
> The exact definition of this address depends upon the processor and the
> calling convention.  Usually some arguments are passed in registers and
> the rest on the stack, and this builtin returns the address of the
> first argument which would be passed on the stack.
> @end deftypefn

That is fine by me.  Thanks!


Segher
diff mbox

Patch

From 9af08fdda587e1876e09840499000e35cc841e96 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Tue, 21 Jul 2015 14:32:09 -0700
Subject: [PATCH] Add __builtin_argument_pointer

When __builtin_frame_address is used to retrieve the address of the
function stack frame, the frame pointer register is required, which
wastes one register and 2 instructions.  For x86-32, one less register
means significant negative impact on performance.  This patch adds a
new builtin function, __builtin_argument_pointer.  It returns the
argument pointer, which, on x86, can be used to compute the stack
address when the function is called by subtracting the size of integer
register.

gcc/

	PR target/66960
	* builtin-types.def (BT_FN_PTR_VOID): New function type.
	* builtins.c (expand_builtin): Handle BUILT_IN_ARGUMENT_POINTER.
	(is_simple_builtin): Likewise.
	* ipa-pure-const.c (special_builtin_state): Likewise.
	* builtins.def: Add BUILT_IN_ARGUMENT_POINTER.
	* function.h (function): Add argument_pointer_taken.
	* config/i386/i386.c (ix86_expand_prologue): Sorry if DRAP is
	used and the argument pointer has been taken.
	* doc/extend.texi: Document __builtin_argument_pointer.

gcc/testsuite/

	PR target/66960
	* gcc.target/i386/pr66960-1.c: New test.
	* gcc.target/i386/pr66960-2.c: Likewise.
	* gcc.target/i386/pr66960-3.c: Likewise.
	* gcc.target/i386/pr66960-4.c: Likewise.
	* gcc.target/i386/pr66960-5.c: Likewise.
---
 gcc/builtin-types.def                     |  1 +
 gcc/builtins.c                            |  5 +++++
 gcc/builtins.def                          |  1 +
 gcc/config/i386/i386.c                    |  6 ++++++
 gcc/doc/extend.texi                       |  4 ++++
 gcc/function.h                            |  3 +++
 gcc/ipa-pure-const.c                      |  1 +
 gcc/testsuite/gcc.target/i386/pr66960-1.c | 34 +++++++++++++++++++++++++++++++
 gcc/testsuite/gcc.target/i386/pr66960-2.c | 34 +++++++++++++++++++++++++++++++
 gcc/testsuite/gcc.target/i386/pr66960-3.c | 18 ++++++++++++++++
 gcc/testsuite/gcc.target/i386/pr66960-4.c | 22 ++++++++++++++++++++
 gcc/testsuite/gcc.target/i386/pr66960-5.c | 22 ++++++++++++++++++++
 12 files changed, 151 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/i386/pr66960-1.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr66960-2.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr66960-3.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr66960-4.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr66960-5.c

diff --git a/gcc/builtin-types.def b/gcc/builtin-types.def
index 0e34531..2b6b5ab 100644
--- a/gcc/builtin-types.def
+++ b/gcc/builtin-types.def
@@ -177,6 +177,7 @@  DEF_FUNCTION_TYPE_1 (BT_FN_COMPLEX_LONGDOUBLE_LONGDOUBLE,
 		     BT_COMPLEX_LONGDOUBLE, BT_LONGDOUBLE)
 DEF_FUNCTION_TYPE_1 (BT_FN_PTR_UINT, BT_PTR, BT_UINT)
 DEF_FUNCTION_TYPE_1 (BT_FN_PTR_SIZE, BT_PTR, BT_SIZE)
+DEF_FUNCTION_TYPE_1 (BT_FN_PTR_VOID, BT_PTR, BT_VOID)
 DEF_FUNCTION_TYPE_1 (BT_FN_INT_INT, BT_INT, BT_INT)
 DEF_FUNCTION_TYPE_1 (BT_FN_INT_UINT, BT_INT, BT_UINT)
 DEF_FUNCTION_TYPE_1 (BT_FN_INT_LONG, BT_INT, BT_LONG)
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 31969ca..b1cfa44 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -6206,6 +6206,10 @@  expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode,
     case BUILT_IN_CONSTANT_P:
       return const0_rtx;
 
+    case BUILT_IN_ARGUMENT_POINTER:
+      cfun->argument_pointer_taken = true;
+      return arg_pointer_rtx;
+
     case BUILT_IN_FRAME_ADDRESS:
     case BUILT_IN_RETURN_ADDRESS:
       return expand_builtin_frame_address (fndecl, exp);
@@ -12395,6 +12399,7 @@  is_simple_builtin (tree decl)
       case BUILT_IN_RETURN:
       case BUILT_IN_AGGREGATE_INCOMING_ADDRESS:
       case BUILT_IN_FRAME_ADDRESS:
+      case BUILT_IN_ARGUMENT_POINTER:
       case BUILT_IN_VA_END:
       case BUILT_IN_STACK_SAVE:
       case BUILT_IN_STACK_RESTORE:
diff --git a/gcc/builtins.def b/gcc/builtins.def
index f7ac4a8..3bc9615 100644
--- a/gcc/builtins.def
+++ b/gcc/builtins.def
@@ -778,6 +778,7 @@  DEF_EXT_LIB_BUILTIN    (BUILT_IN_FFSL, "ffsl", BT_FN_INT_LONG, ATTR_CONST_NOTHRO
 DEF_EXT_LIB_BUILTIN    (BUILT_IN_FFSLL, "ffsll", BT_FN_INT_LONGLONG, ATTR_CONST_NOTHROW_LEAF_LIST)
 DEF_EXT_LIB_BUILTIN        (BUILT_IN_FORK, "fork", BT_FN_PID, ATTR_NOTHROW_LIST)
 DEF_GCC_BUILTIN        (BUILT_IN_FRAME_ADDRESS, "frame_address", BT_FN_PTR_UINT, ATTR_NULL)
+DEF_GCC_BUILTIN        (BUILT_IN_ARGUMENT_POINTER, "argument_pointer", BT_FN_PTR_VOID, ATTR_NULL)
 /* [trans-mem]: Adjust BUILT_IN_TM_FREE if BUILT_IN_FREE is changed.  */
 DEF_LIB_BUILTIN        (BUILT_IN_FREE, "free", BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
 DEF_GCC_BUILTIN        (BUILT_IN_FROB_RETURN_ADDR, "frob_return_addr", BT_FN_PTR_PTR, ATTR_NULL)
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 05fa5e1..1594fb9 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -11577,6 +11577,12 @@  ix86_expand_prologue (void)
     {
       int align_bytes = crtl->stack_alignment_needed / BITS_PER_UNIT;
 
+      /* Can't use DRAP if the stack address has been taken.  */
+      if (cfun->argument_pointer_taken)
+	sorry ("%<__builtin_argument_pointer%> not supported with stack"
+	       " realignment.  This may be worked around by adding"
+	       " -maccumulate-outgoing-args.");
+
       /* Only need to push parameter pointer reg if it is caller saved.  */
       if (!call_used_regs[REGNO (crtl->drap_reg)])
 	{
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index dba8b43..620f038 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -8841,6 +8841,10 @@  option is in effect.  Such calls should only be made in debugging
 situations.
 @end deftypefn
 
+@deftypefn {Built-in Function} {void *} __builtin_argument_pointer (void)
+This function returns the argument pointer.
+@end deftypefn
+
 @node Vector Extensions
 @section Using Vector Instructions through Built-in Functions
 
diff --git a/gcc/function.h b/gcc/function.h
index e92c17c..41bdaed 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -378,6 +378,9 @@  struct GTY(()) function {
 
   /* Set when the tail call has been identified.  */
   unsigned int tail_call_marked : 1;
+
+  /* Set when argument pointer has been taken.  */
+  unsigned int argument_pointer_taken : 1;
 };
 
 /* Add the decl D to the local_decls list of FUN.  */
diff --git a/gcc/ipa-pure-const.c b/gcc/ipa-pure-const.c
index 8fd8c36..31c289d 100644
--- a/gcc/ipa-pure-const.c
+++ b/gcc/ipa-pure-const.c
@@ -480,6 +480,7 @@  special_builtin_state (enum pure_const_state_e *state, bool *looping,
 	case BUILT_IN_CXA_END_CLEANUP:
 	case BUILT_IN_EH_COPY_VALUES:
 	case BUILT_IN_FRAME_ADDRESS:
+	case BUILT_IN_ARGUMENT_POINTER:
 	case BUILT_IN_APPLY:
 	case BUILT_IN_APPLY_ARGS:
 	  *looping = false;
diff --git a/gcc/testsuite/gcc.target/i386/pr66960-1.c b/gcc/testsuite/gcc.target/i386/pr66960-1.c
new file mode 100644
index 0000000..d8caa4f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr66960-1.c
@@ -0,0 +1,34 @@ 
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fomit-frame-pointer" { target { lp64 } } } */
+/* { dg-options "-O2 -fomit-frame-pointer -maddress-mode=short" { target { x32 } } } */
+/* { dg-options "-O2 -fomit-frame-pointer -miamcu -fno-pic" { target { ia32 } } } */
+
+extern char **environ;
+extern void exit (int status);
+extern int main (long argc, char **argv, char **envp);
+
+void
+_start (void)
+{
+  void *argc_p = (__builtin_argument_pointer ()
+		  - sizeof (int __attribute__ ((mode (__word__)))));
+  char **argv = (char **) (argc_p + sizeof (void *));
+  long argc = *(long *) argc_p;
+  int status;
+
+  environ = argv + argc + 1;
+
+  status = main (argc, argv, environ);
+
+  exit (status);
+}
+
+/* { dg-final { scan-assembler "movq\[ \t\]8\\(%rsp\\), %rdi" { target lp64 } } } */
+/* { dg-final { scan-assembler "leaq\[ \t\]16\\(%rsp\\), %rsi" { target lp64 } } } */
+/* { dg-final { scan-assembler "leaq\[ \t\]24\\(%rsp,%rdi,8\\), %rdx" { target lp64 } } } */
+/* { dg-final { scan-assembler "movl\[ \t\]8\\(%esp\\), %edi" { target x32 } } } */
+/* { dg-final { scan-assembler "leal\[ \t\]12\\(%rsp\\), %esi" { target x32 } } } */
+/* { dg-final { scan-assembler "leal\[ \t\]4\\(%rsi,%rdi,4\\), %edx" { target x32 } } } */
+/* { dg-final { scan-assembler "movl\[ \t\]\\(%esp\\), %eax" { target ia32 } } } */
+/* { dg-final { scan-assembler "leal\[ \t\]4\\(%esp\\), %edx" { target ia32 } } } */
+/* { dg-final { scan-assembler "leal\[ \t\]8\\(%esp,%eax,4\\), %ecx" { target ia32 } } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr66960-2.c b/gcc/testsuite/gcc.target/i386/pr66960-2.c
new file mode 100644
index 0000000..f4d2ef6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr66960-2.c
@@ -0,0 +1,34 @@ 
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fno-omit-frame-pointer" { target { lp64 } } } */
+/* { dg-options "-O2 -fno-omit-frame-pointer -maddress-mode=short" { target { x32 } } } */
+/* { dg-options "-O2 -fno-omit-frame-pointer -miamcu" { target { ia32 } } } */
+
+extern char **environ;
+extern void exit (int status);
+extern int main (long argc, char **argv, char **envp);
+
+void
+_start (void)
+{
+  void *argc_p = (__builtin_argument_pointer ()
+		  - sizeof (int __attribute__ ((mode (__word__)))));
+  char **argv = (char **) (argc_p + sizeof (void *));
+  long argc = *(long *) argc_p;
+  int status;
+
+  environ = argv + argc + 1;
+
+  status = main (argc, argv, environ);
+
+  exit (status);
+}
+
+/* { dg-final { scan-assembler "movq\[ \t\]8\\(%rbp\\), %rdi" { target lp64 } } } */
+/* { dg-final { scan-assembler "leaq\[ \t\]16\\(%rbp\\), %rsi" { target lp64 } } } */
+/* { dg-final { scan-assembler "leaq\[ \t\]24\\(%rbp,%rdi,8\\), %rdx" { target lp64 } } } */
+/* { dg-final { scan-assembler "movl\[ \t\]8\\(%ebp\\), %edi" { target x32 } } } */
+/* { dg-final { scan-assembler "leal\[ \t\]12\\(%rbp\\), %esi" { target x32 } } } */
+/* { dg-final { scan-assembler "leal\[ \t\]4\\(%rsi,%rdi,4\\), %edx" { target x32 } } } */
+/* { dg-final { scan-assembler "movl\[ \t\]4\\(%ebp\\), %eax" { target ia32 } } } */
+/* { dg-final { scan-assembler "leal\[ \t\]8\\(%ebp\\), %edx" { target ia32 } } } */
+/* { dg-final { scan-assembler "leal\[ \t\]12\\(%ebp,%eax,4\\), %ecx" { target ia32 } } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr66960-3.c b/gcc/testsuite/gcc.target/i386/pr66960-3.c
new file mode 100644
index 0000000..7eb2608
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr66960-3.c
@@ -0,0 +1,18 @@ 
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -mno-accumulate-outgoing-args" { target { lp64 } } } */
+/* { dg-options "-O2 -mno-accumulate-outgoing-args -maddress-mode=short" { target { x32 } } } */
+/* { dg-options "-O2 -mno-accumulate-outgoing-args -miamcu" { target { ia32 } } } */
+
+extern void abort (void);
+extern int check_int (int *i, int align);
+typedef int aligned __attribute__((aligned(64)));
+
+void *
+foo (void)
+{
+  aligned j;
+  if (check_int (&j, __alignof__(j)) != j)
+    abort ();
+  return (__builtin_argument_pointer ()
+	  - sizeof (int __attribute__ ((mode (__word__)))));
+} /* { dg-message "sorry, unimplemented: .__builtin_argument_pointer. not supported" } */
diff --git a/gcc/testsuite/gcc.target/i386/pr66960-4.c b/gcc/testsuite/gcc.target/i386/pr66960-4.c
new file mode 100644
index 0000000..361e91c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr66960-4.c
@@ -0,0 +1,22 @@ 
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -maccumulate-outgoing-args" { target { lp64 } } } */
+/* { dg-options "-O2 -maccumulate-outgoing-args -maddress-mode=short" { target { x32 } } } */
+/* { dg-options "-O2 -maccumulate-outgoing-args -miamcu" { target { ia32 } } } */
+
+extern void abort (void);
+extern int check_int (int *i, int align);
+typedef int aligned __attribute__((aligned(64)));
+
+void *
+foo (void)
+{
+  aligned j;
+  if (check_int (&j, __alignof__(j)) != j)
+    abort ();
+  return (__builtin_argument_pointer ()
+	  - sizeof (int __attribute__ ((mode (__word__)))));
+}
+
+/* { dg-final { scan-assembler "leaq\[ \t\]8\\(%rbp\\), %rax" { target lp64 } } } */
+/* { dg-final { scan-assembler "leal\[ \t\]8\\(%rbp\\), %eax" { target x32 } } } */
+/* { dg-final { scan-assembler "leal\[ \t\]4\\(%ebp\\), %eax" { target ia32 } } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr66960-5.c b/gcc/testsuite/gcc.target/i386/pr66960-5.c
new file mode 100644
index 0000000..f70a258
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr66960-5.c
@@ -0,0 +1,22 @@ 
+/* { dg-do link } */
+/* { dg-options "-O" } */
+
+extern void link_error (void);
+
+__attribute__ ((noinline, noclone))
+void
+foo (void)
+{
+  void **p = (__builtin_argument_pointer ()
+	      - sizeof (int __attribute__ ((mode (__word__)))));
+  void *ra = __builtin_return_address (0);
+  if (*p != ra)
+    link_error ();
+}
+
+int
+main (void)
+{
+  foo ();
+  return 0;
+}
-- 
2.4.3