diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 6c6fa0b046f970ddf0411f01eca9ce536c21eee1..bf91b4b9fa9a38a3e86f65530ba59258bc352351 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,20 @@
+Wed Jan  8 12:10:57 CET 2003  Jan Hubicka  <jh@suse.cz>
+
+	* i386.md (adddi3_carry_rex64, subdi3_carry_rex64): Name pattern.
+	(addhi3_carry, addqi3_carry, subhi3_carry, subqi3_carry): New patterns.
+	(add??cc): New expanders.
+	* i386.c (expand_int_addcc): New function.
+	* i386-protos.h (expand_int_addcc): Declare.
+
+	* alias.c (memory_modified_1): New static function.
+	(memory_modified): New static varaible.
+	(memory_modified_in_insn_p): New global function.
+	* rtl.h (memory_modified_in_insn_p): Declare.
+	* rtlanal.c (modified_between_p, modified_in_p): Be smart about memory
+	references.
+
+	* expr.h (emit_conditional_add): Declare.
+
 2003-01-07  Janis Johnson  <janis187@us.ibm.com>
 
 	PR other/8947
diff --git a/gcc/alias.c b/gcc/alias.c
index 960475be0c5f63cbf3e9e9bbc2c14a183ee3322c..ffd4991a2c68838ef10d4e98cbf10e54032a3798 100644
--- a/gcc/alias.c
+++ b/gcc/alias.c
@@ -119,6 +119,7 @@ static int nonlocal_referenced_p_1      PARAMS ((rtx *, void *));
 static int nonlocal_referenced_p        PARAMS ((rtx));
 static int nonlocal_set_p_1             PARAMS ((rtx *, void *));
 static int nonlocal_set_p               PARAMS ((rtx));
+static void memory_modified_1		PARAMS ((rtx, rtx, void *));
 
 /* Set up all info needed to perform alias analysis on memory references.  */
 
@@ -2703,6 +2704,35 @@ init_alias_once ()
   alias_sets = splay_tree_new (splay_tree_compare_ints, 0, 0);
 }
 
+/* Set MEMORY_MODIFIED when X modifies DATA (that is assumed
+   to be memory reference.  */
+static bool memory_modified;
+static void
+memory_modified_1 (x, pat, data)
+	rtx x, pat ATTRIBUTE_UNUSED;
+	void *data;
+{
+  if (GET_CODE (x) == MEM)
+    {
+      if (anti_dependence (x, (rtx)data) || output_dependence (x, (rtx)data))
+	memory_modified = true;
+    }
+}
+
+
+/* Return true when INSN possibly modify memory contents of MEM
+   (ie address can be modified).  */
+bool
+memory_modified_in_insn_p (mem, insn)
+     rtx mem, insn;
+{
+  if (!INSN_P (insn))
+    return false;
+  memory_modified = false;
+  note_stores (PATTERN (insn), memory_modified_1, mem);
+  return memory_modified;
+}
+
 /* Initialize the aliasing machinery.  Initialize the REG_KNOWN_VALUE
    array.  */
 
diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h
index a06a160bfbc3a4c42cf91fb0be07018d6565e18e..01fc203377f819c456a9a56e341728742a7794a4 100644
--- a/gcc/config/i386/i386-protos.h
+++ b/gcc/config/i386/i386-protos.h
@@ -141,6 +141,7 @@ extern void ix86_expand_branch PARAMS ((enum rtx_code, rtx));
 extern int ix86_expand_setcc PARAMS ((enum rtx_code, rtx));
 extern int ix86_expand_int_movcc PARAMS ((rtx[]));
 extern int ix86_expand_fp_movcc PARAMS ((rtx[]));
+extern int ix86_expand_int_addcc PARAMS ((rtx[]));
 extern void ix86_expand_call PARAMS ((rtx, rtx, rtx, rtx, rtx, int));
 extern void x86_initialize_trampoline PARAMS ((rtx, rtx, rtx));
 extern rtx ix86_zero_extend_to_Pmode PARAMS ((rtx));
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index c1a760b6358d66e64e803f2abf1b5c219b222cca..db361d9791604e2689a494268d6cc9c3c43f9917 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -9981,6 +9981,69 @@ ix86_expand_fp_movcc (operands)
   return 1;
 }
 
+/* Expand conditional increment or decrement using adb/sbb instructions.
+   The default case using setcc followed by the conditional move can be
+   done by generic code.  */
+int
+ix86_expand_int_addcc (operands)
+     rtx operands[];
+{
+  enum rtx_code code = GET_CODE (operands[1]);
+  rtx compare_op;
+  rtx val = const0_rtx;
+
+  if (operands[3] != const1_rtx
+      && operands[3] != constm1_rtx)
+    return 0;
+  if (!ix86_expand_carry_flag_compare (code, ix86_compare_op0,
+				       ix86_compare_op1, &compare_op))
+     return 0;
+  if (GET_CODE (compare_op) != LTU)
+    val = operands[3] == const1_rtx ? constm1_rtx : const1_rtx;
+  if ((GET_CODE (compare_op) == LTU) == (operands[3] == constm1_rtx))
+    {
+      switch (GET_MODE (operands[0]))
+	{
+	  case QImode:
+            emit_insn (gen_subqi3_carry (operands[0], operands[2], val));
+	    break;
+	  case HImode:
+            emit_insn (gen_subhi3_carry (operands[0], operands[2], val));
+	    break;
+	  case SImode:
+            emit_insn (gen_subsi3_carry (operands[0], operands[2], val));
+	    break;
+	  case DImode:
+            emit_insn (gen_subdi3_carry_rex64 (operands[0], operands[2], val));
+	    break;
+	  default:
+	    abort ();
+	}
+    }
+  else
+    {
+      switch (GET_MODE (operands[0]))
+	{
+	  case QImode:
+            emit_insn (gen_addqi3_carry (operands[0], operands[2], val));
+	    break;
+	  case HImode:
+            emit_insn (gen_addhi3_carry (operands[0], operands[2], val));
+	    break;
+	  case SImode:
+            emit_insn (gen_addsi3_carry (operands[0], operands[2], val));
+	    break;
+	  case DImode:
+            emit_insn (gen_adddi3_carry_rex64 (operands[0], operands[2], val));
+	    break;
+	  default:
+	    abort ();
+	}
+    }
+  return 1; /* DONE */
+}
+
+
 /* Split operands 0 and 1 into SImode parts.  Similar to split_di, but
    works for floating pointer parameters and nonoffsetable memories.
    For pushes, it returns just stack offsets; the values will be saved
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index 8be5fef2ed0fd46285b0e75edba75331f7b9ebe3..a364729301a836c91ab94fb05fd5a0b6fbd52f03 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -4951,7 +4951,7 @@
    split_di (operands+1, 1, operands+1, operands+4);
    split_di (operands+2, 1, operands+2, operands+5);")
 
-(define_insn "*adddi3_carry_rex64"
+(define_insn "adddi3_carry_rex64"
   [(set (match_operand:DI 0 "nonimmediate_operand" "=rm,r")
 	  (plus:DI (plus:DI (ltu:DI (reg:CC 17) (const_int 0))
 			    (match_operand:DI 1 "nonimmediate_operand" "%0,0"))
@@ -4976,7 +4976,33 @@
   [(set_attr "type" "alu")
    (set_attr "mode" "DI")])
 
-(define_insn "*addsi3_carry"
+(define_insn "addqi3_carry"
+  [(set (match_operand:QI 0 "nonimmediate_operand" "=rm,r")
+	  (plus:QI (plus:QI (ltu:QI (reg:CC 17) (const_int 0))
+			    (match_operand:QI 1 "nonimmediate_operand" "%0,0"))
+		   (match_operand:QI 2 "general_operand" "ri,rm")))
+   (clobber (reg:CC 17))]
+  "ix86_binary_operator_ok (PLUS, QImode, operands)"
+  "adc{b}\t{%2, %0|%0, %2}"
+  [(set_attr "type" "alu")
+   (set_attr "pent_pair" "pu")
+   (set_attr "mode" "QI")
+   (set_attr "ppro_uops" "few")])
+
+(define_insn "addhi3_carry"
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r")
+	  (plus:HI (plus:HI (ltu:HI (reg:CC 17) (const_int 0))
+			    (match_operand:HI 1 "nonimmediate_operand" "%0,0"))
+		   (match_operand:HI 2 "general_operand" "ri,rm")))
+   (clobber (reg:CC 17))]
+  "ix86_binary_operator_ok (PLUS, HImode, operands)"
+  "adc{w}\t{%2, %0|%0, %2}"
+  [(set_attr "type" "alu")
+   (set_attr "pent_pair" "pu")
+   (set_attr "mode" "HI")
+   (set_attr "ppro_uops" "few")])
+
+(define_insn "addsi3_carry"
   [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r")
 	  (plus:SI (plus:SI (ltu:SI (reg:CC 17) (const_int 0))
 			    (match_operand:SI 1 "nonimmediate_operand" "%0,0"))
@@ -6653,6 +6679,31 @@
   [(set_attr "type" "alu")
    (set_attr "mode" "DI")])
 
+(define_insn "subqi3_carry"
+  [(set (match_operand:QI 0 "nonimmediate_operand" "=rm,r")
+	  (minus:QI (match_operand:QI 1 "nonimmediate_operand" "0,0")
+	    (plus:QI (ltu:QI (reg:CC 17) (const_int 0))
+	       (match_operand:QI 2 "general_operand" "ri,rm"))))
+   (clobber (reg:CC 17))]
+  "ix86_binary_operator_ok (MINUS, QImode, operands)"
+  "sbb{b}\t{%2, %0|%0, %2}"
+  [(set_attr "type" "alu")
+   (set_attr "pent_pair" "pu")
+   (set_attr "ppro_uops" "few")
+   (set_attr "mode" "QI")])
+
+(define_insn "subhi3_carry"
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r")
+	  (minus:HI (match_operand:HI 1 "nonimmediate_operand" "0,0")
+	    (plus:HI (ltu:HI (reg:CC 17) (const_int 0))
+	       (match_operand:HI 2 "general_operand" "ri,rm"))))
+   (clobber (reg:CC 17))]
+  "ix86_binary_operator_ok (MINUS, HImode, operands)"
+  "sbb{w}\t{%2, %0|%0, %2}"
+  [(set_attr "type" "alu")
+   (set_attr "pent_pair" "pu")
+   (set_attr "ppro_uops" "few")
+   (set_attr "mode" "HI")])
 
 (define_insn "subsi3_carry"
   [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r")
@@ -16459,6 +16510,39 @@
 			 (match_dup 1)
 			 (match_dup 2)))])
 
+;; Conditional addition patterns
+(define_expand "addqicc"
+  [(match_operand:QI 0 "register_operand" "")
+   (match_operand 1 "comparison_operator" "")
+   (match_operand:QI 2 "register_operand" "")
+   (match_operand:QI 3 "const_int_operand" "")]
+  ""
+  "if (!ix86_expand_int_addcc (operands)) FAIL; DONE;")
+
+(define_expand "addhicc"
+  [(match_operand:HI 0 "register_operand" "")
+   (match_operand 1 "comparison_operator" "")
+   (match_operand:HI 2 "register_operand" "")
+   (match_operand:HI 3 "const_int_operand" "")]
+  ""
+  "if (!ix86_expand_int_addcc (operands)) FAIL; DONE;")
+
+(define_expand "addsicc"
+  [(match_operand:SI 0 "register_operand" "")
+   (match_operand 1 "comparison_operator" "")
+   (match_operand:SI 2 "register_operand" "")
+   (match_operand:SI 3 "const_int_operand" "")]
+  ""
+  "if (!ix86_expand_int_addcc (operands)) FAIL; DONE;")
+
+(define_expand "adddicc"
+  [(match_operand:DI 0 "register_operand" "")
+   (match_operand 1 "comparison_operator" "")
+   (match_operand:DI 2 "register_operand" "")
+   (match_operand:DI 3 "const_int_operand" "")]
+  "TARGET_64BIT"
+  "if (!ix86_expand_int_addcc (operands)) FAIL; DONE;")
+
 ;; We can't represent the LT test directly.  Do this by swapping the operands.
 
 (define_split
diff --git a/gcc/expr.h b/gcc/expr.h
index 6e8d19e994b84702c7d7c3a6aac3cea95b6e2c03..7fe3c1be071f86c96377f5009f74f942840ac3b2 100644
--- a/gcc/expr.h
+++ b/gcc/expr.h
@@ -307,6 +307,9 @@ rtx emit_conditional_move PARAMS ((rtx, enum rtx_code, rtx, rtx,
 int can_conditionally_move_p PARAMS ((enum machine_mode mode));
 
 #endif
+rtx emit_conditional_add (rtx, enum rtx_code, rtx, rtx,
+			  enum machine_mode, rtx, rtx,
+			  enum machine_mode, int);
 
 
 /* Functions from expmed.c:  */
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 3cab166f527ed9a618c20ea226867b65087bf702..a2c7514a8989bf26a4031b9eb7a9853660d080f8 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -2251,6 +2251,7 @@ extern void init_alias_once		PARAMS ((void));
 extern void init_alias_analysis		PARAMS ((void));
 extern void end_alias_analysis		PARAMS ((void));
 extern rtx addr_side_effect_eval	PARAMS ((rtx, int, int));
+extern bool memory_modified_in_insn_p	PARAMS ((rtx, rtx));
 
 /* In sibcall.c */
 typedef enum {
diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c
index 2aad022fc2673ea3395642a50c6d559738eda062..63d7feb60351cb60da46fd0e1c9fe47433a392fc 100644
--- a/gcc/rtlanal.c
+++ b/gcc/rtlanal.c
@@ -1037,7 +1037,7 @@ regs_set_between_p (x, start, end)
 
 /* Similar to reg_set_between_p, but check all registers in X.  Return 0
    only if none of them are modified between START and END.  Return 1 if
-   X contains a MEM; this routine does not perform any memory aliasing.  */
+   X contains a MEM; this routine does usememory aliasing.  */
 
 int
 modified_between_p (x, start, end)
@@ -1047,6 +1047,10 @@ modified_between_p (x, start, end)
   enum rtx_code code = GET_CODE (x);
   const char *fmt;
   int i, j;
+  rtx insn;
+
+  if (start == end)
+    return 0;
 
   switch (code)
     {
@@ -1063,10 +1067,14 @@ modified_between_p (x, start, end)
       return 1;
 
     case MEM:
-      /* If the memory is not constant, assume it is modified.  If it is
-	 constant, we still have to check the address.  */
-      if (! RTX_UNCHANGING_P (x))
+      if (RTX_UNCHANGING_P (x))
+	return 0;
+      if (modified_between_p (XEXP (x, 0), start, end))
 	return 1;
+      for (insn = NEXT_INSN (start); insn != end; insn = NEXT_INSN (insn))
+	if (memory_modified_in_insn_p (x, insn))
+	  return 1;
+      return 0;
       break;
 
     case REG:
@@ -1093,7 +1101,7 @@ modified_between_p (x, start, end)
 
 /* Similar to reg_set_p, but check all registers in X.  Return 0 only if none
    of them are modified in INSN.  Return 1 if X contains a MEM; this routine
-   does not perform any memory aliasing.  */
+   does use memory aliasing.  */
 
 int
 modified_in_p (x, insn)
@@ -1119,10 +1127,13 @@ modified_in_p (x, insn)
       return 1;
 
     case MEM:
-      /* If the memory is not constant, assume it is modified.  If it is
-	 constant, we still have to check the address.  */
-      if (! RTX_UNCHANGING_P (x))
+      if (RTX_UNCHANGING_P (x))
+	return 0;
+      if (modified_in_p (XEXP (x, 0), insn))
 	return 1;
+      if (memory_modified_in_insn_p (x, insn))
+	return 1;
+      return 0;
       break;
 
     case REG: