Index: compare-elim.c
===================================================================
--- compare-elim.c	(revision 241326)
+++ compare-elim.c	(working copy)
@@ -143,10 +143,20 @@ conforming_compare (rtx_insn *insn)
   if (!REG_P (dest) || REGNO (dest) != targetm.flags_regnum)
     return NULL;
 
-  if (REG_P (XEXP (src, 0))
-      && (REG_P (XEXP (src, 1)) || CONSTANT_P (XEXP (src, 1))))
+  if (!REG_P (XEXP (src, 0)))
+    return NULL;
+
+  if (CONSTANT_P (XEXP (src, 1)) || REG_P (XEXP (src, 1)))
     return src;
 
+  if (GET_CODE (XEXP (src, 1)) == UNSPEC)
+    {
+      for (int i = 0; i < XVECLEN (XEXP (src, 1), 0); i++)
+	if (!REG_P (XVECEXP (XEXP (src, 1), 0, i)))
+	  return NULL;
+      return src;
+    }
+
   return NULL;
 }
 
@@ -370,21 +380,24 @@ find_comparison_dom_walker::before_dom_c
 	  last_cmp_valid = true;
 	}
 
-      /* Notice if this instruction kills the flags register.  */
-      else if (bitmap_bit_p (killed, targetm.flags_regnum))
+      else
 	{
-	  /* See if this insn could be the "clobber" that eliminates
-	     a future comparison.   */
-	  last_clobber = (arithmetic_flags_clobber_p (insn) ? insn : NULL);
-
-	  /* In either case, the previous compare is no longer valid.  */
-	  last_cmp = NULL;
-	  last_cmp_valid = false;
-	}
+	  /* Notice if this instruction uses the flags register.  */
+	  if (last_cmp)
+	    find_flags_uses_in_insn (last_cmp, insn);
 
-      /* Notice if this instruction uses the flags register.  */
-      else if (last_cmp)
-	find_flags_uses_in_insn (last_cmp, insn);
+	  /* Notice if this instruction kills the flags register.  */
+	  if (bitmap_bit_p (killed, targetm.flags_regnum))
+	    {
+	      /* See if this insn could be the "clobber" that eliminates
+		 a future comparison.   */
+	      last_clobber = (arithmetic_flags_clobber_p (insn) ? insn : NULL);
+
+	      /* In either case, the previous compare is no longer valid.  */
+	      last_cmp = NULL;
+	      last_cmp_valid = false;
+	    }
+	}
 
       /* Notice if any of the inputs to the comparison have changed.  */
       if (last_cmp_valid
@@ -507,39 +520,16 @@ maybe_select_cc_mode (struct comparison
   return flags;
 }
 
-/* Attempt to replace a comparison with a prior arithmetic insn that can
-   compute the same flags value as the comparison itself.  Return true if
-   successful, having made all rtl modifications necessary.  */
+/* Return a register RTX holding the same value at START as REG at END, or
+   NULL_RTX if there is none.  */
 
-static bool
-try_eliminate_compare (struct comparison *cmp)
+static rtx
+equivalent_reg_at_start (rtx reg, rtx_insn *end, rtx_insn *start)
 {
-  rtx_insn *insn, *bb_head;
-  rtx x, flags, in_a, cmp_src;
-
-  /* We must have found an interesting "clobber" preceding the compare.  */
-  if (cmp->prev_clobber == NULL)
-    return false;
-
-  /* ??? For the moment we don't handle comparisons for which IN_B
-     is a register.  We accepted these during initial comparison 
-     recognition in order to eliminate duplicate compares.
-     An improvement here would be to handle x = a - b; if (a cmp b).  */
-  if (!CONSTANT_P (cmp->in_b))
-    return false;
-
-  /* Verify that IN_A is not clobbered in between CMP and PREV_CLOBBER.
-     Given that this target requires this pass, we can assume that most
-     insns do clobber the flags, and so the distance between the compare
-     and the clobber is likely to be small.  */
-  /* ??? This is one point at which one could argue that DF_REF_CHAIN would
-     be useful, but it is thought to be too heavy-weight a solution here.  */
+  rtx_insn *bb_head = BB_HEAD (BLOCK_FOR_INSN (end));
 
-  in_a = cmp->in_a;
-  insn = cmp->insn;
-  bb_head = BB_HEAD (BLOCK_FOR_INSN (insn));
-  for (insn = PREV_INSN (insn);
-       insn != cmp->prev_clobber;
+  for (rtx_insn *insn = PREV_INSN (end);
+       insn != start;
        insn = PREV_INSN (insn))
     {
       const int abnormal_flags
@@ -552,13 +542,13 @@ try_eliminate_compare (struct comparison
       /* Note that the BB_HEAD is always either a note or a label, but in
 	 any case it means that IN_A is defined outside the block.  */
       if (insn == bb_head)
-	return false;
+	return NULL_RTX;
       if (NOTE_P (insn) || DEBUG_INSN_P (insn))
 	continue;
 
       /* Find a possible def of IN_A in INSN.  */
       FOR_EACH_INSN_DEF (def, insn)
-	if (DF_REF_REGNO (def) == REGNO (in_a))
+	if (DF_REF_REGNO (def) == REGNO (reg))
 	  break;
 
       /* No definitions of IN_A; continue searching.  */
@@ -567,35 +557,87 @@ try_eliminate_compare (struct comparison
 
       /* Bail if this is not a totally normal set of IN_A.  */
       if (DF_REF_IS_ARTIFICIAL (def))
-	return false;
+	return NULL_RTX;
       if (DF_REF_FLAGS (def) & abnormal_flags)
-	return false;
+	return NULL_RTX;
 
       /* We've found an insn between the compare and the clobber that sets
 	 IN_A.  Given that pass_cprop_hardreg has not yet run, we still find
 	 situations in which we can usefully look through a copy insn.  */
-      x = single_set (insn);
-      if (x == NULL)
-	return false;
-      in_a = SET_SRC (x);
-      if (!REG_P (in_a))
+      rtx x = single_set (insn);
+      if (x == NULL_RTX)
+	return NULL_RTX;
+      reg = SET_SRC (x);
+      if (!REG_P (reg))
+	return NULL_RTX;
+    }
+
+  return reg;
+}
+
+/* Attempt to replace a comparison with a prior arithmetic insn that can
+   compute the same flags value as the comparison itself.  Return true if
+   successful, having made all rtl modifications necessary.  */
+
+static bool
+try_eliminate_compare (struct comparison *cmp)
+{
+  rtx x, flags, in_a, in_b, cmp_src;
+
+  /* We must have found an interesting "clobber" preceding the compare.  */
+  if (cmp->prev_clobber == NULL)
+    return false;
+
+  /* Verify that IN_A is not clobbered in between CMP and PREV_CLOBBER.
+     Given that this target requires this pass, we can assume that most
+     insns do clobber the flags, and so the distance between the compare
+     and the clobber is likely to be small.  */
+  /* ??? This is one point at which one could argue that DF_REF_CHAIN would
+     be useful, but it is thought to be too heavy-weight a solution here.  */
+  in_a = equivalent_reg_at_start (cmp->in_a, cmp->insn, cmp->prev_clobber);
+  if (!in_a)
+    return false;
+
+  /* Likewise for IN_B if need be.  */
+  if (CONSTANT_P (cmp->in_b))
+    in_b = cmp->in_b;
+  else if (REG_P (cmp->in_b))
+    {
+      in_b = equivalent_reg_at_start (cmp->in_b, cmp->insn, cmp->prev_clobber);
+      if (!in_b)
 	return false;
     }
+  else if (GET_CODE (cmp->in_b) == UNSPEC)
+    {
+      const int len = XVECLEN (cmp->in_b, 0);
+      rtvec v = rtvec_alloc (len);
+      for (int i = 0; i < len; i++)
+	{
+	  rtx r = equivalent_reg_at_start (XVECEXP (cmp->in_b, 0, i),
+					   cmp->insn, cmp->prev_clobber);
+	  if (!r)
+	    return false;
+	  RTVEC_ELT (v, i) = r;
+	}
+      in_b = gen_rtx_UNSPEC (GET_MODE (cmp->in_b), v, XINT (cmp->in_b, 1));
+    }
+  else
+    gcc_unreachable ();
 
   /* We've reached PREV_CLOBBER without finding a modification of IN_A.
      Validate that PREV_CLOBBER itself does in fact refer to IN_A.  Do
      recall that we've already validated the shape of PREV_CLOBBER.  */
+  rtx insn = cmp->prev_clobber;
   x = XVECEXP (PATTERN (insn), 0, 0);
   if (rtx_equal_p (SET_DEST (x), in_a))
     cmp_src = SET_SRC (x);
 
   /* Also check operations with implicit extensions, e.g.:
      [(set (reg:DI)
-	   (zero_extend:DI (plus:SI (reg:SI)(reg:SI))))
+	   (zero_extend:DI (plus:SI (reg:SI) (reg:SI))))
       (set (reg:CCZ flags)
-	   (compare:CCZ
-	     (plus:SI (reg:SI)(reg:SI))
-	     (const_int 0)))]				*/
+	   (compare:CCZ (plus:SI (reg:SI) (reg:SI))
+			(const_int 0)))] */
   else if (REG_P (SET_DEST (x))
 	   && REG_P (in_a)
 	   && REGNO (SET_DEST (x)) == REGNO (in_a)
@@ -603,17 +645,29 @@ try_eliminate_compare (struct comparison
 	       || GET_CODE (SET_SRC (x)) == SIGN_EXTEND)
 	   && GET_MODE (XEXP (SET_SRC (x), 0)) == GET_MODE (in_a))
     cmp_src = XEXP (SET_SRC (x), 0);
+
+  /* Also check fully redundant comparisons, e.g.:
+     [(set (reg:SI)
+	   (minus:SI (reg:SI) (reg:SI))))
+      (set (reg:CC flags)
+	   (compare:CC (reg:SI) (reg:SI)))] */
+  else if (REG_P (in_b)
+	   && GET_CODE (SET_SRC (x)) == MINUS
+	   && rtx_equal_p (XEXP (SET_SRC (x), 0), in_a)
+	   && rtx_equal_p (XEXP (SET_SRC (x), 1), in_b))
+    cmp_src = in_a;
+
   else
     return false;
 
   /* Determine if we ought to use a different CC_MODE here.  */
-  flags = maybe_select_cc_mode (cmp, cmp_src, cmp->in_b);
+  flags = maybe_select_cc_mode (cmp, cmp_src, in_b);
   if (flags == NULL)
     flags = gen_rtx_REG (cmp->orig_mode, targetm.flags_regnum);
 
   /* Generate a new comparison for installation in the setter.  */
   x = copy_rtx (cmp_src);
-  x = gen_rtx_COMPARE (GET_MODE (flags), x, cmp->in_b);
+  x = gen_rtx_COMPARE (GET_MODE (flags), x, in_b);
   x = gen_rtx_SET (flags, x);
 
   /* Succeed if the new instruction is valid.  Note that we may have started
Index: config/visium/predicates.md
===================================================================
--- config/visium/predicates.md	(revision 241326)
+++ config/visium/predicates.md	(working copy)
@@ -131,13 +131,17 @@ (define_predicate "visium_equality_compa
   (match_code "eq,ne"))
 
 ;; Return true if OP is a valid comparison operator for CCNZmode.
-(define_special_predicate "visium_nz_comparison_operator"
+(define_predicate "visium_nz_comparison_operator"
   (match_code "eq,ne,lt,ge"))
 
 ;; Return true if OP is a valid comparison operator for CCCmode.
-(define_special_predicate "visium_c_comparison_operator"
+(define_predicate "visium_c_comparison_operator"
   (match_code "eq,ne,ltu,geu"))
 
+;; Return true if OP is a valid comparison operator for CCVmode.
+(define_predicate "visium_v_comparison_operator"
+  (match_code "eq,ne"))
+
 ;; Return true if OP is a valid FP comparison operator.
 (define_predicate "visium_fp_comparison_operator"
   (match_code "eq,ne,ordered,unordered,unlt,unle,ungt,unge,lt,le,gt,ge"))
@@ -155,6 +159,8 @@ (define_predicate "visium_branch_operato
       return visium_nz_comparison_operator (op, mode);
     case CCCmode:
       return visium_c_comparison_operator (op, mode);
+    case CCVmode:
+      return visium_v_comparison_operator (op, mode);
     case CCFPmode:
     case CCFPEmode:
       return visium_fp_comparison_operator (op, mode);
Index: config/visium/visium-modes.def
===================================================================
--- config/visium/visium-modes.def	(revision 241326)
+++ config/visium/visium-modes.def	(working copy)
@@ -29,6 +29,10 @@ along with GCC; see the file COPYING3.
    instruction.  Only the =,!= and unsigned <,>= operators can be used in
    conjunction with it.
 
+   We also have a CCVmode which is used by the arithmetic instructions when
+   they explicitly set the V flag (signed overflow).  Only the =,!= operators
+   can be used in conjunction with it.
+
    We also have two modes to indicate that the condition code is set by the
    the floating-point unit.  One for comparisons which generate an exception
    if the result is unordered (CCFPEmode) and one for comparisons which never
@@ -36,5 +40,6 @@ along with GCC; see the file COPYING3.
 
 CC_MODE (CCNZ);
 CC_MODE (CCC);
+CC_MODE (CCV);
 CC_MODE (CCFP);
 CC_MODE (CCFPE);
Index: config/visium/visium.c
===================================================================
--- config/visium/visium.c	(revision 241326)
+++ config/visium/visium.c	(working copy)
@@ -2833,6 +2833,14 @@ visium_select_cc_mode (enum rtx_code cod
       && rtx_equal_p (XEXP (op0, 0), op1))
     return CCCmode;
 
+  /* This is for the {add,sub,neg}<mode>3_insn_set_overflow pattern.  */
+  if ((code == EQ || code == NE)
+      && GET_CODE (op1) == UNSPEC
+      && (XINT (op1, 1) == UNSPEC_ADDV
+	  || XINT (op1, 1) == UNSPEC_SUBV
+	  || XINT (op1, 1) == UNSPEC_NEGV))
+    return CCVmode;
+
   if (op1 != const0_rtx)
     return CCmode;
 
@@ -3101,6 +3109,8 @@ output_cbranch (rtx label, enum rtx_code
     case NE:
       if (cc_mode == CCCmode)
 	cond = "cs";
+      else if (cc_mode == CCVmode)
+	cond = "os";
       else
 	cond = "ne";
       break;
@@ -3108,6 +3118,8 @@ output_cbranch (rtx label, enum rtx_code
     case EQ:
       if (cc_mode == CCCmode)
 	cond = "cc";
+      else if (cc_mode == CCVmode)
+	cond = "oc";
       else
 	cond = "eq";
       break;
Index: config/visium/visium.md
===================================================================
--- config/visium/visium.md	(revision 241326)
+++ config/visium/visium.md	(working copy)
@@ -81,6 +81,9 @@ (define_c_enum "unspec" [
   UNSPEC_ITOF
   UNSPEC_FTOI
   UNSPEC_NOP
+  UNSPEC_ADDV
+  UNSPEC_SUBV
+  UNSPEC_NEGV
 ])
 
 ;; UNSPEC_VOLATILE usage.
@@ -745,6 +748,27 @@ (define_expand "add<mode>3"
 		  (match_operand:QHI 2 "register_operand" "")))]
   "")
 
+(define_expand "uaddv<mode>4"
+  [(set (match_operand:I 0 "register_operand" "")
+	(plus:I (match_operand:I 1 "register_operand" "")
+		(match_operand:I 2 "register_operand" "")))
+   (set (pc)
+        (if_then_else (ltu (match_dup 0) (match_dup 1))
+		      (label_ref (match_operand 3 ""))
+		      (pc)))]
+  "")
+
+(define_expand "addv<mode>4"
+  [(set (match_operand:I 0 "register_operand" "")
+	(plus:I (match_operand:I 1 "register_operand" "")
+		(match_operand:I 2 "register_operand" "")))
+   (set (pc)
+        (if_then_else (ne (match_dup 0)
+			  (unspec:I [(match_dup 1) (match_dup 2)] UNSPEC_ADDV))
+		      (label_ref (match_operand 3 ""))
+		      (pc)))]
+  "")
+
 (define_insn_and_split "*add<mode>3_insn"
   [(set (match_operand:QHI 0 "register_operand" "=r")
 	(plus:QHI (match_operand:QHI 1 "register_operand" "%r")
@@ -767,6 +791,28 @@ (define_insn "*add<mode>3_insn<subst_ari
   "add<s>   %0,%1,%2"
   [(set_attr "type" "arith")])
 
+(define_insn "*add<mode>3_insn_set_carry"
+  [(set (match_operand:QHI 0 "register_operand" "=r")
+	(plus:QHI (match_operand:QHI 1 "register_operand" "%r")
+		  (match_operand:QHI 2 "register_operand" "r")))
+   (set (reg:CCC R_FLAGS)
+	(compare:CCC (plus:QHI (match_dup 1) (match_dup 2))
+		     (match_dup 1)))]
+  "reload_completed"
+  "add<s>   %0,%1,%2"
+  [(set_attr "type" "arith")])
+
+(define_insn "*add<mode>3_insn_set_overflow"
+  [(set (match_operand:QHI 0 "register_operand" "=r")
+	(plus:QHI (match_operand:QHI 1 "register_operand" "%r")
+		  (match_operand:QHI 2 "register_operand" "r")))
+   (set (reg:CCV R_FLAGS)
+	(compare:CCV (plus:QHI (match_dup 1) (match_dup 2))
+		     (unspec:QHI [(match_dup 1) (match_dup 2)] UNSPEC_ADDV)))]
+  "reload_completed"
+  "add<s>   %0,%1,%2"
+  [(set_attr "type" "arith")])
+
 (define_expand "addsi3"
   [(set (match_operand:SI 0 "register_operand" "")
 	(plus:SI (match_operand:SI 1 "register_operand" "")
@@ -822,6 +868,19 @@ (define_insn "addsi3_insn_set_carry"
     addi    %0,%2"
   [(set_attr "type" "arith")])
 
+(define_insn "*addsi3_insn_set_overflow"
+  [(set (match_operand:SI 0 "register_operand"          "=r,r")
+	(plus:SI (match_operand:SI 1 "register_operand" "%r,0")
+		 (match_operand:SI 2 "real_add_operand" " r,J")))
+   (set (reg:CCV R_FLAGS)
+	(compare:CCV (plus:SI (match_dup 1) (match_dup 2))
+		     (unspec:SI [(match_dup 1) (match_dup 2)] UNSPEC_ADDV)))]
+  "reload_completed"
+  "@
+    add.l   %0,%1,%2
+    addi    %0,%2"
+  [(set_attr "type" "arith")])
+
 (define_expand "adddi3"
   [(set (match_operand:DI 0 "register_operand" "")
 	(plus:DI (match_operand:DI 1 "register_operand" "")
@@ -897,6 +956,34 @@ (define_expand "sub<mode>3"
 		   (match_operand:QHI 2 "register_operand" "")))]
   "")
 
+(define_expand "usubv<mode>4"
+  [(set (match_operand:I 0 "register_operand" "")
+	(minus:I (match_operand:I 1 "reg_or_0_operand" "")
+		 (match_operand:I 2 "register_operand" "")))
+   (set (pc)
+        (if_then_else (ltu (match_dup 1) (match_dup 2))
+		      (label_ref (match_operand 3 ""))
+		      (pc)))]
+  ""
+{
+  if (operands[1] == const0_rtx)
+    {
+      emit_insn (gen_unegv<mode>3 (operands[0], operands[2], operands[3]));
+      DONE;
+    }
+})
+
+(define_expand "subv<mode>4"
+  [(set (match_operand:I 0 "register_operand" "")
+	(minus:I (match_operand:I 1 "register_operand" "")
+		 (match_operand:I 2 "register_operand" "")))
+   (set (pc)
+        (if_then_else (ne (match_dup 0)
+			  (unspec:I [(match_dup 1) (match_dup 2)] UNSPEC_SUBV))
+		      (label_ref (match_operand 3 ""))
+		      (pc)))]
+  "")
+
 (define_insn_and_split "*sub<mode>3_insn"
   [(set (match_operand:QHI 0 "register_operand" "=r")
 	(minus:QHI (match_operand:QHI 1 "reg_or_0_operand" "rO")
@@ -919,6 +1006,27 @@ (define_insn "*sub<mode>3_insn<subst_ari
   "sub<s>   %0,%r1,%2"
   [(set_attr "type" "arith")])
 
+(define_insn "*sub<mode>3_insn_set_carry"
+  [(set (match_operand:QHI 0 "register_operand" "=r")
+	(minus:QHI (match_operand:QHI 1 "reg_or_0_operand" "rO")
+		   (match_operand:QHI 2 "register_operand" "r")))
+   (set (reg:CC R_FLAGS)
+	(compare:CC (match_dup 1) (match_dup 2)))]
+  "reload_completed"
+  "sub<s>   %0,%r1,%2"
+  [(set_attr "type" "arith")])
+
+(define_insn "*sub<mode>3_insn_set_overflow"
+  [(set (match_operand:QHI 0 "register_operand" "=r")
+	(minus:QHI (match_operand:QHI 1 "reg_or_0_operand" "rO")
+		   (match_operand:QHI 2 "register_operand" "r")))
+   (set (reg:CCV R_FLAGS)
+	(compare:CCV (minus:QHI (match_dup 1) (match_dup 2))
+		     (unspec:QHI [(match_dup 1) (match_dup 2)] UNSPEC_SUBV)))]
+  "reload_completed"
+  "sub<s>   %0,%r1,%2"
+  [(set_attr "type" "arith")])
+
 (define_expand "subsi3"
   [(set (match_operand:SI 0 "register_operand" "")
 	(minus:SI (match_operand:SI 1 "reg_or_0_operand" "")
@@ -973,6 +1081,19 @@ (define_insn "subsi3_insn_set_carry"
     subi    %0,%2"
   [(set_attr "type" "arith")])
 
+(define_insn "*subsi3_insn_set_overflow"
+  [(set (match_operand:SI 0 "register_operand"           "=r,r")
+	(minus:SI (match_operand:SI 1 "register_operand" " r,0")
+		  (match_operand:SI 2 "real_add_operand" " r,J")))
+   (set (reg:CCV R_FLAGS)
+	(compare:CCV (minus:SI (match_dup 1) (match_dup 2))
+		     (unspec:SI [(match_dup 1) (match_dup 2)] UNSPEC_SUBV)))]
+  "reload_completed"
+  "@
+    sub.l   %0,%1,%2
+    subi    %0,%2"
+  [(set_attr "type" "arith")])
+
 (define_expand "subdi3"
   [(set (match_operand:DI 0 "register_operand" "")
 	(minus:DI (match_operand:DI 1 "register_operand" "")
@@ -1047,6 +1168,25 @@ (define_expand "neg<mode>2"
 	(neg:I (match_operand:I 1 "register_operand" "")))]
   "")
 
+(define_expand "unegv<mode>3"
+  [(set (match_operand:I 0 "register_operand" "")
+	(neg:I (match_operand:I 1 "register_operand" "")))
+   (set (pc)
+        (if_then_else (ne (match_dup 0) (const_int 0))
+		      (label_ref (match_operand 2 ""))
+		      (pc)))]
+  "")
+
+(define_expand "negv<mode>3"
+  [(set (match_operand:I 0 "register_operand" "")
+	(neg:I (match_operand:I 1 "register_operand" "")))
+   (set (pc)
+        (if_then_else (ne (match_dup 0)
+			  (unspec:I [(match_dup 1)] UNSPEC_NEGV))
+		      (label_ref (match_operand 2 ""))
+		      (pc)))]
+  "")
+
 (define_insn_and_split "*neg<mode>2_insn"
   [(set (match_operand:I 0 "register_operand" "=r")
 	(neg:I (match_operand:I 1 "register_operand" "r")))]
@@ -1075,6 +1215,16 @@ (define_insn "negsi2_insn_set_carry"
   "sub.l   %0,r0,%1"
   [(set_attr "type" "arith")])
 
+(define_insn "*neg<mode>2_insn_set_overflow"
+  [(set (match_operand:I 0 "register_operand" "=r")
+	(neg:I (match_operand:I 1 "register_operand" "r")))
+   (set (reg:CCV R_FLAGS)
+	(compare:CCV (neg:I (match_dup 1))
+		     (unspec:I [(match_dup 1)] UNSPEC_NEGV)))]
+  "reload_completed"
+  "sub<s>   %0,r0,%1"
+  [(set_attr "type" "arith")])
+
 (define_expand "negdi2"
   [(set (match_operand:DI 0 "register_operand" "")
 	(neg:DI (match_operand:DI 1 "register_operand" "")))]
@@ -1850,6 +2000,45 @@ (define_insn "*btst"
 ;;
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;
+;; Integer overflow tests
+;;
+;; Modes QI, HI and SI are supported directly.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+
+(define_insn "*addv_tst<mode>"
+  [(set (reg:CCV R_FLAGS)
+	(compare:CCV (match_operand:I 0 "register_operand" "r")
+ 		     (unspec:I [(match_operand:I 1 "register_operand" "%r")
+				(match_operand:I 2 "register_operand" "r")]
+			       UNSPEC_ADDV)))]
+  "reload_completed"
+  "add<s>   r0,%1,%2"
+  [(set_attr "type" "arith")])
+
+(define_insn "*subv_tst<mode>"
+  [(set (reg:CCV R_FLAGS)
+	(compare:CCV (match_operand:I 0 "register_operand" "r")
+ 		     (unspec:I [(match_operand:I 1 "reg_or_0_operand" "rO")
+				(match_operand:I 2 "register_operand" "r")]
+			       UNSPEC_SUBV)))]
+  "reload_completed"
+  "sub<s>   r0,%r1,%2"
+  [(set_attr "type" "arith")])
+
+(define_insn "*negv_tst<mode>"
+  [(set (reg:CCV R_FLAGS)
+	(compare:CCV (match_operand:I 0 "register_operand" "r")
+ 		     (unspec:I [(match_operand:I 1 "register_operand" "r")]
+			       UNSPEC_NEGV)))]
+  "reload_completed"
+  "sub<s>   r0,r0,%1"
+  [(set_attr "type" "arith")])
+
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
 ;; Integer comparisons
 ;;
 ;; Modes QI, HI and SI are supported directly.
@@ -2124,6 +2313,65 @@ (define_insn_and_split "*cbranch<mode>4_
   DONE;
 }
   [(set_attr "type" "cmp")])
+
+(define_insn_and_split "*cbranch<mode>4_addv_insn"
+  [(set (pc)
+	(if_then_else (match_operator 0 "visium_equality_comparison_operator"
+		       [(match_operand:I 1 "register_operand" "r")
+ 		        (unspec:I [(match_operand:I 2 "register_operand" "%r")
+				   (match_operand:I 3 "register_operand" "r")]
+				  UNSPEC_ADDV)])
+		      (label_ref (match_operand 4 ""))
+		      (pc)))]
+  ""
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+{
+  visium_split_cbranch (GET_CODE (operands[0]), XEXP (operands[0], 0),
+			XEXP (operands[0], 1), operands[4]);
+  DONE;
+}
+  [(set_attr "type" "cmp")])
+
+(define_insn_and_split "*cbranch<mode>4_subv_insn"
+  [(set (pc)
+	(if_then_else (match_operator 0 "visium_equality_comparison_operator"
+		       [(match_operand:I 1 "register_operand" "r")
+ 		        (unspec:I [(match_operand:I 2 "reg_or_0_operand" "rO")
+				   (match_operand:I 3 "register_operand" "r")]
+				  UNSPEC_SUBV)])
+		      (label_ref (match_operand 4 ""))
+		      (pc)))]
+  ""
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+{
+  visium_split_cbranch (GET_CODE (operands[0]), XEXP (operands[0], 0),
+			XEXP (operands[0], 1), operands[4]);
+  DONE;
+}
+  [(set_attr "type" "cmp")])
+
+(define_insn_and_split "*cbranch<mode>4_negv_insn"
+  [(set (pc)
+	(if_then_else (match_operator 0 "visium_equality_comparison_operator"
+		       [(match_operand:I 1 "register_operand" "r")
+ 		        (unspec:I [(match_operand:I 2 "register_operand" "r")]
+				  UNSPEC_NEGV)])
+		      (label_ref (match_operand 3 ""))
+		      (pc)))]
+  ""
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+{
+  visium_split_cbranch (GET_CODE (operands[0]), XEXP (operands[0], 0),
+			XEXP (operands[0], 1), operands[3]);
+  DONE;
+}
+  [(set_attr "type" "cmp")])
 
 (define_insn_and_split "*cbranchsi4_btst_insn"
   [(set (pc)
Index: testsuite/gcc.target/visium/overflow16.c
===================================================================
--- testsuite/gcc.target/visium/overflow16.c	(revision 0)
+++ testsuite/gcc.target/visium/overflow16.c	(working copy)
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+#include <stdbool.h>
+
+bool my_uadd_overflow (unsigned short a, unsigned short b, unsigned short *res)
+{
+  return __builtin_add_overflow (a, b, res);
+}
+
+bool my_usub_overflow (unsigned short a, unsigned short b, unsigned short *res)
+{
+  return __builtin_sub_overflow (a, b, res);
+}
+
+bool my_uneg_overflow (unsigned short a, unsigned short *res)
+{
+  return __builtin_sub_overflow (0, a, res);
+}
+
+bool my_add_overflow (short a, short b, short *res)
+{
+  return __builtin_add_overflow (a, b, res);
+}
+
+bool my_sub_overflow (short a, short b, short *res)
+{
+  return __builtin_sub_overflow (a, b, res);
+}
+
+bool my_neg_overflow (short a, short *res)
+{
+  return __builtin_sub_overflow (0, a, res);
+}
+
+/* { dg-final { scan-assembler-times "add.w" 2 } } */
+/* { dg-final { scan-assembler-times "sub.w" 4 } } */
+/* { dg-final { scan-assembler-not "cmp.w" } } */
+/* { dg-final { scan-assembler-not "mov.w" } } */
Index: testsuite/gcc.target/visium/overflow32.c
===================================================================
--- testsuite/gcc.target/visium/overflow32.c	(revision 0)
+++ testsuite/gcc.target/visium/overflow32.c	(working copy)
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+#include <stdbool.h>
+
+bool my_uadd_overflow (unsigned int a, unsigned int b, unsigned int *res)
+{
+  return __builtin_add_overflow (a, b, res);
+}
+
+bool my_usub_overflow (unsigned int a, unsigned int b, unsigned int *res)
+{
+  return __builtin_sub_overflow (a, b, res);
+}
+
+bool my_uneg_overflow (unsigned int a, unsigned int *res)
+{
+  return __builtin_sub_overflow (0, a, res);
+}
+
+bool my_add_overflow (int a, int b, int *res)
+{
+  return __builtin_add_overflow (a, b, res);
+}
+
+bool my_sub_overflow (int a, int b, int *res)
+{
+  return __builtin_sub_overflow (a, b, res);
+}
+
+bool my_neg_overflow (int a, int *res)
+{
+  return __builtin_sub_overflow (0, a, res);
+}
+
+/* { dg-final { scan-assembler-times "add.l" 2 } } */
+/* { dg-final { scan-assembler-times "sub.l" 4 } } */
+/* { dg-final { scan-assembler-not "cmp.l" } } */
+/* { dg-final { scan-assembler-not "mov.l" } } */
Index: testsuite/gcc.target/visium/overflow8.c
===================================================================
--- testsuite/gcc.target/visium/overflow8.c	(revision 0)
+++ testsuite/gcc.target/visium/overflow8.c	(working copy)
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+#include <stdbool.h>
+
+bool my_uadd_overflow (unsigned char a, unsigned char b, unsigned char *res)
+{
+  return __builtin_add_overflow (a, b, res);
+}
+
+bool my_usub_overflow (unsigned char a, unsigned char b, unsigned char *res)
+{
+  return __builtin_sub_overflow (a, b, res);
+}
+
+bool my_uneg_overflow (unsigned char a, unsigned char *res)
+{
+  return __builtin_sub_overflow (0, a, res);
+}
+
+bool my_add_overflow (signed char a, signed char b, signed char *res)
+{
+  return __builtin_add_overflow (a, b, res);
+}
+
+bool my_sub_overflow (signed char a, signed char b, signed char *res)
+{
+  return __builtin_sub_overflow (a, b, res);
+}
+
+bool my_neg_overflow (signed char a, signed char *res)
+{
+  return __builtin_sub_overflow (0, a, res);
+}
+
+/* { dg-final { scan-assembler-times "add.b" 2 } } */
+/* { dg-final { scan-assembler-times "sub.b" 4 } } */
+/* { dg-final { scan-assembler-not "cmp.b" } } */
+/* { dg-final { scan-assembler-not "mov.b" } } */
