On Fri, Jul 10, 2015 at 9:30 AM, Uros Bizjak <ubiz...@gmail.com> wrote: > On Thu, Jul 9, 2015 at 12:54 PM, H.J. Lu <hjl.to...@gmail.com> wrote: >> Indirect sibcall with register arguments is OK when there is register >> available for argument passing. >> >> OK for trunk if there is no regression? >> >> >> H.J. >> --- >> 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_p >> to cum->nregs != 0. >> (function_arg_advance_32): Set cfun->machine->arg_reg_available_p >> to 0 when setting cum->nregs = 0. > > Do we also need similar functionality for 64bit ABIs? What happens if > we are out of argument regs there?
64-bit is OK since we have rax, r10 and r11 as scratch registers which aren't used to pass arguments. >> * config/i386/i386.h (machine_function): Add arg_reg_available_p. >> >> 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. >> --- >> gcc/config/i386/i386.c | 15 +++++++++------ >> gcc/config/i386/i386.h | 3 +++ >> gcc/testsuite/gcc.target/i386/pr66819-1.c | 8 ++++++++ >> gcc/testsuite/gcc.target/i386/pr66819-2.c | 8 ++++++++ >> gcc/testsuite/gcc.target/i386/pr66819-3.c | 10 ++++++++++ >> gcc/testsuite/gcc.target/i386/pr66819-4.c | 12 ++++++++++++ >> gcc/testsuite/gcc.target/i386/pr66819-5.c | 10 ++++++++++ >> 7 files changed, 60 insertions(+), 6 deletions(-) >> create mode 100644 gcc/testsuite/gcc.target/i386/pr66819-1.c >> create mode 100644 gcc/testsuite/gcc.target/i386/pr66819-2.c >> create mode 100644 gcc/testsuite/gcc.target/i386/pr66819-3.c >> create mode 100644 gcc/testsuite/gcc.target/i386/pr66819-4.c >> create mode 100644 gcc/testsuite/gcc.target/i386/pr66819-5.c >> >> diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c >> index 54ee6f3..85e59a8 100644 >> --- a/gcc/config/i386/i386.c >> +++ b/gcc/config/i386/i386.c >> @@ -5628,12 +5628,12 @@ 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; >> - } >> + /* FIXME: 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_p) > > Isn't enough to look at arg_reg_available here? We need to check ix86_function_regparm since nregs is 0 if -mregparm=N isn't used and pr65753.c will fail. >> + return false; >> } >> } >> >> @@ -6567,6 +6567,7 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, /* >> Argument info to initialize */ >> ? X86_64_REGPARM_MAX >> : X86_64_MS_REGPARM_MAX); >> } >> + cfun->machine->arg_reg_available_p = cum->nregs != 0; > > false instead of 0. This is a boolean. Updated. >> if (TARGET_SSE) >> { >> cum->sse_nregs = SSE_REGPARM_MAX; >> @@ -6636,6 +6637,7 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, /* >> Argument info to initialize */ >> else >> cum->nregs = ix86_function_regparm (fntype, fndecl); >> } >> + cfun->machine->arg_reg_available_p = cum->nregs != 0; > > IMO, cum->nregs > 0 would be more descriptive. Updated. >> /* Set up the number of SSE registers used for passing SFmode >> and DFmode arguments. Warn for mismatching ABI. */ >> @@ -7584,6 +7586,7 @@ pass_in_reg: >> { >> cum->nregs = 0; >> cum->regno = 0; >> + cfun->machine->arg_reg_available_p = 0; >> } >> break; >> >> diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h >> index 74334ff..0b6e304 100644 >> --- a/gcc/config/i386/i386.h >> +++ b/gcc/config/i386/i386.h >> @@ -2479,6 +2479,9 @@ 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. */ >> + BOOL_BITFIELD arg_reg_available_p : 1; > > This is not a predicate, but a boolean flag. Please remove _p from the name. Updated. Here is the updated patch. OK for trunk? Thanks. -- H.J.
From 3bcd6c122684d896840b2feb756e9b9ab8723ecc Mon Sep 17 00:00:00 2001 From: "H.J. Lu" <hjl.to...@gmail.com> Date: Wed, 8 Jul 2015 21:10:25 -0700 Subject: [PATCH] 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. (function_arg_advance_32): Set cfun->machine->arg_reg_available to 0 when setting 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. --- gcc/config/i386/i386.c | 16 ++++++++++------ gcc/config/i386/i386.h | 3 +++ gcc/testsuite/gcc.target/i386/pr66819-1.c | 8 ++++++++ gcc/testsuite/gcc.target/i386/pr66819-2.c | 8 ++++++++ gcc/testsuite/gcc.target/i386/pr66819-3.c | 10 ++++++++++ gcc/testsuite/gcc.target/i386/pr66819-4.c | 12 ++++++++++++ gcc/testsuite/gcc.target/i386/pr66819-5.c | 10 ++++++++++ 7 files changed, 61 insertions(+), 6 deletions(-) create mode 100644 gcc/testsuite/gcc.target/i386/pr66819-1.c create mode 100644 gcc/testsuite/gcc.target/i386/pr66819-2.c create mode 100644 gcc/testsuite/gcc.target/i386/pr66819-3.c create mode 100644 gcc/testsuite/gcc.target/i386/pr66819-4.c create mode 100644 gcc/testsuite/gcc.target/i386/pr66819-5.c diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 57b8acc..c0a1993 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -5629,12 +5629,12 @@ 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; - } + /* ??? 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; } } @@ -6610,6 +6610,7 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, /* Argument info to initialize */ if (stdarg_p (fntype)) { cum->nregs = 0; + cfun->machine->arg_reg_available = false; cum->sse_nregs = 0; cum->mmx_nregs = 0; cum->warn_avx512f = false; @@ -6642,6 +6643,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. @@ -7584,6 +7587,7 @@ pass_in_reg: 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 74334ff..14006c8 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -2479,6 +2479,9 @@ 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. */ + 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 0000000..7c8a1ab --- /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 0000000..9de4f97 --- /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 0000000..3bc5a34 --- /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 0000000..18b2ccf --- /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 0000000..6b019d1 --- /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); +} -- 2.4.3