diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 24a252a..de7907a 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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  Martin Liska  <mliska@suse.cz>
 
 	PR ipa/64146
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 17ef751..122a350 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -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);
diff --git a/gcc/config/i386/i386.opt b/gcc/config/i386/i386.opt
index 3d54bfa..6dc4da2 100644
--- a/gcc/config/i386/i386.opt
+++ b/gcc/config/i386/i386.opt
@@ -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
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 15068da..33a7ed2 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -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
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 025dfce..6c06503 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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  Martin Liska  <mliska@suse.cz>
 
 	* g++.dg/ipa/pr64146.C: New test.
diff --git a/gcc/testsuite/gcc.target/i386/amd64-abi-7.c b/gcc/testsuite/gcc.target/i386/amd64-abi-7.c
new file mode 100644
index 0000000..fcca680
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/amd64-abi-7.c
@@ -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;
+}
diff --git a/gcc/testsuite/gcc.target/i386/amd64-abi-8.c b/gcc/testsuite/gcc.target/i386/amd64-abi-8.c
new file mode 100644
index 0000000..b25ceec
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/amd64-abi-8.c
@@ -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;
+}
diff --git a/gcc/testsuite/gcc.target/i386/amd64-abi-9.c b/gcc/testsuite/gcc.target/i386/amd64-abi-9.c
new file mode 100644
index 0000000..4707eb7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/amd64-abi-9.c
@@ -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;
+}
