diff options
author | hjl <hjl@138bc75d-0d04-0410-961f-82ee72b054a4> | 2015-07-10 20:30:10 +0000 |
---|---|---|
committer | H.J. Lu <hjl.tools@gmail.com> | 2015-08-18 04:49:35 -0700 |
commit | 442e79de226c0f8793e5b43bcc1064b9694006d8 (patch) | |
tree | 6d3e98a1b2ea7e9fcfdd3266d59c9561fb3a60e2 | |
parent | 739f56d834080ab561fda11d1bcb0eb50ff1236e (diff) | |
download | gcc-442e79de226c0f8793e5b43bcc1064b9694006d8.tar.gz |
Allow indirect sibcall with register arguments
Indirect sibcall with register arguments is OK when there is register
available for argument passing.
gcc/
PR target/66819
* config/i386/i386.c (ix86_function_ok_for_sibcall): Allow
indirect sibcall with register arguments if register available
for argument passing.
(init_cumulative_args): Set cfun->machine->arg_reg_available
to (cum->nregs > 0) or to true if function has a variable
argument list.
(function_arg_advance_32): Set cfun->machine->arg_reg_available
to false if cum->nregs <= 0.
* config/i386/i386.h (machine_function): Add arg_reg_available.
gcc/testsuite/
PR target/66819
* gcc.target/i386/pr66819-1.c: New test.
* gcc.target/i386/pr66819-2.c: Likewise.
* gcc.target/i386/pr66819-3.c: Likewise.
* gcc.target/i386/pr66819-4.c: Likewise.
* gcc.target/i386/pr66819-5.c: Likewise.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@225688 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | gcc/config/i386/i386.c | 23 | ||||
-rw-r--r-- | gcc/config/i386/i386.h | 7 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/i386/pr66819-1.c | 8 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/i386/pr66819-2.c | 8 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/i386/pr66819-3.c | 10 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/i386/pr66819-4.c | 12 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/i386/pr66819-5.c | 10 |
7 files changed, 72 insertions, 6 deletions
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 5dcba3fbfc8..b60dda7c093 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -5533,12 +5533,16 @@ ix86_function_ok_for_sibcall (tree decl, tree exp) if (!decl || (TARGET_DLLIMPORT_DECL_ATTRIBUTES && DECL_DLLIMPORT_P (decl))) { - if (ix86_function_regparm (type, NULL) >= 3) - { - /* ??? Need to count the actual number of registers to be used, - not the possible number of registers. Fix later. */ - return false; - } + /* Check if regparm >= 3 since arg_reg_available is set to + false if regparm == 0. If regparm is 1 or 2, there is + always a call-clobbered register available. + + ??? The symbol indirect call doesn't need a call-clobbered + register. But we don't know if this is a symbol indirect + call or not here. */ + if (ix86_function_regparm (type, NULL) >= 3 + && !cfun->machine->arg_reg_available) + return false; } } @@ -6514,6 +6518,10 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, /* Argument info to initialize */ if (stdarg_p (fntype)) { cum->nregs = 0; + /* Since in 32-bit, variable arguments are always passed on + stack, there is scratch register available for indirect + sibcall. */ + cfun->machine->arg_reg_available = true; cum->sse_nregs = 0; cum->mmx_nregs = 0; cum->warn_avx512f = false; @@ -6546,6 +6554,8 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, /* Argument info to initialize */ and DFmode arguments. Warn for mismatching ABI. */ cum->float_in_sse = ix86_function_sseregparm (fntype, fndecl, true); } + + cfun->machine->arg_reg_available = (cum->nregs > 0); } /* Return the "natural" mode for TYPE. In most cases, this is just TYPE_MODE. @@ -7475,6 +7485,7 @@ function_arg_advance_32 (CUMULATIVE_ARGS *cum, machine_mode mode, if (cum->nregs <= 0) { cum->nregs = 0; + cfun->machine->arg_reg_available = false; cum->regno = 0; } break; diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index bb19902ebe5..6b199575635 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -2482,6 +2482,13 @@ struct GTY(()) machine_function { /* If true, it is safe to not save/restore DRAP register. */ BOOL_BITFIELD no_drap_save_restore : 1; + /* If true, there is register available for argument passing. This + is used only in ix86_function_ok_for_sibcall by 32-bit to determine + if there is scratch register available for indirect sibcall. In + 64-bit, rax, r10 and r11 are scratch registers which aren't used to + pass arguments and can be used for indirect sibcall. */ + BOOL_BITFIELD arg_reg_available : 1; + /* During prologue/epilogue generation, the current frame state. Otherwise, the frame state at the end of the prologue. */ struct machine_frame_state fs; diff --git a/gcc/testsuite/gcc.target/i386/pr66819-1.c b/gcc/testsuite/gcc.target/i386/pr66819-1.c new file mode 100644 index 00000000000..7c8a1ab08c3 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr66819-1.c @@ -0,0 +1,8 @@ +/* { dg-do compile { target ia32 } } */ +/* { dg-options "-O2 -mregparm=3" } */ +/* { dg-final { scan-assembler-not "call" } } */ + +void foo(void (*bar)(void)) +{ + bar(); +} diff --git a/gcc/testsuite/gcc.target/i386/pr66819-2.c b/gcc/testsuite/gcc.target/i386/pr66819-2.c new file mode 100644 index 00000000000..9de4f97a906 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr66819-2.c @@ -0,0 +1,8 @@ +/* { dg-do compile { target ia32 } } */ +/* { dg-options "-fPIC -O2 -mregparm=3" } */ +/* { dg-final { scan-assembler-not "call" } } */ + +void foo(void (*bar)(void)) +{ + bar(); +} diff --git a/gcc/testsuite/gcc.target/i386/pr66819-3.c b/gcc/testsuite/gcc.target/i386/pr66819-3.c new file mode 100644 index 00000000000..3bc5a3471e6 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr66819-3.c @@ -0,0 +1,10 @@ +/* { dg-do compile { target ia32 } } */ +/* { dg-options "-O2 -mregparm=3" } */ +/* { dg-final { scan-assembler-not "call" } } */ + +void (*bar)(int, int); + +void foo(int i, int j) +{ + bar(i, j); +} diff --git a/gcc/testsuite/gcc.target/i386/pr66819-4.c b/gcc/testsuite/gcc.target/i386/pr66819-4.c new file mode 100644 index 00000000000..18b2ccf8120 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr66819-4.c @@ -0,0 +1,12 @@ +/* { dg-do compile { target ia32 } } */ +/* { dg-options "-O2 -mregparm=3" } */ +/* { dg-final { scan-assembler-not "call" } } */ + +#include <stdarg.h> + +void (*bar)(int, va_list); + +void foo(int i, va_list args) +{ + bar(i, args); +} diff --git a/gcc/testsuite/gcc.target/i386/pr66819-5.c b/gcc/testsuite/gcc.target/i386/pr66819-5.c new file mode 100644 index 00000000000..6b019d1aefc --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr66819-5.c @@ -0,0 +1,10 @@ +/* { dg-do compile { target ia32 } } */ +/* { dg-options "-O2 -mregparm=3" } */ +/* { dg-final { scan-assembler "call" } } */ + +void (*bar)(int, int, int); + +void foo(int i, int j, int k) +{ + bar(i, j, k); +} |