Index: i386.h
===================================================================
--- i386.h	(revision 163716)
+++ i386.h	(working copy)
@@ -274,10 +274,10 @@ enum ix86_tune_indices {
   X86_TUNE_HIMODE_MATH,
   X86_TUNE_PROMOTE_QI_REGS,
   X86_TUNE_PROMOTE_HI_REGS,
-  X86_TUNE_ADD_ESP_4,
-  X86_TUNE_ADD_ESP_8,
-  X86_TUNE_SUB_ESP_4,
-  X86_TUNE_SUB_ESP_8,
+  X86_TUNE_SINGLE_POP,
+  X86_TUNE_DOUBLE_POP,
+  X86_TUNE_SINGLE_PUSH,
+  X86_TUNE_DOUBLE_PUSH,
   X86_TUNE_INTEGER_DFMODE_MOVES,
   X86_TUNE_PARTIAL_REG_DEPENDENCY,
   X86_TUNE_SSE_PARTIAL_REG_DEPENDENCY,
@@ -348,10 +348,10 @@ extern unsigned char ix86_tune_features[
 #define TARGET_HIMODE_MATH	ix86_tune_features[X86_TUNE_HIMODE_MATH]
 #define TARGET_PROMOTE_QI_REGS	ix86_tune_features[X86_TUNE_PROMOTE_QI_REGS]
 #define TARGET_PROMOTE_HI_REGS	ix86_tune_features[X86_TUNE_PROMOTE_HI_REGS]
-#define TARGET_ADD_ESP_4	ix86_tune_features[X86_TUNE_ADD_ESP_4]
-#define TARGET_ADD_ESP_8	ix86_tune_features[X86_TUNE_ADD_ESP_8]
-#define TARGET_SUB_ESP_4	ix86_tune_features[X86_TUNE_SUB_ESP_4]
-#define TARGET_SUB_ESP_8	ix86_tune_features[X86_TUNE_SUB_ESP_8]
+#define TARGET_SINGLE_POP	ix86_tune_features[X86_TUNE_SINGLE_POP]
+#define TARGET_DOUBLE_POP	ix86_tune_features[X86_TUNE_DOUBLE_POP]
+#define TARGET_SINGLE_PUSH	ix86_tune_features[X86_TUNE_SINGLE_PUSH]
+#define TARGET_DOUBLE_PUSH	ix86_tune_features[X86_TUNE_DOUBLE_PUSH]
 #define TARGET_INTEGER_DFMODE_MOVES \
 	ix86_tune_features[X86_TUNE_INTEGER_DFMODE_MOVES]
 #define TARGET_PARTIAL_REG_DEPENDENCY \
Index: i386.md
===================================================================
--- i386.md	(revision 163716)
+++ i386.md	(working copy)
@@ -1749,7 +1749,7 @@
   [(set_attr "type" "push")
    (set_attr "mode" "<MODE>")])
 
-(define_insn "pop<mode>1"
+(define_insn "*pop<mode>1"
   [(set (match_operand:P 0 "nonimmediate_operand" "=r*m")
 	(match_operand:P 1 "pop_operand" ">"))]
   ""
@@ -17025,202 +17025,131 @@
 ;; alternative when no register is available later.
 
 (define_peephole2
-  [(match_scratch:SI 0 "r")
-   (parallel [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int -4)))
+  [(match_scratch:P 1 "r")
+   (parallel [(set (reg:P SP_REG)
+		   (plus:P (reg:P SP_REG)
+			   (match_operand:P 0 "const_int_operand" "")))
 	      (clobber (reg:CC FLAGS_REG))
 	      (clobber (mem:BLK (scratch)))])]
-  "optimize_insn_for_size_p () || !TARGET_SUB_ESP_4"
-  [(clobber (match_dup 0))
-   (parallel [(set (mem:SI (pre_dec:SI (reg:SI SP_REG))) (match_dup 0))
+  "(TARGET_SINGLE_PUSH || optimize_insn_for_size_p ())
+   && INTVAL (operands[0]) == -GET_MODE_SIZE (Pmode)"
+  [(clobber (match_dup 1))
+   (parallel [(set (mem:P (pre_dec:P (reg:P SP_REG))) (match_dup 1))
 	      (clobber (mem:BLK (scratch)))])])
 
 (define_peephole2
-  [(match_scratch:SI 0 "r")
-   (parallel [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int -8)))
+  [(match_scratch:P 1 "r")
+   (parallel [(set (reg:P SP_REG)
+		   (plus:P (reg:P SP_REG)
+			   (match_operand:P 0 "const_int_operand" "")))
 	      (clobber (reg:CC FLAGS_REG))
 	      (clobber (mem:BLK (scratch)))])]
-  "optimize_insn_for_size_p () || !TARGET_SUB_ESP_8"
-  [(clobber (match_dup 0))
-   (set (mem:SI (pre_dec:SI (reg:SI SP_REG))) (match_dup 0))
-   (parallel [(set (mem:SI (pre_dec:SI (reg:SI SP_REG))) (match_dup 0))
+  "(TARGET_DOUBLE_PUSH || optimize_insn_for_size_p ())
+   && INTVAL (operands[0]) == -2*GET_MODE_SIZE (Pmode)"
+  [(clobber (match_dup 1))
+   (set (mem:P (pre_dec:P (reg:P SP_REG))) (match_dup 1))
+   (parallel [(set (mem:P (pre_dec:P (reg:P SP_REG))) (match_dup 1))
 	      (clobber (mem:BLK (scratch)))])])
 
 ;; Convert esp subtractions to push.
 (define_peephole2
-  [(match_scratch:SI 0 "r")
-   (parallel [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int -4)))
-	      (clobber (reg:CC FLAGS_REG))])]
-  "optimize_insn_for_size_p () || !TARGET_SUB_ESP_4"
-  [(clobber (match_dup 0))
-   (set (mem:SI (pre_dec:SI (reg:SI SP_REG))) (match_dup 0))])
-
-(define_peephole2
-  [(match_scratch:SI 0 "r")
-   (parallel [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int -8)))
-	      (clobber (reg:CC FLAGS_REG))])]
-  "optimize_insn_for_size_p () || !TARGET_SUB_ESP_8"
-  [(clobber (match_dup 0))
-   (set (mem:SI (pre_dec:SI (reg:SI SP_REG))) (match_dup 0))
-   (set (mem:SI (pre_dec:SI (reg:SI SP_REG))) (match_dup 0))])
+  [(match_scratch:P 1 "r")
+   (parallel [(set (reg:P SP_REG)
+		   (plus:P (reg:P SP_REG)
+			   (match_operand:P 0 "const_int_operand" "")))
+	      (clobber (reg:CC FLAGS_REG))])]
+  "(TARGET_SINGLE_PUSH || optimize_insn_for_size_p ())
+   && INTVAL (operands[0]) == -GET_MODE_SIZE (Pmode)"
+  [(clobber (match_dup 1))
+   (set (mem:P (pre_dec:P (reg:P SP_REG))) (match_dup 1))])
+
+(define_peephole2
+  [(match_scratch:P 1 "r")
+   (parallel [(set (reg:P SP_REG)
+		   (plus:P (reg:P SP_REG)
+			   (match_operand:P 0 "const_int_operand" "")))
+	      (clobber (reg:CC FLAGS_REG))])]
+  "(TARGET_DOUBLE_PUSH || optimize_insn_for_size_p ())
+   && INTVAL (operands[0]) == -2*GET_MODE_SIZE (Pmode)"
+  [(clobber (match_dup 1))
+   (set (mem:P (pre_dec:P (reg:P SP_REG))) (match_dup 1))
+   (set (mem:P (pre_dec:P (reg:P SP_REG))) (match_dup 1))])
 
 ;; Convert epilogue deallocator to pop.
 (define_peephole2
-  [(match_scratch:SI 0 "r")
-   (parallel [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int 4)))
+  [(match_scratch:P 1 "r")
+   (parallel [(set (reg:P SP_REG)
+		   (plus:P (reg:P SP_REG)
+			   (match_operand:P 0 "const_int_operand" "")))
 	      (clobber (reg:CC FLAGS_REG))
 	      (clobber (mem:BLK (scratch)))])]
-  "optimize_insn_for_size_p () || !TARGET_ADD_ESP_4"
-  [(parallel [(set (match_dup 0) (mem:SI (post_inc:SI (reg:SI SP_REG))))
+  "(TARGET_SINGLE_POP || optimize_insn_for_size_p ())
+   && INTVAL (operands[0]) == GET_MODE_SIZE (Pmode)"
+  [(parallel [(set (match_dup 1) (mem:P (post_inc:P (reg:P SP_REG))))
 	      (clobber (mem:BLK (scratch)))])])
 
 ;; Two pops case is tricky, since pop causes dependency
 ;; on destination register.  We use two registers if available.
 (define_peephole2
-  [(match_scratch:SI 0 "r")
-   (match_scratch:SI 1 "r")
-   (parallel [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int 8)))
+  [(match_scratch:P 1 "r")
+   (match_scratch:P 2 "r")
+   (parallel [(set (reg:P SP_REG)
+		   (plus:P (reg:P SP_REG)
+			   (match_operand:P 0 "const_int_operand" "")))
 	      (clobber (reg:CC FLAGS_REG))
 	      (clobber (mem:BLK (scratch)))])]
-  "optimize_insn_for_size_p () || !TARGET_ADD_ESP_8"
-  [(parallel [(set (match_dup 0) (mem:SI (post_inc:SI (reg:SI SP_REG))))
+  "(TARGET_DOUBLE_POP || optimize_insn_for_size_p ())
+   && INTVAL (operands[0]) == 2*GET_MODE_SIZE (Pmode)"
+  [(parallel [(set (match_dup 1) (mem:P (post_inc:P (reg:P SP_REG))))
 	      (clobber (mem:BLK (scratch)))])
-   (set (match_dup 1) (mem:SI (post_inc:SI (reg:SI SP_REG))))])
+   (set (match_dup 2) (mem:P (post_inc:P (reg:P SP_REG))))])
 
 (define_peephole2
-  [(match_scratch:SI 0 "r")
-   (parallel [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int 8)))
+  [(match_scratch:P 1 "r")
+   (parallel [(set (reg:P SP_REG)
+		   (plus:P (reg:P SP_REG)
+			   (match_operand:P 0 "const_int_operand" "")))
 	      (clobber (reg:CC FLAGS_REG))
 	      (clobber (mem:BLK (scratch)))])]
-  "optimize_insn_for_size_p ()"
-  [(parallel [(set (match_dup 0) (mem:SI (post_inc:SI (reg:SI SP_REG))))
+  "optimize_insn_for_size_p ()
+   && INTVAL (operands[0]) == 2*GET_MODE_SIZE (Pmode)"
+  [(parallel [(set (match_dup 1) (mem:P (post_inc:P (reg:P SP_REG))))
 	      (clobber (mem:BLK (scratch)))])
-   (set (match_dup 0) (mem:SI (post_inc:SI (reg:SI SP_REG))))])
+   (set (match_dup 1) (mem:P (post_inc:P (reg:P SP_REG))))])
 
 ;; Convert esp additions to pop.
 (define_peephole2
-  [(match_scratch:SI 0 "r")
-   (parallel [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int 4)))
+  [(match_scratch:P 1 "r")
+   (parallel [(set (reg:P SP_REG)
+		   (plus:P (reg:P SP_REG)
+			   (match_operand:P 0 "const_int_operand" "")))
 	      (clobber (reg:CC FLAGS_REG))])]
-  ""
-  [(set (match_dup 0) (mem:SI (post_inc:SI (reg:SI SP_REG))))])
+  "INTVAL (operands[0]) == GET_MODE_SIZE (Pmode)"
+  [(set (match_dup 1) (mem:P (post_inc:P (reg:P SP_REG))))])
 
 ;; Two pops case is tricky, since pop causes dependency
 ;; on destination register.  We use two registers if available.
 (define_peephole2
-  [(match_scratch:SI 0 "r")
-   (match_scratch:SI 1 "r")
-   (parallel [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int 8)))
-	      (clobber (reg:CC FLAGS_REG))])]
-  ""
-  [(set (match_dup 0) (mem:SI (post_inc:SI (reg:SI SP_REG))))
-   (set (match_dup 1) (mem:SI (post_inc:SI (reg:SI SP_REG))))])
-
-(define_peephole2
-  [(match_scratch:SI 0 "r")
-   (parallel [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int 8)))
-	      (clobber (reg:CC FLAGS_REG))])]
-  "optimize_insn_for_size_p ()"
-  [(set (match_dup 0) (mem:SI (post_inc:SI (reg:SI SP_REG))))
-   (set (match_dup 0) (mem:SI (post_inc:SI (reg:SI SP_REG))))])
-
-(define_peephole2
-  [(match_scratch:DI 0 "r")
-   (parallel [(set (reg:DI SP_REG) (plus:DI (reg:DI SP_REG) (const_int -8)))
-	      (clobber (reg:CC FLAGS_REG))
-	      (clobber (mem:BLK (scratch)))])]
-  "optimize_insn_for_size_p () || !TARGET_SUB_ESP_4"
-  [(clobber (match_dup 0))
-   (parallel [(set (mem:DI (pre_dec:DI (reg:DI SP_REG))) (match_dup 0))
-	      (clobber (mem:BLK (scratch)))])])
-
-(define_peephole2
-  [(match_scratch:DI 0 "r")
-   (parallel [(set (reg:DI SP_REG) (plus:DI (reg:DI SP_REG) (const_int -16)))
-	      (clobber (reg:CC FLAGS_REG))
-	      (clobber (mem:BLK (scratch)))])]
-  "optimize_insn_for_size_p () || !TARGET_SUB_ESP_8"
-  [(clobber (match_dup 0))
-   (set (mem:DI (pre_dec:DI (reg:DI SP_REG))) (match_dup 0))
-   (parallel [(set (mem:DI (pre_dec:DI (reg:DI SP_REG))) (match_dup 0))
-	      (clobber (mem:BLK (scratch)))])])
-
-;; Convert esp subtractions to push.
-(define_peephole2
-  [(match_scratch:DI 0 "r")
-   (parallel [(set (reg:DI SP_REG) (plus:DI (reg:DI SP_REG) (const_int -8)))
-	      (clobber (reg:CC FLAGS_REG))])]
-  "optimize_insn_for_size_p () || !TARGET_SUB_ESP_4"
-  [(clobber (match_dup 0))
-   (set (mem:DI (pre_dec:DI (reg:DI SP_REG))) (match_dup 0))])
-
-(define_peephole2
-  [(match_scratch:DI 0 "r")
-   (parallel [(set (reg:DI SP_REG) (plus:DI (reg:DI SP_REG) (const_int -16)))
-	      (clobber (reg:CC FLAGS_REG))])]
-  "optimize_insn_for_size_p () || !TARGET_SUB_ESP_8"
-  [(clobber (match_dup 0))
-   (set (mem:DI (pre_dec:DI (reg:DI SP_REG))) (match_dup 0))
-   (set (mem:DI (pre_dec:DI (reg:DI SP_REG))) (match_dup 0))])
-
-;; Convert epilogue deallocator to pop.
-(define_peephole2
-  [(match_scratch:DI 0 "r")
-   (parallel [(set (reg:DI SP_REG) (plus:DI (reg:DI SP_REG) (const_int 8)))
-	      (clobber (reg:CC FLAGS_REG))
-	      (clobber (mem:BLK (scratch)))])]
-  "optimize_insn_for_size_p () || !TARGET_ADD_ESP_4"
-  [(parallel [(set (match_dup 0) (mem:DI (post_inc:DI (reg:DI SP_REG))))
-	      (clobber (mem:BLK (scratch)))])])
-
-;; Two pops case is tricky, since pop causes dependency
-;; on destination register.  We use two registers if available.
-(define_peephole2
-  [(match_scratch:DI 0 "r")
-   (match_scratch:DI 1 "r")
-   (parallel [(set (reg:DI SP_REG) (plus:DI (reg:DI SP_REG) (const_int 16)))
-	      (clobber (reg:CC FLAGS_REG))
-	      (clobber (mem:BLK (scratch)))])]
-  "optimize_insn_for_size_p () || !TARGET_ADD_ESP_8"
-  [(parallel [(set (match_dup 0) (mem:DI (post_inc:DI (reg:DI SP_REG))))
-	      (clobber (mem:BLK (scratch)))])
-   (set (match_dup 1) (mem:DI (post_inc:DI (reg:DI SP_REG))))])
-
-(define_peephole2
-  [(match_scratch:DI 0 "r")
-   (parallel [(set (reg:DI SP_REG) (plus:DI (reg:DI SP_REG) (const_int 16)))
-	      (clobber (reg:CC FLAGS_REG))
-	      (clobber (mem:BLK (scratch)))])]
-  "optimize_insn_for_size_p ()"
-  [(parallel [(set (match_dup 0) (mem:DI (post_inc:DI (reg:DI SP_REG))))
-	      (clobber (mem:BLK (scratch)))])
-   (set (match_dup 0) (mem:DI (post_inc:DI (reg:DI SP_REG))))])
-
-;; Convert esp additions to pop.
-(define_peephole2
-  [(match_scratch:DI 0 "r")
-   (parallel [(set (reg:DI SP_REG) (plus:DI (reg:DI SP_REG) (const_int 8)))
-	      (clobber (reg:CC FLAGS_REG))])]
-  ""
-  [(set (match_dup 0) (mem:DI (post_inc:DI (reg:DI SP_REG))))])
-
-;; Two pops case is tricky, since pop causes dependency
-;; on destination register.  We use two registers if available.
-(define_peephole2
-  [(match_scratch:DI 0 "r")
-   (match_scratch:DI 1 "r")
-   (parallel [(set (reg:DI SP_REG) (plus:DI (reg:DI SP_REG) (const_int 16)))
-	      (clobber (reg:CC FLAGS_REG))])]
-  ""
-  [(set (match_dup 0) (mem:DI (post_inc:DI (reg:DI SP_REG))))
-   (set (match_dup 1) (mem:DI (post_inc:DI (reg:DI SP_REG))))])
-
-(define_peephole2
-  [(match_scratch:DI 0 "r")
-   (parallel [(set (reg:DI SP_REG) (plus:DI (reg:DI SP_REG) (const_int 16)))
-	      (clobber (reg:CC FLAGS_REG))])]
-  "optimize_insn_for_size_p ()"
-  [(set (match_dup 0) (mem:DI (post_inc:DI (reg:DI SP_REG))))
-   (set (match_dup 0) (mem:DI (post_inc:DI (reg:DI SP_REG))))])
+  [(match_scratch:P 1 "r")
+   (match_scratch:P 2 "r")
+   (parallel [(set (reg:P SP_REG)
+		   (plus:P (reg:P SP_REG)
+			   (match_operand:P 0 "const_int_operand" "")))
+	      (clobber (reg:CC FLAGS_REG))])]
+  "INTVAL (operands[0]) == 2*GET_MODE_SIZE (Pmode)"
+  [(set (match_dup 1) (mem:P (post_inc:P (reg:P SP_REG))))
+   (set (match_dup 2) (mem:P (post_inc:P (reg:P SP_REG))))])
+
+(define_peephole2
+  [(match_scratch:P 1 "r")
+   (parallel [(set (reg:P SP_REG)
+		   (plus:P (reg:P SP_REG)
+			   (match_operand:P 0 "const_int_operand" "")))
+	      (clobber (reg:CC FLAGS_REG))])]
+  "optimize_insn_for_size_p ()
+   && INTVAL (operands[0]) == 2*GET_MODE_SIZE (Pmode)"
+  [(set (match_dup 1) (mem:P (post_inc:P (reg:P SP_REG))))
+   (set (match_dup 1) (mem:P (post_inc:P (reg:P SP_REG))))])
 
 ;; Convert compares with 1 to shorter inc/dec operations when CF is not
 ;; required and register dies.  Similarly for 128 to -128.
Index: i386.c
===================================================================
--- i386.c	(revision 163716)
+++ i386.c	(working copy)
@@ -1480,21 +1480,21 @@ static unsigned int initial_ix86_tune_fe
   /* X86_TUNE_PROMOTE_HI_REGS */
   m_PPRO,
 
-  /* X86_TUNE_ADD_ESP_4: Enable if add/sub is preferred over 1/2 push/pop.  */
-  m_ATOM | m_AMD_MULTIPLE | m_K6_GEODE | m_PENT4 | m_NOCONA
-  | m_CORE2 | m_GENERIC,
-
-  /* X86_TUNE_ADD_ESP_8 */
-  m_AMD_MULTIPLE | m_ATOM | m_PPRO | m_K6_GEODE | m_386
-  | m_486 | m_PENT4 | m_NOCONA | m_CORE2 | m_GENERIC,
+  /* X86_TUNE_SINGLE_POP: Enable if single pop insn is preferred
+     over esp addition.  */
+  m_386 | m_486 | m_PENT | m_PPRO,
 
-  /* X86_TUNE_SUB_ESP_4 */
-  m_AMD_MULTIPLE | m_ATOM | m_PPRO | m_PENT4 | m_NOCONA | m_CORE2
-  | m_GENERIC,
+  /* X86_TUNE_DOUBLE_POP: Enable if double pop insn is preferred
+     over esp addition.  */
+  m_PENT,
 
-  /* X86_TUNE_SUB_ESP_8 */
-  m_AMD_MULTIPLE | m_ATOM | m_PPRO | m_386 | m_486
-  | m_PENT4 | m_NOCONA | m_CORE2 | m_GENERIC,
+  /* X86_TUNE_SINGLE_PUSH: Enable if single push insn is preferred
+     over esp subtraction.  */
+  m_386 | m_486 | m_PENT | m_K6_GEODE,
+
+  /* X86_TUNE_DOUBLE_PUSH. Enable if double push insn is preferred
+     over esp subtraction.  */
+  m_PENT | m_K6_GEODE,
 
   /* X86_TUNE_INTEGER_DFMODE_MOVES: Enable if integer moves are preferred
      for DFmode copies */
