diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index f1486ff3750..e1582f8c9a6 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -10422,25 +10422,21 @@ ix86_function_arg (cumulative_args_t cum_v, machine_mode omode,
 	{
 	  /* This is the pointer argument.  */
 	  gcc_assert (TYPE_MODE (type) == Pmode);
-	  if (cfun->machine->func_type == TYPE_INTERRUPT)
-	    /* -WORD(AP) in the current frame in interrupt handler.  */
-	    arg = plus_constant (Pmode, arg_pointer_rtx,
-				 -UNITS_PER_WORD);
-	  else
-	    /* (AP) in the current frame in exception handler.  */
-	    arg = arg_pointer_rtx;
+	  /* It is at -WORD(AP) in the current frame in interrupt and
+	     exception handlers.  */
+	  arg = plus_constant (Pmode, arg_pointer_rtx, -UNITS_PER_WORD);
 	}
       else
 	{
 	  gcc_assert (cfun->machine->func_type == TYPE_EXCEPTION
 		      && TREE_CODE (type) == INTEGER_TYPE
 		      && TYPE_MODE (type) == word_mode);
-	  /* The integer argument is the error code at -WORD(AP) in
+	  /* The integer argument is the error code at -2 * WORD(AP) in
 	     the current frame in exception handler.  */
 	  arg = gen_rtx_MEM (word_mode,
 			     plus_constant (Pmode,
 					    arg_pointer_rtx,
-					    -UNITS_PER_WORD));
+					    -2 * UNITS_PER_WORD));
 	}
       return arg;
     }
@@ -12915,8 +12911,8 @@ ix86_compute_frame_layout (void)
 	  the registers need to be saved before allocating the frame.  */
        && flag_stack_check != STATIC_BUILTIN_STACK_CHECK);
 
-  /* Skip return address.  */
-  offset = UNITS_PER_WORD;
+  /* Skip return address and error code in exception handler.  */
+  offset = INCOMING_FRAME_SP_OFFSET;
 
   /* Skip pushed static chain.  */
   if (ix86_static_chain_on_stack)
@@ -15221,8 +15217,9 @@ ix86_expand_epilogue (int style)
   m->fs.red_zone_offset = 0;
   if (ix86_using_red_zone () && crtl->args.pops_args < 65536)
     {
-      /* The red-zone begins below the return address.  */
-      m->fs.red_zone_offset = RED_ZONE_SIZE + UNITS_PER_WORD;
+      /* The red-zone begins below return address and error code in
+	 exception handler.  */
+      m->fs.red_zone_offset = RED_ZONE_SIZE + INCOMING_FRAME_SP_OFFSET;
 
       /* When the register save area is in the aligned portion of
          the stack, determine the maximum runtime displacement that
@@ -15517,18 +15514,7 @@ ix86_expand_epilogue (int style)
     }
 
   if (cfun->machine->func_type != TYPE_NORMAL)
-    {
-      /* Return with the "IRET" instruction from interrupt handler.
-	 Pop the 'ERROR_CODE' off the stack before the 'IRET'
-	 instruction in exception handler.  */
-      if (cfun->machine->func_type == TYPE_EXCEPTION)
-	{
-	  rtx r = plus_constant (Pmode, stack_pointer_rtx,
-				 UNITS_PER_WORD);
-	  emit_insn (gen_rtx_SET (stack_pointer_rtx, r));
-	}
-      emit_jump_insn (gen_interrupt_return ());
-    }
+    emit_jump_insn (gen_interrupt_return ());
   else if (crtl->args.pops_args && crtl->args.size)
     {
       rtx popc = GEN_INT (crtl->args.pops_args);
diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
index 682745ae06b..ddbd6759caf 100644
--- a/gcc/config/i386/i386.h
+++ b/gcc/config/i386/i386.h
@@ -2177,8 +2177,10 @@ extern int const svr4_dbx_register_map[FIRST_PSEUDO_REGISTER];
 /* PC is dbx register 8; let's use that column for RA.  */
 #define DWARF_FRAME_RETURN_COLUMN 	(TARGET_64BIT ? 16 : 8)
 
-/* Before the prologue, the top of the frame is at 4(%esp).  */
-#define INCOMING_FRAME_SP_OFFSET UNITS_PER_WORD
+/* Before the prologue, there are return address and error code for
+   exception handler on the top of the frame.  */
+#define INCOMING_FRAME_SP_OFFSET \
+  (UNITS_PER_WORD * (1 + (cfun->machine->func_type == TYPE_EXCEPTION)))
 
 /* Describe how we implement __builtin_eh_return.  */
 #define EH_RETURN_DATA_REGNO(N)	((N) <= DX_REG ? (N) : INVALID_REGNUM)
diff --git a/gcc/testsuite/gcc.dg/guality/pr68037-1.c b/gcc/testsuite/gcc.dg/guality/pr68037-1.c
index 74f61ec5f96..44cab58659f 100644
--- a/gcc/testsuite/gcc.dg/guality/pr68037-1.c
+++ b/gcc/testsuite/gcc.dg/guality/pr68037-1.c
@@ -59,9 +59,9 @@ main ()
   return 0;
 }
 
-/* { dg-final { gdb-test 31 "error" "0x12345670" } } */
-/* { dg-final { gdb-test 31 "frame->ip" "0x12345671" } } */
-/* { dg-final { gdb-test 31 "frame->cs" "0x12345672" } } */
-/* { dg-final { gdb-test 31 "frame->flags" "0x12345673" } } */
-/* { dg-final { gdb-test 31 "frame->sp" "0x12345674" } } */
-/* { dg-final { gdb-test 31 "frame->ss" "0x12345675" } } */
+/* { dg-final { gdb-test 33 "error" "0x12345670" } } */
+/* { dg-final { gdb-test 33 "frame->ip" "0x12345671" } } */
+/* { dg-final { gdb-test 33 "frame->cs" "0x12345672" } } */
+/* { dg-final { gdb-test 33 "frame->flags" "0x12345673" } } */
+/* { dg-final { gdb-test 33 "frame->sp" "0x12345674" } } */
+/* { dg-final { gdb-test 33 "frame->ss" "0x12345675" } } */
diff --git a/gcc/testsuite/gcc.target/i386/interrupt-5.c b/gcc/testsuite/gcc.target/i386/interrupt-5.c
index 803c0636299..5742b6f4743 100644
--- a/gcc/testsuite/gcc.target/i386/interrupt-5.c
+++ b/gcc/testsuite/gcc.target/i386/interrupt-5.c
@@ -7,12 +7,21 @@ extern void link_error (void);
 
 typedef unsigned int uword_t __attribute__ ((mode (__word__)));
 
+struct interrupt_frame
+{
+  uword_t ip;
+  uword_t cs;
+  uword_t flags;
+  uword_t sp;
+  uword_t ss;
+};
+
 __attribute__ ((used, interrupt))
 void
-foo (void *frame, uword_t error)
+foo (struct interrupt_frame *frame, uword_t error)
 {
   void *ra = __builtin_return_address (0);
-  if ((uintptr_t) ra != (uintptr_t) error)
+  if ((uintptr_t) ra != (uintptr_t) frame->ip)
     link_error ();
 }
 
diff --git a/gcc/testsuite/gcc.target/i386/pr79793-1.c b/gcc/testsuite/gcc.target/i386/pr79793-1.c
new file mode 100644
index 00000000000..a382fe9c5e2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr79793-1.c
@@ -0,0 +1,14 @@
+/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */
+/* { dg-options "-O2 -mgeneral-regs-only" } */
+
+void
+ __attribute__ ((interrupt))
+fn1 (void *frame)
+{
+  char fxsave_region [512] __attribute__((aligned(16)));
+  __builtin_ia32_fxsave64 (fxsave_region);
+}
+
+/* { dg-final { scan-assembler-times "sub\[lq\]\[\t \]*\\\$400,\[\t \]*%\[re\]sp" 1 } } */
+/* { dg-final { scan-assembler-times "fxsave64\[\t \]*-120\\(%\[re\]sp\\)" 1 } } */
+/* { dg-final { scan-assembler-times "add\[lq\]\[\t \]*\\\$400,\[\t \]*%\[re\]sp" 1 } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr79793-2.c b/gcc/testsuite/gcc.target/i386/pr79793-2.c
new file mode 100644
index 00000000000..f6ae5aed33a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr79793-2.c
@@ -0,0 +1,16 @@
+/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */
+/* { dg-options "-O2 -mgeneral-regs-only" } */
+
+typedef unsigned int uword_t __attribute__ ((mode (__word__)));
+
+void
+ __attribute__ ((interrupt))
+fn1 (void *frame, uword_t error)
+{
+  char fxsave_region [512] __attribute__((aligned(16)));
+  __builtin_ia32_fxsave64 (fxsave_region);
+}
+
+/* { dg-final { scan-assembler-times "sub\[lq\]\[\t \]*\\\$392,\[\t \]*%\[re\]sp" 1 } } */
+/* { dg-final { scan-assembler-times "fxsave64\[\t \]*-120\\(%\[re\]sp\\)" 1 } } */
+/* { dg-final { scan-assembler-times "add\[lq\]\[\t \]*\\\$400,\[\t \]*%\[re\]sp" 1 } } */
