Signed-off-by: Richard Henderson <r...@twiddle.net> --- tcg/aarch64/tcg-target.c | 110 ++++++++++++++++++++++++++++++++++++----------- tcg/aarch64/tcg-target.h | 8 ++-- 2 files changed, 90 insertions(+), 28 deletions(-)
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 -- 1.8.3.1