diff --git a/tcg/aarch64/tcg-target.c b/tcg/aarch64/tcg-target.c
index 3474ca4..967526b 100644
--- a/tcg/aarch64/tcg-target.c
+++ b/tcg/aarch64/tcg-target.c
@@ -109,8 +109,10 @@ static inline void patch_reloc(uint8_t *code_ptr, int type,
 #define TCG_CT_CONST_S25  0x100
 #define TCG_CT_CONST_LI32 0x200
 #define TCG_CT_CONST_LI64 0x400
-#define TCG_CT_CONST_CMP  0x800
-#define TCG_CT_CONST_ZERO 0x1000
+#define TCG_CT_CONST_ZERO 0x800
+#define TCG_CT_CONST_AI   0x1000
+#define TCG_CT_CONST_AIC  0x2000
+#define TCG_CT_CONST_AIN  0x4000
 
 #include "bitmask-table.h"
 
@@ -137,14 +139,11 @@ static int find_bitmask32(uint32_t val)
     return find_bitmask64(((uint64_t)val << 32) | val);
 }
 
-static int can_cmpi(tcg_target_long val)
+static int is_aimm(tcg_target_long val)
 {
-    if (val < 0) {
-        val = ~val;
-    }
     return (val & ~0xfff) == 0 || (val & ~0xfff000) == 0;
 }
-
+    
 /* parse target specific constraints */
 static int target_parse_constraint(TCGArgConstraint *ct,
                                    const char **pct_str)
@@ -168,12 +167,9 @@ static int target_parse_constraint(TCGArgConstraint *ct,
         tcg_regset_reset_reg(ct->u.regs, TCG_REG_X3);
 #endif
         break;
-    case 'A': /* 25-bit signed, to be added or subtracted.  */
+    case 'I': /* 25-bit signed, to be added or subtracted.  */
         ct->ct |= TCG_CT_CONST_S25;
         break;
-    case 'C': /* a 12-bit constant (maybe inverted) to be used with compare. */
-        ct->ct |= TCG_CT_CONST_CMP;
-        break;
     case 'K': /* logical immediate 32-bit */
         ct->ct |= TCG_CT_CONST_LI32;
         break;
@@ -183,6 +179,15 @@ static int target_parse_constraint(TCGArgConstraint *ct,
     case 'Z': /* zero */
         ct->ct |= TCG_CT_CONST_ZERO;
         break;
+    case 'A': /* an arithmetic immediate.  */
+        ct->ct |= TCG_CT_CONST_AI;
+        break;
+    case 'C': /* a complimented arithmetic immediate.  */
+        ct->ct |= TCG_CT_CONST_AIC;
+        break;
+    case 'N': /* a negated arithmetic immediate.  */
+        ct->ct |= TCG_CT_CONST_AIN;
+        break;
     default:
         return -1;
     }
@@ -209,10 +214,16 @@ static inline int tcg_target_const_match(tcg_target_long val,
     if ((ct & TCG_CT_CONST_LI32) && find_bitmask32(val) >= 0) {
         return 1;
     }
-    if ((ct & TCG_CT_CONST_CMP) && can_cmpi(val)) {
+    if ((ct & TCG_CT_CONST_ZERO) && val == 0) {
         return 1;
     }
-    if ((ct & TCG_CT_CONST_ZERO) && val == 0) {
+    if ((ct & TCG_CT_CONST_AI) && is_aimm(val)) {
+        return 1;
+    }
+    if ((ct & TCG_CT_CONST_AIC) && is_aimm(~val)) {
+        return 1;
+    }
+    if ((ct & TCG_CT_CONST_AIN) && is_aimm(-val)) {
         return 1;
     }
 
@@ -246,9 +257,14 @@ typedef enum {
 
     /* Add/subtract shifted register instructions */
     INSN_ADD   = 0x0b000000,
+    INSN_ADDS  = 0x2b000000,
     INSN_SUB   = 0x4b000000,
     INSN_SUBS  = 0x6b000000,
 
+    /* Add/subtract with carry instructions */
+    INSN_ADC   = 0x1a000000,
+    INSN_SBC   = 0x5a000000,
+
     /* Data-processing (1 source) instructions */
     INSN_REV16 = 0x5ac00400,
     INSN_REVx  = 0xdac00c00,
@@ -1242,6 +1258,33 @@ static inline void tcg_out_load_pair(TCGContext *s, TCGReg addr,
     tcg_out32(s, 0xa9400000 | idx << 16 | r2 << 10 | addr << 5 | r1);
 }
 
+static inline void tcg_out_addsub2(TCGContext *s, AArch64Ext ext, TCGReg rl,
+                                   TCGReg rh, TCGReg al, TCGReg ah,
+                                   tcg_target_long bl, TCGReg bh,
+                                   bool const_bl, bool sub)
+{
+    TCGReg orig_rl = rl;
+
+    if (rl == ah || rl == bh) {
+        rl = TCG_REG_TMP;
+    }
+    if (const_bl) {
+        if ((bl < 0) ^ sub) {
+            tcg_out_aimm(s, INSN_SUBSI, ext, rl, al, -bl);
+        } else {
+            tcg_out_aimm(s, INSN_ADDSI, ext, rl, al, bl);
+        }
+    } else {
+        tcg_out_arith(s, sub ? INSN_SUBS : INSN_ADDS, ext, rl, al, bl, 0);
+    }
+
+    tcg_out_arith(s, sub ? INSN_ADC : INSN_SBC, ext, rh, ah, bh, 0);
+
+    if (rl != orig_rl) {
+        tcg_out_movr(s, ext, orig_rl, rl);
+    }
+}
+
 static void tcg_out_op(TCGContext *s, TCGOpcode opc,
                        const TCGArg *args, const int *const_args)
 {
@@ -1562,7 +1605,21 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
     case INDEX_op_deposit_i32:
         tcg_out_dep(s, ext, args[0], REG0(2), args[3], args[4]);
         break;
-    
+
+    case INDEX_op_add2_i64:
+        ext = E64; /* fall through */
+    case INDEX_op_add2_i32:
+        tcg_out_addsub2(s, ext, args[0], args[1], REG0(2), REG0(3), args[4],
+                        REG0(5), const_args[4], false);
+        break;
+
+    case INDEX_op_sub2_i64:
+        ext = E64; /* fall through */
+    case INDEX_op_sub2_i32:
+        tcg_out_addsub2(s, ext, args[0], args[1], REG0(2), REG0(3), args[4],
+                        REG0(5), const_args[4], true);
+        break;
+
     default:
         tcg_abort(); /* opcode not implemented */
     }
@@ -1603,10 +1660,10 @@ static const TCGTargetOpDef aarch64_op_defs[] = {
     { INDEX_op_st32_i64, { "r", "r" } },
     { INDEX_op_st_i64, { "r", "r" } },
 
-    { INDEX_op_add_i32, { "r", "r", "rA" } },
-    { INDEX_op_add_i64, { "r", "r", "rA" } },
-    { INDEX_op_sub_i32, { "r", "rZ", "rA" } },
-    { INDEX_op_sub_i64, { "r", "rZ", "rA" } },
+    { INDEX_op_add_i32, { "r", "r", "rI" } },
+    { INDEX_op_add_i64, { "r", "r", "rI" } },
+    { INDEX_op_sub_i32, { "r", "rZ", "rI" } },
+    { INDEX_op_sub_i64, { "r", "rZ", "rI" } },
     { INDEX_op_mul_i32, { "r", "r", "r" } },
     { INDEX_op_mul_i64, { "r", "r", "r" } },
     { INDEX_op_and_i32, { "r", "r", "rK" } },
@@ -1636,12 +1693,12 @@ static const TCGTargetOpDef aarch64_op_defs[] = {
     { INDEX_op_rotl_i64, { "r", "r", "ri" } },
     { INDEX_op_rotr_i64, { "r", "r", "ri" } },
 
-    { INDEX_op_brcond_i32, { "r", "rC" } },
-    { INDEX_op_brcond_i64, { "r", "rC" } },
-    { INDEX_op_setcond_i32, { "r", "r", "rC" } },
-    { INDEX_op_setcond_i64, { "r", "r", "rC" } },
-    { INDEX_op_movcond_i32, { "r", "r", "rC", "rZ", "rZ" } },
-    { INDEX_op_movcond_i64, { "r", "r", "rC", "rZ", "rZ" } },
+    { INDEX_op_brcond_i32, { "r", "rAC" } },
+    { INDEX_op_brcond_i64, { "r", "rAC" } },
+    { INDEX_op_setcond_i32, { "r", "r", "rAC" } },
+    { INDEX_op_setcond_i64, { "r", "r", "rAC" } },
+    { INDEX_op_movcond_i32, { "r", "r", "rAC", "rZ", "rZ" } },
+    { INDEX_op_movcond_i64, { "r", "r", "rAC", "rZ", "rZ" } },
 
     { INDEX_op_qemu_ld8u, { "r", "l" } },
     { INDEX_op_qemu_ld8s, { "r", "l" } },
@@ -1679,6 +1736,11 @@ static const TCGTargetOpDef aarch64_op_defs[] = {
     { INDEX_op_deposit_i32, { "r", "0", "rZ" } },
     { INDEX_op_deposit_i64, { "r", "0", "rZ" } },
 
+    { INDEX_op_add2_i32, { "r", "r", "rZ", "rZ", "rAN", "rZ" } },
+    { INDEX_op_add2_i64, { "r", "r", "rZ", "rZ", "rAN", "rZ" } },
+    { INDEX_op_sub2_i32, { "r", "r", "rZ", "rZ", "rAN", "rZ" } },
+    { INDEX_op_sub2_i64, { "r", "r", "rZ", "rZ", "rAN", "rZ" } },
+
     { -1 },
 };
 
diff --git a/tcg/aarch64/tcg-target.h b/tcg/aarch64/tcg-target.h
index 4082172..0c71048 100644
--- a/tcg/aarch64/tcg-target.h
+++ b/tcg/aarch64/tcg-target.h
@@ -57,8 +57,8 @@ typedef enum {
 #define TCG_TARGET_HAS_nor_i32          0
 #define TCG_TARGET_HAS_deposit_i32      1
 #define TCG_TARGET_HAS_movcond_i32      1
-#define TCG_TARGET_HAS_add2_i32         0
-#define TCG_TARGET_HAS_sub2_i32         0
+#define TCG_TARGET_HAS_add2_i32         1
+#define TCG_TARGET_HAS_sub2_i32         1
 #define TCG_TARGET_HAS_mulu2_i32        0
 #define TCG_TARGET_HAS_muls2_i32        0
 
@@ -83,8 +83,8 @@ typedef enum {
 #define TCG_TARGET_HAS_nor_i64          0
 #define TCG_TARGET_HAS_deposit_i64      1
 #define TCG_TARGET_HAS_movcond_i64      1
-#define TCG_TARGET_HAS_add2_i64         0
-#define TCG_TARGET_HAS_sub2_i64         0
+#define TCG_TARGET_HAS_add2_i64         1
+#define TCG_TARGET_HAS_sub2_i64         1
 #define TCG_TARGET_HAS_mulu2_i64        0
 #define TCG_TARGET_HAS_muls2_i64        0
 
