Signed-off-by: Richard Henderson <r...@twiddle.net> --- tcg/aarch64/tcg-target.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++ tcg/aarch64/tcg-target.h | 8 ++--- 2 files changed, 82 insertions(+), 4 deletions(-)
diff --git a/tcg/aarch64/tcg-target.c b/tcg/aarch64/tcg-target.c index 894a1d9..bc1ca84 100644 --- a/tcg/aarch64/tcg-target.c +++ b/tcg/aarch64/tcg-target.c @@ -115,6 +115,7 @@ static inline void patch_reloc(uint8_t *code_ptr, int type, #define TCG_CT_CONST_AIMM 0x200 #define TCG_CT_CONST_LIMM 0x400 #define TCG_CT_CONST_ZERO 0x800 +#define TCG_CT_CONST_MONE 0x1000 /* parse target specific constraints */ static int target_parse_constraint(TCGArgConstraint *ct, @@ -148,6 +149,9 @@ static int target_parse_constraint(TCGArgConstraint *ct, case 'L': /* Valid for logical immediate. */ ct->ct |= TCG_CT_CONST_LIMM; break; + case 'M': /* minus one */ + ct->ct |= TCG_CT_CONST_MONE; + break; case 'Z': /* zero */ ct->ct |= TCG_CT_CONST_ZERO; break; @@ -205,6 +209,9 @@ static int tcg_target_const_match(tcg_target_long val, if ((ct & TCG_CT_CONST_ZERO) && val == 0) { return 1; } + if ((ct & TCG_CT_CONST_MONE) && val == -1) { + return 1; + } return 0; } @@ -284,6 +291,10 @@ typedef enum { INSN_SUB = 0x4b000000, INSN_SUBS = 0x6b000000, + /* Add/subtract with carry instructions */ + INSN_ADC = 0x1a000000, + INSN_SBC = 0x5a000000, + /* Data-processing (2 source) instructions */ INSN_LSLV = 0x1ac02000, INSN_LSRV = 0x1ac02400, @@ -869,6 +880,47 @@ static void tcg_out_addsubi(TCGContext *s, int ext, TCGReg rd, tcg_fmt_Rdn_aimm(s, insn, ext, rd, rn, aimm); } +static inline void tcg_out_addsub2(TCGContext *s, int ext, TCGReg rl, + TCGReg rh, TCGReg al, TCGReg ah, + tcg_target_long bl, tcg_target_long bh, + bool const_bl, bool const_bh, bool sub) +{ + TCGReg orig_rl = rl; + AArch64Insn insn; + + if (rl == ah || (!const_bh && rl == bh)) { + rl = TCG_REG_TMP; + } + + if (const_bl) { + insn = INSN_ADDSI; + if ((bl < 0) ^ sub) { + insn = INSN_SUBSI; + bl = -bl; + } + tcg_fmt_Rdn_aimm(s, insn, ext, rl, al, bl); + } else { + tcg_fmt_Rdnm(s, sub ? INSN_SUBS : INSN_ADDS, ext, rl, al, bl); + } + + insn = INSN_ADC; + if (const_bh) { + /* Note that the only two constants we support are 0 and -1, and + that SBC = rn + ~rm + c, so adc -1 is sbc 0, and vice-versa. */ + if ((bh != 0) ^ sub) { + insn = INSN_SBC; + } + bh = TCG_REG_XZR; + } else if (sub) { + insn = INSN_SBC; + } + tcg_fmt_Rdnm(s, insn, ext, rh, ah, bh); + + if (rl != orig_rl) { + tcg_out_movr(s, ext, orig_rl, rl); + } +} + static inline void tcg_out_nop(TCGContext *s) { tcg_out32(s, 0xd503201f); @@ -1524,6 +1576,27 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, tcg_out_dep(s, ext, a0, REG0(2), args[3], args[4]); break; + case INDEX_op_add2_i32: + a2 = (int32_t)args[4]; + c2 = false; + goto do_addsub2; + case INDEX_op_add2_i64: + a2 = args[4]; + c2 = false; + goto do_addsub2; + case INDEX_op_sub2_i32: + a2 = (int32_t)args[4]; + c2 = true; + goto do_addsub2; + case INDEX_op_sub2_i64: + a2 = args[4]; + c2 = true; + goto do_addsub2; + do_addsub2: + tcg_out_addsub2(s, ext, a0, a1, REG0(2), REG0(3), a2, + args[5], const_args[4], const_args[5], c2); + break; + case INDEX_op_mov_i64: case INDEX_op_mov_i32: case INDEX_op_movi_i64: @@ -1646,6 +1719,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", "rwA", "rwMZ" } }, + { INDEX_op_add2_i64, { "r", "r", "rZ", "rZ", "rA", "rMZ" } }, + { INDEX_op_sub2_i32, { "r", "r", "rZ", "rZ", "rwA", "rwMZ" } }, + { INDEX_op_sub2_i64, { "r", "r", "rZ", "rZ", "rA", "rMZ" } }, + { -1 }, }; diff --git a/tcg/aarch64/tcg-target.h b/tcg/aarch64/tcg-target.h index ac1c97d..f311954 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 #define TCG_TARGET_HAS_muluh_i32 0 @@ -85,8 +85,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 #define TCG_TARGET_HAS_muluh_i64 0 -- 1.8.3.1