X86-64: Add -mskip-rax-setup

The Linux kernel never passes floating point arguments around, vararg
functions or not. Hence no vector registers are ever used when calling a
vararg function.  But gcc still dutifully emits an "xor %eax,%eax" before
each and every call of a vararg function.  Since no callee use that for
anything, these instructions are redundant.

This patch adds the -mskip-rax-setup option to skip setting up RAX
register when SSE is disabled and there are no variable arguments passed
in vector registers.  Since RAX register is used to avoid unnecessarily
saving vector registers on stack when passing variable arguments, the
impacts of this option are callees may waste some stack space, misbehave
or jump to a random location.  GCC 4.4 or newer don't those issues,
regardless the RAX register value since they don't check the RAX register
value when SSE is disabled.

gcc/

	* config/i386/i386.c (ix86_expand_call): Skip setting up RAX
	register for -mskip-rax-setup when there are no parameters
	passed in vector registers.
	* config/i386/i386.opt (mskip-rax-setup): New option.
	* doc/invoke.texi: Document -mskip-rax-setup.

gcc/testsuite/

	* gcc.target/i386/amd64-abi-7.c: New tests.
	* gcc.target/i386/amd64-abi-8.c: Likwise.
	* gcc.target/i386/amd64-abi-9.c: Likwise.

From-SVN: r218870
This commit is contained in:
H.J. Lu 2014-12-18 17:35:45 +00:00 committed by H.J. Lu
parent 8448880117
commit fbe575b652
8 changed files with 119 additions and 1 deletions

View File

@ -1,3 +1,11 @@
2014-12-18 H.J. Lu <hongjiu.lu@intel.com>
* config/i386/i386.c (ix86_expand_call): Skip setting up RAX
register for -mskip-rax-setup when there are no parameters
passed in vector registers.
* config/i386/i386.opt (mskip-rax-setup): New option.
* doc/invoke.texi: Document -mskip-rax-setup.
2014-12-18 Alan Lawrence <alan.lawrence@arm.com>
* config/aarch64/aarch64-simd.md (aarch64_lshr_simddi): Handle shift

View File

@ -25461,7 +25461,12 @@ ix86_expand_call (rtx retval, rtx fnaddr, rtx callarg1,
}
}
if (TARGET_64BIT && INTVAL (callarg2) >= 0)
/* Skip setting up RAX register for -mskip-rax-setup when there are no
parameters passed in vector registers. */
if (TARGET_64BIT
&& (INTVAL (callarg2) > 0
|| (INTVAL (callarg2) == 0
&& (TARGET_SSE || !flag_skip_rax_setup))))
{
rtx al = gen_rtx_REG (QImode, AX_REG);
emit_move_insn (al, callarg2);

View File

@ -831,6 +831,10 @@ Target Report Var(flag_nop_mcount) Init(0)
Generate mcount/__fentry__ calls as nops. To activate they need to be
patched in.
mskip-rax-setup
Target Report Var(flag_skip_rax_setup) Init(0)
Skip setting up RAX register when passing variable arguments.
m8bit-idiv
Target Report Mask(USE_8BIT_IDIV) Save
Expand 32bit/64bit integer divide into 8bit unsigned integer divide with run-time check

View File

@ -16256,6 +16256,19 @@ the profiling functions as nops. This is useful when they
should be patched in later dynamically. This is likely only
useful together with @option{-mrecord-mcount}.
@item -mskip-rax-setup
@itemx -mno-skip-rax-setup
@opindex mskip-rax-setup
When generating code for the x86-64 architecture with SSE extensions
disabled, @option{-skip-rax-setup} can be used to skip setting up RAX
register when there are no variable arguments passed in vector registers.
@strong{Warning:} Since RAX register is used to avoid unnecessarily
saving vector registers on stack when passing variable arguments, the
impacts of this option are callees may waste some stack space,
misbehave or jump to a random location. GCC 4.4 or newer don't have
those issues, regardless the RAX register value.
@item -m8bit-idiv
@itemx -mno-8bit-idiv
@opindex 8bit-idiv

View File

@ -1,3 +1,9 @@
2014-12-18 H.J. Lu <hongjiu.lu@intel.com>
* gcc.target/i386/amd64-abi-7.c: New tests.
* gcc.target/i386/amd64-abi-8.c: Likwise.
* gcc.target/i386/amd64-abi-9.c: Likwise.
2014-12-18 Alan Lawrence <alan.lawrence@arm.com>
* gcc.target/aarch64/ushr64_1.c: Remove scan-assembler "ushr...64".

View File

@ -0,0 +1,46 @@
/* { dg-do run { target { ! { ia32 } } } } */
/* { dg-options "-O2 -mno-sse" } */
#include <stdarg.h>
#include <assert.h>
int n1 = 30;
int n2 = 324;
void *n3 = (void *) &n2;
int n4 = 407;
int e1;
int e2;
void *e3;
int e4;
static void
__attribute__((noinline))
foo (va_list va_arglist)
{
e2 = va_arg (va_arglist, int);
e3 = va_arg (va_arglist, void *);
e4 = va_arg (va_arglist, int);
}
static void
__attribute__((noinline))
test (int a1, ...)
{
va_list va_arglist;
e1 = a1;
va_start (va_arglist, a1);
foo (va_arglist);
va_end (va_arglist);
}
int
main ()
{
test (n1, n2, n3, n4);
assert (n1 == e1);
assert (n2 == e2);
assert (n3 == e3);
assert (n4 == e4);
return 0;
}

View File

@ -0,0 +1,18 @@
/* { dg-do compile { target { ! { ia32 } } } } */
/* { dg-options "-O2 -mno-sse -mskip-rax-setup" } */
/* { dg-final { scan-assembler-not "xorl\[\\t \]*\\\%eax,\[\\t \]*%eax" } } */
void foo (const char *, ...);
void
test1 (void)
{
foo ("%d", 20);
}
int
test2 (void)
{
foo ("%d", 20);
return 3;
}

View File

@ -0,0 +1,18 @@
/* { dg-do compile { target { ! { ia32 } } } } */
/* { dg-options "-O2 -mno-sse -mno-skip-rax-setup" } */
/* { dg-final { scan-assembler-times "xorl\[\\t \]*\\\%eax,\[\\t \]*%eax" 2 } } */
void foo (const char *, ...);
void
test1 (void)
{
foo ("%d", 20);
}
int
test2 (void)
{
foo ("%d", 20);
return 3;
}