]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/config/arm/arm.md
[arm] Early split addvdi4
[thirdparty/gcc.git] / gcc / config / arm / arm.md
index f597a277c177050d96d9f495c10aa4d207e2df02..e9e0ca925d28060eb431536f8c31e41d37a11ed1 100644 (file)
          if (!arm_not_operand (hi_op2, SImode))
            hi_op2 = force_reg (SImode, hi_op2);
 
-         emit_insn (gen_addsi3_compareC (lo_dest, lo_op1, lo_op2));
+         emit_insn (gen_addsi3_compare_op1 (lo_dest, lo_op1, lo_op2));
+         rtx carry = gen_rtx_LTU (SImode, gen_rtx_REG (CC_Cmode, CC_REGNUM),
+                                  const0_rtx);
          if (hi_op2 == const0_rtx)
-           emit_insn (gen_add0si3_carryin_ltu (hi_dest, hi_op1));
+           emit_insn (gen_add0si3_carryin (hi_dest, hi_op1, carry));
          else
-           emit_insn (gen_addsi3_carryin_ltu (hi_dest, hi_op1, hi_op2));
+           emit_insn (gen_addsi3_carryin (hi_dest, hi_op1, hi_op2, carry));
        }
 
       if (lo_result != lo_dest)
   "
 )
 
-(define_expand "addv<mode>4"
-  [(match_operand:SIDI 0 "register_operand")
-   (match_operand:SIDI 1 "register_operand")
-   (match_operand:SIDI 2 "register_operand")
+(define_expand "addvsi4"
+  [(match_operand:SI 0 "s_register_operand")
+   (match_operand:SI 1 "s_register_operand")
+   (match_operand:SI 2 "arm_add_operand")
    (match_operand 3 "")]
   "TARGET_32BIT"
 {
-  emit_insn (gen_add<mode>3_compareV (operands[0], operands[1], operands[2]));
+  if (CONST_INT_P (operands[2]))
+    emit_insn (gen_addsi3_compareV_imm (operands[0], operands[1], operands[2]));
+  else
+    emit_insn (gen_addsi3_compareV_reg (operands[0], operands[1], operands[2]));
   arm_gen_unlikely_cbranch (NE, CC_Vmode, operands[3]);
 
   DONE;
 })
 
-(define_expand "uaddv<mode>4"
-  [(match_operand:SIDI 0 "register_operand")
-   (match_operand:SIDI 1 "register_operand")
-   (match_operand:SIDI 2 "register_operand")
+(define_expand "addvdi4"
+  [(match_operand:DI 0 "s_register_operand")
+   (match_operand:DI 1 "s_register_operand")
+   (match_operand:DI 2 "reg_or_int_operand")
    (match_operand 3 "")]
   "TARGET_32BIT"
 {
-  emit_insn (gen_add<mode>3_compareC (operands[0], operands[1], operands[2]));
+  rtx lo_result, hi_result;
+  rtx lo_op1, hi_op1, lo_op2, hi_op2;
+  arm_decompose_di_binop (operands[1], operands[2], &lo_op1, &hi_op1,
+                         &lo_op2, &hi_op2);
+  lo_result = gen_lowpart (SImode, operands[0]);
+  hi_result = gen_highpart (SImode, operands[0]);
+
+  if (lo_op2 == const0_rtx)
+    {
+      emit_move_insn (lo_result, lo_op1);
+      if (!arm_add_operand (hi_op2, SImode))
+       hi_op2 = force_reg (SImode, hi_op2);
+
+      emit_insn (gen_addvsi4 (hi_result, hi_op1, hi_op2, operands[3]));
+    }
+  else
+    {
+      if (!arm_add_operand (lo_op2, SImode))
+       lo_op2 = force_reg (SImode, lo_op2);
+      if (!arm_not_operand (hi_op2, SImode))
+       hi_op2 = force_reg (SImode, hi_op2);
+
+      emit_insn (gen_addsi3_compare_op1 (lo_result, lo_op1, lo_op2));
+
+      if (hi_op2 == const0_rtx)
+        emit_insn (gen_addsi3_cin_vout_0 (hi_result, hi_op1));
+      else if (CONST_INT_P (hi_op2))
+        emit_insn (gen_addsi3_cin_vout_imm (hi_result, hi_op1, hi_op2));
+      else
+        emit_insn (gen_addsi3_cin_vout_reg (hi_result, hi_op1, hi_op2));
+
+      arm_gen_unlikely_cbranch (NE, CC_Vmode, operands[3]);
+    }
+
+  DONE;
+})
+
+(define_expand "addsi3_cin_vout_reg"
+  [(parallel
+    [(set (match_dup 3)
+         (compare:CC_V
+          (plus:DI
+           (plus:DI (match_dup 4)
+                    (sign_extend:DI (match_operand:SI 1 "s_register_operand")))
+           (sign_extend:DI (match_operand:SI 2 "s_register_operand")))
+          (sign_extend:DI (plus:SI (plus:SI (match_dup 5) (match_dup 1))
+                                   (match_dup 2)))))
+     (set (match_operand:SI 0 "s_register_operand")
+         (plus:SI (plus:SI (match_dup 5) (match_dup 1))
+                  (match_dup 2)))])]
+  "TARGET_32BIT"
+  {
+    operands[3] = gen_rtx_REG (CC_Vmode, CC_REGNUM);
+    rtx ccin = gen_rtx_REG (CC_Cmode, CC_REGNUM);
+    operands[4] = gen_rtx_LTU (DImode, ccin, const0_rtx);
+    operands[5] = gen_rtx_LTU (SImode, ccin, const0_rtx);
+  }
+)
+
+(define_insn "*addsi3_cin_vout_reg_insn"
+  [(set (reg:CC_V CC_REGNUM)
+       (compare:CC_V
+        (plus:DI
+         (plus:DI
+          (match_operand:DI 3 "arm_carry_operation" "")
+          (sign_extend:DI (match_operand:SI 1 "s_register_operand" "%0,r")))
+         (sign_extend:DI (match_operand:SI 2 "s_register_operand" "l,r")))
+        (sign_extend:DI
+         (plus:SI (plus:SI (match_operand:SI 4 "arm_carry_operation" "")
+                           (match_dup 1))
+                  (match_dup 2)))))
+   (set (match_operand:SI 0 "s_register_operand" "=l,r")
+       (plus:SI (plus:SI (match_dup 4) (match_dup 1))
+                (match_dup 2)))]
+  "TARGET_32BIT"
+  "@
+   adcs%?\\t%0, %0, %2
+   adcs%?\\t%0, %1, %2"
+  [(set_attr "type" "alus_sreg")
+   (set_attr "arch" "t2,*")
+   (set_attr "length" "2,4")]
+)
+
+(define_expand "addsi3_cin_vout_imm"
+  [(parallel
+    [(set (match_dup 3)
+         (compare:CC_V
+          (plus:DI
+           (plus:DI (match_dup 4)
+                    (sign_extend:DI (match_operand:SI 1 "s_register_operand")))
+           (match_dup 2))
+          (sign_extend:DI (plus:SI (plus:SI (match_dup 5) (match_dup 1))
+                                   (match_dup 2)))))
+     (set (match_operand:SI 0 "s_register_operand")
+         (plus:SI (plus:SI (match_dup 5) (match_dup 1))
+                  (match_operand 2 "arm_adcimm_operand")))])]
+  "TARGET_32BIT"
+  {
+    operands[3] = gen_rtx_REG (CC_Vmode, CC_REGNUM);
+    rtx ccin = gen_rtx_REG (CC_Cmode, CC_REGNUM);
+    operands[4] = gen_rtx_LTU (DImode, ccin, const0_rtx);
+    operands[5] = gen_rtx_LTU (SImode, ccin, const0_rtx);
+  }
+)
+
+(define_insn "*addsi3_cin_vout_imm_insn"
+  [(set (reg:CC_V CC_REGNUM)
+       (compare:CC_V
+        (plus:DI
+         (plus:DI
+          (match_operand:DI 3 "arm_carry_operation" "")
+          (sign_extend:DI (match_operand:SI 1 "s_register_operand" "r,r")))
+         (match_operand 2 "arm_adcimm_operand" "I,K"))
+        (sign_extend:DI
+         (plus:SI (plus:SI (match_operand:SI 4 "arm_carry_operation" "")
+                           (match_dup 1))
+                  (match_dup 2)))))
+   (set (match_operand:SI 0 "s_register_operand" "=r,r")
+       (plus:SI (plus:SI (match_dup 4) (match_dup 1))
+                (match_dup 2)))]
+  "TARGET_32BIT"
+  "@
+   adcs%?\\t%0, %1, %2
+   sbcs%?\\t%0, %1, #%B2"
+  [(set_attr "type" "alus_imm")]
+)
+
+(define_expand "addsi3_cin_vout_0"
+  [(parallel
+    [(set (match_dup 2)
+         (compare:CC_V
+          (plus:DI (match_dup 3)
+                   (sign_extend:DI (match_operand:SI 1 "s_register_operand")))
+          (sign_extend:DI (plus:SI (match_dup 4) (match_dup 1)))))
+     (set (match_operand:SI 0 "s_register_operand")
+         (plus:SI (match_dup 4) (match_dup 1)))])]
+  "TARGET_32BIT"
+  {
+    operands[2] = gen_rtx_REG (CC_Vmode, CC_REGNUM);
+    rtx ccin = gen_rtx_REG (CC_Cmode, CC_REGNUM);
+    operands[3] = gen_rtx_LTU (DImode, ccin, const0_rtx);
+    operands[4] = gen_rtx_LTU (SImode, ccin, const0_rtx);
+  }
+)
+
+(define_insn "*addsi3_cin_vout_0_insn"
+  [(set (reg:CC_V CC_REGNUM)
+       (compare:CC_V
+        (plus:DI
+         (match_operand:DI 2 "arm_carry_operation" "")
+         (sign_extend:DI (match_operand:SI 1 "s_register_operand" "r")))
+        (sign_extend:DI (plus:SI
+                         (match_operand:SI 3 "arm_carry_operation" "")
+                         (match_dup 1)))))
+   (set (match_operand:SI 0 "s_register_operand" "=r")
+       (plus:SI (match_dup 3) (match_dup 1)))]
+  "TARGET_32BIT"
+  "adcs%?\\t%0, %1, #0"
+  [(set_attr "type" "alus_imm")]
+)
+
+(define_expand "uaddvsi4"
+  [(match_operand:SI 0 "s_register_operand")
+   (match_operand:SI 1 "s_register_operand")
+   (match_operand:SI 2 "arm_add_operand")
+   (match_operand 3 "")]
+  "TARGET_32BIT"
+{
+  emit_insn (gen_addsi3_compare_op1 (operands[0], operands[1], operands[2]));
   arm_gen_unlikely_cbranch (LTU, CC_Cmode, operands[3]);
 
   DONE;
 })
 
+(define_expand "uaddvdi4"
+  [(match_operand:DI 0 "s_register_operand")
+   (match_operand:DI 1 "s_register_operand")
+   (match_operand:DI 2 "reg_or_int_operand")
+   (match_operand 3 "")]
+  "TARGET_32BIT"
+{
+  rtx lo_result, hi_result;
+  rtx lo_op1, hi_op1, lo_op2, hi_op2;
+  arm_decompose_di_binop (operands[1], operands[2], &lo_op1, &hi_op1,
+                         &lo_op2, &hi_op2);
+  lo_result = gen_lowpart (SImode, operands[0]);
+  hi_result = gen_highpart (SImode, operands[0]);
+
+  if (lo_op2 == const0_rtx)
+    {
+      emit_move_insn (lo_result, lo_op1);
+      if (!arm_add_operand (hi_op2, SImode))
+       hi_op2 = force_reg (SImode, hi_op2);
+
+      gen_uaddvsi4 (hi_result, hi_op1, hi_op2, operands[3]);
+    }
+  else
+    {
+      if (!arm_add_operand (lo_op2, SImode))
+       lo_op2 = force_reg (SImode, lo_op2);
+      if (!arm_not_operand (hi_op2, SImode))
+       hi_op2 = force_reg (SImode, hi_op2);
+
+      emit_insn (gen_addsi3_compare_op1 (lo_result, lo_op1, lo_op2));
+
+      if (hi_op2 == const0_rtx)
+        emit_insn (gen_addsi3_cin_cout_0 (hi_result, hi_op1));
+      else if (CONST_INT_P (hi_op2))
+        emit_insn (gen_addsi3_cin_cout_imm (hi_result, hi_op1, hi_op2));
+      else
+        emit_insn (gen_addsi3_cin_cout_reg (hi_result, hi_op1, hi_op2));
+
+      arm_gen_unlikely_cbranch (GEU, CC_ADCmode, operands[3]);
+    }
+
+  DONE;
+})
+
+(define_expand "addsi3_cin_cout_reg"
+  [(parallel
+    [(set (match_dup 3)
+         (compare:CC_ADC
+          (plus:DI
+           (plus:DI (match_dup 4)
+                    (zero_extend:DI (match_operand:SI 1 "s_register_operand")))
+           (zero_extend:DI (match_operand:SI 2 "s_register_operand")))
+          (const_int 4294967296)))
+     (set (match_operand:SI 0 "s_register_operand")
+         (plus:SI (plus:SI (match_dup 5) (match_dup 1))
+                  (match_dup 2)))])]
+  "TARGET_32BIT"
+  {
+    operands[3] = gen_rtx_REG (CC_ADCmode, CC_REGNUM);
+    rtx ccin = gen_rtx_REG (CC_Cmode, CC_REGNUM);
+    operands[4] = gen_rtx_LTU (DImode, ccin, const0_rtx);
+    operands[5] = gen_rtx_LTU (SImode, ccin, const0_rtx);
+  }
+)
+
+(define_insn "*addsi3_cin_cout_reg_insn"
+  [(set (reg:CC_ADC CC_REGNUM)
+       (compare:CC_ADC
+        (plus:DI
+         (plus:DI
+          (match_operand:DI 3 "arm_carry_operation" "")
+          (zero_extend:DI (match_operand:SI 1 "s_register_operand" "%0,r")))
+         (zero_extend:DI (match_operand:SI 2 "s_register_operand" "l,r")))
+       (const_int 4294967296)))
+   (set (match_operand:SI 0 "s_register_operand" "=l,r")
+       (plus:SI (plus:SI (match_operand:SI 4 "arm_carry_operation" "")
+                         (match_dup 1))
+                (match_dup 2)))]
+  "TARGET_32BIT"
+  "@
+   adcs%?\\t%0, %0, %2
+   adcs%?\\t%0, %1, %2"
+  [(set_attr "type" "alus_sreg")
+   (set_attr "arch" "t2,*")
+   (set_attr "length" "2,4")]
+)
+
+(define_expand "addsi3_cin_cout_imm"
+  [(parallel
+    [(set (match_dup 3)
+         (compare:CC_ADC
+          (plus:DI
+           (plus:DI (match_dup 4)
+                    (zero_extend:DI (match_operand:SI 1 "s_register_operand")))
+           (match_dup 6))
+          (const_int 4294967296)))
+     (set (match_operand:SI 0 "s_register_operand")
+         (plus:SI (plus:SI (match_dup 5) (match_dup 1))
+                  (match_operand:SI 2 "arm_adcimm_operand")))])]
+  "TARGET_32BIT"
+  {
+    operands[3] = gen_rtx_REG (CC_ADCmode, CC_REGNUM);
+    rtx ccin = gen_rtx_REG (CC_Cmode, CC_REGNUM);
+    operands[4] = gen_rtx_LTU (DImode, ccin, const0_rtx);
+    operands[5] = gen_rtx_LTU (SImode, ccin, const0_rtx);
+    operands[6] = GEN_INT (UINTVAL (operands[2]) & 0xffffffff);
+  }
+)
+
+(define_insn "*addsi3_cin_cout_imm_insn"
+  [(set (reg:CC_ADC CC_REGNUM)
+       (compare:CC_ADC
+        (plus:DI
+         (plus:DI
+          (match_operand:DI 3 "arm_carry_operation" "")
+          (zero_extend:DI (match_operand:SI 1 "s_register_operand" "r,r")))
+         (match_operand:DI 5 "const_int_operand" "n,n"))
+       (const_int 4294967296)))
+   (set (match_operand:SI 0 "s_register_operand" "=r,r")
+       (plus:SI (plus:SI (match_operand:SI 4 "arm_carry_operation" "")
+                         (match_dup 1))
+                (match_operand:SI 2 "arm_adcimm_operand" "I,K")))]
+  "TARGET_32BIT
+   && (UINTVAL (operands[2]) & 0xffffffff) == UINTVAL (operands[5])"
+  "@
+   adcs%?\\t%0, %1, %2
+   sbcs%?\\t%0, %1, #%B2"
+  [(set_attr "type" "alus_imm")]
+)
+
+(define_expand "addsi3_cin_cout_0"
+  [(parallel
+    [(set (match_dup 2)
+         (compare:CC_ADC
+          (plus:DI (match_dup 3)
+                   (zero_extend:DI (match_operand:SI 1 "s_register_operand")))
+          (const_int 4294967296)))
+     (set (match_operand:SI 0 "s_register_operand")
+         (plus:SI (match_dup 4) (match_dup 1)))])]
+  "TARGET_32BIT"
+  {
+    operands[2] = gen_rtx_REG (CC_ADCmode, CC_REGNUM);
+    rtx ccin = gen_rtx_REG (CC_Cmode, CC_REGNUM);
+    operands[3] = gen_rtx_LTU (DImode, ccin, const0_rtx);
+    operands[4] = gen_rtx_LTU (SImode, ccin, const0_rtx);
+  }
+)
+
+(define_insn "*addsi3_cin_cout_0_insn"
+  [(set (reg:CC_ADC CC_REGNUM)
+       (compare:CC_ADC
+        (plus:DI
+         (match_operand:DI 2 "arm_carry_operation" "")
+         (zero_extend:DI (match_operand:SI 1 "s_register_operand" "r")))
+       (const_int 4294967296)))
+   (set (match_operand:SI 0 "s_register_operand" "=r")
+       (plus:SI (match_operand:SI 3 "arm_carry_operation" "") (match_dup 1)))]
+  "TARGET_32BIT"
+  "adcs%?\\t%0, %1, #0"
+  [(set_attr "type" "alus_imm")]
+)
+
 (define_expand "addsi3"
   [(set (match_operand:SI          0 "s_register_operand")
        (plus:SI (match_operand:SI 1 "s_register_operand")
  ]
 )
 
-(define_insn "adddi3_compareV"
+(define_insn "addsi3_compareV_reg"
   [(set (reg:CC_V CC_REGNUM)
-       (ne:CC_V
-         (plus:TI
-           (sign_extend:TI (match_operand:DI 1 "s_register_operand" "r"))
-           (sign_extend:TI (match_operand:DI 2 "s_register_operand" "r")))
-         (sign_extend:TI (plus:DI (match_dup 1) (match_dup 2)))))
-   (set (match_operand:DI 0 "s_register_operand" "=&r")
-       (plus:DI (match_dup 1) (match_dup 2)))]
+       (compare:CC_V
+         (plus:DI
+           (sign_extend:DI (match_operand:SI 1 "register_operand" "%l,0,r"))
+           (sign_extend:DI (match_operand:SI 2 "register_operand" "l,r,r")))
+         (sign_extend:DI (plus:SI (match_dup 1) (match_dup 2)))))
+   (set (match_operand:SI 0 "register_operand" "=l,r,r")
+       (plus:SI (match_dup 1) (match_dup 2)))]
   "TARGET_32BIT"
-  "adds\\t%Q0, %Q1, %Q2;adcs\\t%R0, %R1, %R2"
- [(set_attr "conds" "set")
-   (set_attr "length" "8")
-   (set_attr "type" "multiple")]
+  "adds%?\\t%0, %1, %2"
+  [(set_attr "conds" "set")
+   (set_attr "arch" "t2,t2,*")
+   (set_attr "length" "2,2,4")
+   (set_attr "type" "alus_sreg")]
 )
 
-(define_insn "addsi3_compareV"
+(define_insn "*addsi3_compareV_reg_nosum"
   [(set (reg:CC_V CC_REGNUM)
-       (ne:CC_V
+       (compare:CC_V
          (plus:DI
-           (sign_extend:DI (match_operand:SI 1 "register_operand" "r"))
-           (sign_extend:DI (match_operand:SI 2 "register_operand" "r")))
-         (sign_extend:DI (plus:SI (match_dup 1) (match_dup 2)))))
-   (set (match_operand:SI 0 "register_operand" "=r")
-       (plus:SI (match_dup 1) (match_dup 2)))]
+           (sign_extend:DI (match_operand:SI 0 "register_operand" "%l,r"))
+           (sign_extend:DI (match_operand:SI 1 "register_operand" "l,r")))
+         (sign_extend:DI (plus:SI (match_dup 0) (match_dup 1)))))]
   "TARGET_32BIT"
-  "adds%?\\t%0, %1, %2"
+  "cmn%?\\t%0, %1"
   [(set_attr "conds" "set")
+   (set_attr "arch" "t2,*")
+   (set_attr "length" "2,4")
    (set_attr "type" "alus_sreg")]
 )
 
-(define_insn "adddi3_compareC"
-  [(set (reg:CC_C CC_REGNUM)
-       (compare:CC_C
+(define_insn "addsi3_compareV_imm"
+  [(set (reg:CC_V CC_REGNUM)
+       (compare:CC_V
          (plus:DI
-           (match_operand:DI 1 "register_operand" "r")
-           (match_operand:DI 2 "register_operand" "r"))
-         (match_dup 1)))
-   (set (match_operand:DI 0 "register_operand" "=&r")
-       (plus:DI (match_dup 1) (match_dup 2)))]
-  "TARGET_32BIT"
-  "adds\\t%Q0, %Q1, %Q2;adcs\\t%R0, %R1, %R2"
- [(set_attr "conds" "set")
-   (set_attr "length" "8")
-   (set_attr "type" "multiple")]
+           (sign_extend:DI
+            (match_operand:SI 1 "register_operand" "l,0,l,0,r,r"))
+           (match_operand 2 "arm_addimm_operand" "Pd,Py,Px,Pw,I,L"))
+         (sign_extend:DI (plus:SI (match_dup 1) (match_dup 2)))))
+   (set (match_operand:SI 0 "register_operand" "=l,l,l,l,r,r")
+       (plus:SI (match_dup 1) (match_dup 2)))]
+  "TARGET_32BIT
+   && INTVAL (operands[2]) == ARM_SIGN_EXTEND (INTVAL (operands[2]))"
+  "@
+   adds%?\\t%0, %1, %2
+   adds%?\\t%0, %0, %2
+   subs%?\\t%0, %1, #%n2
+   subs%?\\t%0, %0, #%n2
+   adds%?\\t%0, %1, %2
+   subs%?\\t%0, %1, #%n2"
+  [(set_attr "conds" "set")
+   (set_attr "arch" "t2,t2,t2,t2,*,*")
+   (set_attr "length" "2,2,2,2,4,4")
+   (set_attr "type" "alus_imm")]
 )
 
-(define_insn "addsi3_compareC"
-   [(set (reg:CC_C CC_REGNUM)
-        (compare:CC_C (plus:SI (match_operand:SI 1 "register_operand" "r")
-                               (match_operand:SI 2 "register_operand" "r"))
-                      (match_dup 1)))
-    (set (match_operand:SI 0 "register_operand" "=r")
-        (plus:SI (match_dup 1) (match_dup 2)))]
-  "TARGET_32BIT"
-  "adds%?\\t%0, %1, %2"
+(define_insn "addsi3_compareV_imm_nosum"
+  [(set (reg:CC_V CC_REGNUM)
+       (compare:CC_V
+         (plus:DI
+           (sign_extend:DI
+            (match_operand:SI 0 "register_operand" "l,r,r"))
+           (match_operand 1 "arm_addimm_operand" "Pw,I,L"))
+         (sign_extend:DI (plus:SI (match_dup 0) (match_dup 1)))))]
+  "TARGET_32BIT
+   && INTVAL (operands[1]) == ARM_SIGN_EXTEND (INTVAL (operands[1]))"
+  "@
+   cmp%?\\t%0, #%n1
+   cmn%?\\t%0, %1
+   cmp%?\\t%0, #%n1"
   [(set_attr "conds" "set")
-   (set_attr "type" "alus_sreg")]
+   (set_attr "arch" "t2,*,*")
+   (set_attr "length" "2,4,4")
+   (set_attr "type" "alus_imm")]
+)
+
+;; We can handle more constants efficently if we can clobber either a scratch
+;; or the other source operand.  We deliberately leave this late as in
+;; high register pressure situations it's not worth forcing any reloads.
+(define_peephole2
+  [(match_scratch:SI 2 "l")
+   (set (reg:CC_V CC_REGNUM)
+       (compare:CC_V
+         (plus:DI
+           (sign_extend:DI
+            (match_operand:SI 0 "low_register_operand"))
+           (match_operand 1 "const_int_operand"))
+         (sign_extend:DI (plus:SI (match_dup 0) (match_dup 1)))))]
+  "TARGET_THUMB2
+   && satisfies_constraint_Pd (operands[1])"
+  [(parallel[
+    (set (reg:CC_V CC_REGNUM)
+        (compare:CC_V
+         (plus:DI (sign_extend:DI (match_dup 0))
+                  (sign_extend:DI (match_dup 1)))
+         (sign_extend:DI (plus:SI (match_dup 0) (match_dup 1)))))
+    (set (match_dup 2) (plus:SI (match_dup 0) (match_dup 1)))])]
+)
+
+(define_peephole2
+  [(set (reg:CC_V CC_REGNUM)
+       (compare:CC_V
+         (plus:DI
+           (sign_extend:DI
+            (match_operand:SI 0 "low_register_operand"))
+           (match_operand 1 "const_int_operand"))
+         (sign_extend:DI (plus:SI (match_dup 0) (match_dup 1)))))]
+  "TARGET_THUMB2
+   && dead_or_set_p (peep2_next_insn (0), operands[0])
+   && satisfies_constraint_Py (operands[1])"
+  [(parallel[
+    (set (reg:CC_V CC_REGNUM)
+        (compare:CC_V
+         (plus:DI (sign_extend:DI (match_dup 0))
+                  (sign_extend:DI (match_dup 1)))
+         (sign_extend:DI (plus:SI (match_dup 0) (match_dup 1)))))
+    (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 1)))])]
 )
 
 (define_insn "addsi3_compare0"
 ;; the operands, and we know that the use of the condition code is
 ;; either GEU or LTU, so we can use the carry flag from the addition
 ;; instead of doing the compare a second time.
-(define_insn "*addsi3_compare_op1"
+(define_insn "addsi3_compare_op1"
   [(set (reg:CC_C CC_REGNUM)
        (compare:CC_C
-        (plus:SI (match_operand:SI 1 "s_register_operand" "l,0,l,0,r,r,r")
-                 (match_operand:SI 2 "arm_add_operand" "lPd,Py,lPx,Pw,I,L,r"))
+        (plus:SI (match_operand:SI 1 "s_register_operand" "l,0,l,0,rk,rk")
+                 (match_operand:SI 2 "arm_add_operand" "lPd,Py,lPx,Pw,rkI,L"))
         (match_dup 1)))
-   (set (match_operand:SI 0 "s_register_operand" "=l,l,l,l,r,r,r")
+   (set (match_operand:SI 0 "s_register_operand" "=l,l,l,l,rk,rk")
        (plus:SI (match_dup 1) (match_dup 2)))]
   "TARGET_32BIT"
   "@
    subs%?\\t%0, %1, #%n2
    subs%?\\t%0, %0, #%n2
    adds%?\\t%0, %1, %2
-   subs%?\\t%0, %1, #%n2
-   adds%?\\t%0, %1, %2"
+   subs%?\\t%0, %1, #%n2"
   [(set_attr "conds" "set")
-   (set_attr "arch" "t2,t2,t2,t2,*,*,*")
-   (set_attr "length" "2,2,2,2,4,4,4")
-   (set_attr "type"
-    "alus_sreg,alus_imm,alus_sreg,alus_imm,alus_imm,alus_imm,alus_sreg")]
+   (set_attr "arch" "t2,t2,t2,t2,*,*")
+   (set_attr "length" "2,2,2,2,4,4")
+   (set (attr "type")
+       (if_then_else (match_operand 2 "const_int_operand")
+                     (const_string "alu_imm")
+                     (const_string "alu_sreg")))]
 )
 
 (define_insn "*addsi3_compare_op2"
   [(set (reg:CC_C CC_REGNUM)
        (compare:CC_C
-        (plus:SI (match_operand:SI 1 "s_register_operand" "l,0,l,0,r,r,r")
-                 (match_operand:SI 2 "arm_add_operand" "lPd,Py,lPx,Pw,I,L,r"))
+        (plus:SI (match_operand:SI 1 "s_register_operand" "l,0,l,0,r,r")
+                 (match_operand:SI 2 "arm_add_operand" "lPd,Py,lPx,Pw,rI,L"))
         (match_dup 2)))
-   (set (match_operand:SI 0 "s_register_operand" "=l,l,l,l,r,r,r")
+   (set (match_operand:SI 0 "s_register_operand" "=l,l,l,l,r,r")
        (plus:SI (match_dup 1) (match_dup 2)))]
   "TARGET_32BIT"
   "@
    subs%?\\t%0, %1, #%n2
    subs%?\\t%0, %0, #%n2
    adds%?\\t%0, %1, %2
-   subs%?\\t%0, %1, #%n2
-   adds%?\\t%0, %1, %2"
+   subs%?\\t%0, %1, #%n2"
   [(set_attr "conds" "set")
-   (set_attr "arch" "t2,t2,t2,t2,*,*,*")
-   (set_attr "length" "2,2,2,2,4,4,4")
-   (set_attr "type"
-    "alus_sreg,alus_imm,alus_sreg,alus_imm,alus_imm,alus_imm,alus_sreg")]
+   (set_attr "arch" "t2,t2,t2,t2,*,*")
+   (set_attr "length" "2,2,2,2,4,4")
+   (set (attr "type")
+       (if_then_else (match_operand 2 "const_int_operand")
+                     (const_string "alu_imm")
+                     (const_string "alu_sreg")))]
 )
 
 (define_insn "*compare_addsi2_op0"
   [(set (reg:CC_C CC_REGNUM)
         (compare:CC_C
-          (plus:SI (match_operand:SI 0 "s_register_operand" "l,l,r,r,r")
-                   (match_operand:SI 1 "arm_add_operand" "Pv,l,I,L,r"))
+          (plus:SI (match_operand:SI 0 "s_register_operand" "l,l,r,r")
+                   (match_operand:SI 1 "arm_add_operand"    "l,Pw,rI,L"))
           (match_dup 0)))]
   "TARGET_32BIT"
   "@
-   cmp%?\\t%0, #%n1
-   cmn%?\\t%0, %1
    cmn%?\\t%0, %1
    cmp%?\\t%0, #%n1
-   cmn%?\\t%0, %1"
+   cmn%?\\t%0, %1
+   cmp%?\\t%0, #%n1"
   [(set_attr "conds" "set")
    (set_attr "predicable" "yes")
-   (set_attr "arch" "t2,t2,*,*,*")
-   (set_attr "predicable_short_it" "yes,yes,no,no,no")
-   (set_attr "length" "2,2,4,4,4")
-   (set_attr "type" "alus_imm,alus_sreg,alus_imm,alus_imm,alus_sreg")]
+   (set_attr "arch" "t2,t2,*,*")
+   (set_attr "predicable_short_it" "yes,yes,no,no")
+   (set_attr "length" "2,2,4,4")
+   (set (attr "type")
+       (if_then_else (match_operand 1 "const_int_operand")
+                     (const_string "alu_imm")
+                     (const_string "alu_sreg")))]
 )
 
 (define_insn "*compare_addsi2_op1"
   [(set (reg:CC_C CC_REGNUM)
         (compare:CC_C
-          (plus:SI (match_operand:SI 0 "s_register_operand" "l,l,r,r,r")
-                   (match_operand:SI 1 "arm_add_operand" "Pv,l,I,L,r"))
+          (plus:SI (match_operand:SI 0 "s_register_operand" "l,l,r,r")
+                   (match_operand:SI 1 "arm_add_operand" "l,Pw,rI,L"))
           (match_dup 1)))]
   "TARGET_32BIT"
   "@
-   cmp%?\\t%0, #%n1
-   cmn%?\\t%0, %1
    cmn%?\\t%0, %1
    cmp%?\\t%0, #%n1
-   cmn%?\\t%0, %1"
+   cmn%?\\t%0, %1
+   cmp%?\\t%0, #%n1"
   [(set_attr "conds" "set")
    (set_attr "predicable" "yes")
-   (set_attr "arch" "t2,t2,*,*,*")
-   (set_attr "predicable_short_it" "yes,yes,no,no,no")
-   (set_attr "length" "2,2,4,4,4")
-   (set_attr "type" "alus_imm,alus_sreg,alus_imm,alus_imm,alus_sreg")]
+   (set_attr "arch" "t2,t2,*,*")
+   (set_attr "predicable_short_it" "yes,yes,no,no")
+   (set_attr "length" "2,2,4,4")
+   (set (attr "type")
+       (if_then_else (match_operand 1 "const_int_operand")
+                     (const_string "alu_imm")
+                     (const_string "alu_sreg")))]
  )
 
-(define_insn "addsi3_carryin_<optab>"
+(define_insn "addsi3_carryin"
   [(set (match_operand:SI 0 "s_register_operand" "=l,r,r")
         (plus:SI (plus:SI (match_operand:SI 1 "s_register_operand" "%l,r,r")
                           (match_operand:SI 2 "arm_not_operand" "0,rI,K"))
-                 (LTUGEU:SI (reg:<cnb> CC_REGNUM) (const_int 0))))]
+                 (match_operand:SI 3 "arm_carry_operation" "")))]
   "TARGET_32BIT"
   "@
    adc%?\\t%0, %1, %2
 )
 
 ;; Canonicalization of the above when the immediate is zero.
-(define_insn "add0si3_carryin_<optab>"
+(define_insn "add0si3_carryin"
   [(set (match_operand:SI 0 "s_register_operand" "=r")
-       (plus:SI (LTUGEU:SI (reg:<cnb> CC_REGNUM) (const_int 0))
+       (plus:SI (match_operand:SI 2 "arm_carry_operation" "")
                 (match_operand:SI 1 "arm_not_operand" "r")))]
   "TARGET_32BIT"
   "adc%?\\t%0, %1, #0"
    (set_attr "type" "adc_imm")]
 )
 
-(define_insn "*addsi3_carryin_alt2_<optab>"
+(define_insn "*addsi3_carryin_alt2"
   [(set (match_operand:SI 0 "s_register_operand" "=l,r,r")
-        (plus:SI (plus:SI (LTUGEU:SI (reg:<cnb> CC_REGNUM) (const_int 0))
+        (plus:SI (plus:SI (match_operand:SI 3 "arm_carry_operation" "")
                           (match_operand:SI 1 "s_register_operand" "%l,r,r"))
                  (match_operand:SI 2 "arm_not_operand" "l,rI,K")))]
   "TARGET_32BIT"
    (set_attr "type" "adc_reg,adc_reg,adc_imm")]
 )
 
-(define_insn "*addsi3_carryin_shift_<optab>"
-  [(set (match_operand:SI 0 "s_register_operand" "=r")
+(define_insn "*addsi3_carryin_shift"
+  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
        (plus:SI (plus:SI
                  (match_operator:SI 2 "shift_operator"
-                   [(match_operand:SI 3 "s_register_operand" "r")
-                    (match_operand:SI 4 "reg_or_int_operand" "rM")])
-                 (LTUGEU:SI (reg:<cnb> CC_REGNUM) (const_int 0)))
-                (match_operand:SI 1 "s_register_operand" "r")))]
+                   [(match_operand:SI 3 "s_register_operand" "r,r")
+                    (match_operand:SI 4 "shift_amount_operand" "M,r")])
+                 (match_operand:SI 5 "arm_carry_operation" ""))
+                (match_operand:SI 1 "s_register_operand" "r,r")))]
   "TARGET_32BIT"
   "adc%?\\t%0, %1, %3%S2"
   [(set_attr "conds" "use")
+   (set_attr "arch" "32,a")
+   (set_attr "shift" "3")
    (set_attr "predicable" "yes")
    (set (attr "type") (if_then_else (match_operand 4 "const_int_operand" "")
                      (const_string "alu_shift_imm")
                      (const_string "alu_shift_reg")))]
 )
 
-(define_insn "*addsi3_carryin_clobercc_<optab>"
+(define_insn "*addsi3_carryin_clobercc"
   [(set (match_operand:SI 0 "s_register_operand" "=r")
        (plus:SI (plus:SI (match_operand:SI 1 "s_register_operand" "%r")
                          (match_operand:SI 2 "arm_rhs_operand" "rI"))
-                (LTUGEU:SI (reg:<cnb> CC_REGNUM) (const_int 0))))
+                (match_operand:SI 3 "arm_carry_operation" "")))
    (clobber (reg:CC CC_REGNUM))]
    "TARGET_32BIT"
    "adcs%?\\t%0, %1, %2"
    (set_attr "type" "adc_reg,adc_imm,alu_shift_imm")]
 )
 
+(define_insn "cmpsi3_carryin_<CC_EXTEND>out"
+  [(set (reg:<CC_EXTEND> CC_REGNUM)
+       (compare:<CC_EXTEND>
+        (SE:DI (match_operand:SI 1 "s_register_operand" "0,r"))
+        (plus:DI (match_operand:DI 3 "arm_borrow_operation" "")
+                 (SE:DI (match_operand:SI 2 "s_register_operand" "l,r")))))
+   (clobber (match_scratch:SI 0 "=l,r"))]
+  "TARGET_32BIT"
+  "sbcs\\t%0, %1, %2"
+  [(set_attr "conds" "set")
+   (set_attr "arch" "t2,*")
+   (set_attr "length" "2,4")
+   (set_attr "type" "adc_reg")]
+)
+
+;; Similar to the above, but handling a constant which has a different
+;; canonicalization.
+(define_insn "cmpsi3_imm_carryin_<CC_EXTEND>out"
+  [(set (reg:<CC_EXTEND> CC_REGNUM)
+       (compare:<CC_EXTEND>
+        (SE:DI (match_operand:SI 1 "s_register_operand" "r,r"))
+        (plus:DI (match_operand:DI 3 "arm_borrow_operation" "")
+                 (match_operand:DI 2 "arm_adcimm_operand" "I,K"))))
+   (clobber (match_scratch:SI 0 "=l,r"))]
+  "TARGET_32BIT"
+  "@
+   sbcs\\t%0, %1, %2
+   adcs\\t%0, %1, #%B2"
+  [(set_attr "conds" "set")
+   (set_attr "type" "adc_imm")]
+)
+
+;; Further canonicalization when the constant is zero.
+(define_insn "cmpsi3_0_carryin_<CC_EXTEND>out"
+  [(set (reg:<CC_EXTEND> CC_REGNUM)
+       (compare:<CC_EXTEND>
+        (SE:DI (match_operand:SI 1 "s_register_operand" "r,r"))
+        (match_operand:DI 2 "arm_borrow_operation" "")))
+   (clobber (match_scratch:SI 0 "=l,r"))]
+  "TARGET_32BIT"
+  "sbcs\\t%0, %1, #0"
+  [(set_attr "conds" "set")
+   (set_attr "type" "adc_imm")]
+)
+
 (define_insn "*subsi3_carryin_const"
   [(set (match_operand:SI 0 "s_register_operand" "=r")
        (minus:SI (plus:SI
                                    (const_string "alu_shift_reg")))]
 )
 
+(define_insn "*subsi3_carryin_shift_alt"
+  [(set (match_operand:SI 0 "s_register_operand" "=r")
+       (minus:SI (minus:SI
+                  (match_operand:SI 1 "s_register_operand" "r")
+                  (match_operand:SI 5 "arm_borrow_operation" ""))
+                 (match_operator:SI 2 "shift_operator"
+                  [(match_operand:SI 3 "s_register_operand" "r")
+                   (match_operand:SI 4 "reg_or_int_operand" "rM")])))]
+  "TARGET_32BIT"
+  "sbc%?\\t%0, %1, %3%S2"
+  [(set_attr "conds" "use")
+   (set_attr "predicable" "yes")
+   (set (attr "type") (if_then_else (match_operand 4 "const_int_operand" "")
+                                   (const_string "alu_shift_imm")
+                                   (const_string "alu_shift_reg")))]
+)
+
 (define_insn "*rsbsi3_carryin_shift"
   [(set (match_operand:SI 0 "s_register_operand" "=r")
        (minus:SI (minus:SI
                      (const_string "alu_shift_reg")))]
 )
 
+(define_insn "*rsbsi3_carryin_shift_alt"
+  [(set (match_operand:SI 0 "s_register_operand" "=r")
+       (minus:SI (minus:SI
+                  (match_operator:SI 2 "shift_operator"
+                   [(match_operand:SI 3 "s_register_operand" "r")
+                    (match_operand:SI 4 "reg_or_int_operand" "rM")])
+                   (match_operand:SI 5 "arm_borrow_operation" ""))
+                 (match_operand:SI 1 "s_register_operand" "r")))]
+  "TARGET_ARM"
+  "rsc%?\\t%0, %1, %3%S2"
+  [(set_attr "conds" "use")
+   (set_attr "predicable" "yes")
+   (set (attr "type") (if_then_else (match_operand 4 "const_int_operand" "")
+                     (const_string "alu_shift_imm")
+                     (const_string "alu_shift_reg")))]
+)
+
 ; transform ((x << y) - 1) to ~(~(x-1) << y)  Where X is a constant.
 (define_split
   [(set (match_operand:SI 0 "s_register_operand" "")
    (set_attr "type" "alus_imm")]
 )
 
+;; Similarly, but the result is unused.
+(define_insn "rsb_imm_compare_scratch"
+  [(set (reg:CC_RSB CC_REGNUM)
+       (compare:CC_RSB (not:SI (match_operand:SI 2 "s_register_operand" "r"))
+                       (match_operand 1 "arm_not_immediate_operand" "K")))
+   (clobber (match_scratch:SI 0 "=r"))]
+  "TARGET_32BIT"
+  "rsbs\\t%0, %2, #%B1"
+  [(set_attr "conds" "set")
+   (set_attr "type" "alus_imm")]
+)
+
+;; Compare the sum of a value plus a carry against a constant.  Uses
+;; RSC, so the result is swapped.  Only available on Arm
+(define_insn "rscsi3_<CC_EXTEND>out_scratch"
+  [(set (reg:CC_SWP CC_REGNUM)
+       (compare:CC_SWP
+        (plus:DI (SE:DI (match_operand:SI 2 "s_register_operand" "r"))
+                 (match_operand:DI 3 "arm_borrow_operation" ""))
+        (match_operand 1 "arm_immediate_operand" "I")))
+   (clobber (match_scratch:SI 0 "=r"))]
+  "TARGET_ARM"
+  "rscs\\t%0, %2, %1"
+  [(set_attr "conds" "set")
+   (set_attr "type" "alus_imm")]
+)
+
 (define_expand "subsf3"
   [(set (match_operand:SF           0 "s_register_operand")
        (minus:SF (match_operand:SF 1 "s_register_operand")
   [(set (pc) (if_then_else
              (match_operator 0 "expandable_comparison_operator"
               [(match_operand:DI 1 "s_register_operand")
-               (match_operand:DI 2 "cmpdi_operand")])
+               (match_operand:DI 2 "reg_or_int_operand")])
              (label_ref (match_operand 3 "" ""))
              (pc)))]
   "TARGET_32BIT"
    (set_attr "predicable" "yes")]
 )
 
-;; DImode comparisons.  The generic code generates branches that
-;; if-conversion cannot reduce to a conditional compare, so we do
-;; that directly.
-
-(define_insn "*arm_cmpdi_insn"
-  [(set (reg:CC_NCV CC_REGNUM)
-       (compare:CC_NCV (match_operand:DI 0 "s_register_operand" "r")
-                       (match_operand:DI 1 "arm_di_operand"       "rDi")))
-   (clobber (match_scratch:SI 2 "=r"))]
-  "TARGET_32BIT"
-  "cmp\\t%Q0, %Q1\;sbcs\\t%2, %R0, %R1"
-  [(set_attr "conds" "set")
-   (set_attr "length" "8")
-   (set_attr "type" "multiple")]
-)
-
-(define_insn_and_split "*arm_cmpdi_unsigned"
-  [(set (reg:CC_CZ CC_REGNUM)
-        (compare:CC_CZ (match_operand:DI 0 "s_register_operand" "l,r,r,r")
-                       (match_operand:DI 1 "arm_di_operand"     "Py,r,Di,rDi")))]
-
-  "TARGET_32BIT"
-  "#"   ; "cmp\\t%R0, %R1\;it eq\;cmpeq\\t%Q0, %Q1"
-  "&& reload_completed"
-  [(set (reg:CC CC_REGNUM)
-        (compare:CC (match_dup 2) (match_dup 3)))
-   (cond_exec (eq:SI (reg:CC CC_REGNUM) (const_int 0))
-              (set (reg:CC CC_REGNUM)
-                   (compare:CC (match_dup 0) (match_dup 1))))]
-  {
-    operands[2] = gen_highpart (SImode, operands[0]);
-    operands[0] = gen_lowpart (SImode, operands[0]);
-    if (CONST_INT_P (operands[1]))
-      operands[3] = gen_highpart_mode (SImode, DImode, operands[1]);
-    else
-      operands[3] = gen_highpart (SImode, operands[1]);
-    operands[1] = gen_lowpart (SImode, operands[1]);
-  }
-  [(set_attr "conds" "set")
-   (set_attr "enabled_for_short_it" "yes,yes,no,*")
-   (set_attr "arch" "t2,t2,t2,a")
-   (set_attr "length" "6,6,10,8")
-   (set_attr "type" "multiple")]
-)
-
-(define_insn "*arm_cmpdi_zero"
-  [(set (reg:CC_Z CC_REGNUM)
-       (compare:CC_Z (match_operand:DI 0 "s_register_operand" "r")
-                     (const_int 0)))
-   (clobber (match_scratch:SI 1 "=r"))]
-  "TARGET_32BIT"
-  "orrs%?\\t%1, %Q0, %R0"
-  [(set_attr "conds" "set")
-   (set_attr "type" "logics_reg")]
-)
-
 ; This insn allows redundant compares to be removed by cse, nothing should
 ; ever appear in the output file since (set (reg x) (reg x)) is a no-op that
 ; is deleted later on. The match_dup will match the mode here, so that
    (set_attr "type" "multiple")]
 )
 
+(define_insn "*negscc_borrow"
+  [(set (match_operand:SI 0 "s_register_operand" "=r")
+       (neg:SI (match_operand:SI 1 "arm_borrow_operation" "")))]
+  "TARGET_32BIT"
+  "sbc\\t%0, %0, %0"
+  [(set_attr "conds" "use")
+   (set_attr "length" "4")
+   (set_attr "type" "adc_reg")]
+)
+
 (define_insn_and_split "*mov_negscc"
   [(set (match_operand:SI 0 "s_register_operand" "=r")
        (neg:SI (match_operator:SI 1 "arm_comparison_operator_mode"
                 [(match_operand 2 "cc_register" "") (const_int 0)])))]
-  "TARGET_ARM"
+  "TARGET_ARM && !arm_borrow_operation (operands[1], SImode)"
   "#"   ; "mov%D1\\t%0, #0\;mvn%d1\\t%0, #0"
-  "TARGET_ARM"
+  "&& true"
   [(set (match_dup 0)
         (if_then_else:SI (match_dup 1)
                          (match_dup 3)
   [(set (match_operand:SI 0 "s_register_operand")
        (match_operator:SI 1 "expandable_comparison_operator"
         [(match_operand:DI 2 "s_register_operand")
-         (match_operand:DI 3 "cmpdi_operand")]))]
+         (match_operand:DI 3 "reg_or_int_operand")]))]
   "TARGET_32BIT"
   "{
      if (!arm_validize_comparison (&operands[1],