Message ID | CAMe9rOqLxX3h_Pn2Rn1Ph-FH41e1DfEG1qPheDLBNdycPa=sNw@mail.gmail.com |
---|---|
State | New |
Headers | show |
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
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.
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
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
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
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
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
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
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