* [PATCH] Add __builtin_argument_pointer
@ 2015-09-01 14:52 H.J. Lu
2015-09-03 17:33 ` H.J. Lu
0 siblings, 1 reply; 2+ messages in thread
From: H.J. Lu @ 2015-09-01 14:52 UTC (permalink / raw)
To: Segher Boessenkool, Jeff Law, Jakub Jelinek
Cc: Mike Stump, GCC Patches, Uros Bizjak
[-- Attachment #1: Type: text/plain, Size: 849 bytes --]
On Wed, Aug 19, 2015 at 3:35 PM, Segher Boessenkool
<segher@kernel.crashing.org> wrote:
> 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!
>
>
Here is a patch to add __builtin_argument_pointer. OK for master?
Thanks.
--
H.J.
[-- Attachment #2: 0001-Add-__builtin_argument_pointer.patch --]
[-- Type: text/x-patch, Size: 13409 bytes --]
From e1e3883d0b3fba3f9bdb6b103939d284721ad5f5 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 | 11 ++++++++++
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, 158 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 d79372c..57c6d02 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -6185,6 +6185,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);
@@ -12374,6 +12378,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 070605f..c3fc475 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..8b3792e 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -8841,6 +8841,17 @@ 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 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
+
@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
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: [PATCH] Add __builtin_argument_pointer
2015-09-01 14:52 [PATCH] Add __builtin_argument_pointer H.J. Lu
@ 2015-09-03 17:33 ` H.J. Lu
0 siblings, 0 replies; 2+ messages in thread
From: H.J. Lu @ 2015-09-03 17:33 UTC (permalink / raw)
To: Segher Boessenkool, Jeff Law, Jakub Jelinek
Cc: Mike Stump, GCC Patches, Uros Bizjak
On Tue, Sep 1, 2015 at 7:52 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Wed, Aug 19, 2015 at 3:35 PM, Segher Boessenkool
> <segher@kernel.crashing.org> wrote:
>> 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!
>>
>>
>
> Here is a patch to add __builtin_argument_pointer. OK for master?
>
I withdrew this patch.
--
H.J.
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2015-09-03 17:30 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-09-01 14:52 [PATCH] Add __builtin_argument_pointer H.J. Lu
2015-09-03 17:33 ` H.J. Lu
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).