Cleaning up the implementation of tcg_out_movi at the same time. Signed-off-by: Richard Henderson <r...@twiddle.net> --- tcg/aarch64/tcg-target.c | 49 +++++++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 21 deletions(-)
diff --git a/tcg/aarch64/tcg-target.c b/tcg/aarch64/tcg-target.c index c44f404..f9319ed 100644 --- a/tcg/aarch64/tcg-target.c +++ b/tcg/aarch64/tcg-target.c @@ -279,6 +279,11 @@ typedef enum { INSN_EOR = 0x4a000000, INSN_EON = 0x4a200000, + /* Move wide immediate instructions */ + INSN_MOVN = 0x12800000, + INSN_MOVZ = 0x52800000, + INSN_MOVK = 0x72800000, + /* Add/subtract immediate instructions */ INSN_ADDI = 0x11000000, INSN_ADDSI = 0x31000000, @@ -495,6 +500,16 @@ static inline void tcg_fmt_Rdnm_cond(TCGContext *s, AArch64Insn insn, | tcg_cond_to_aarch64[c] << 12); } +/* This function is used for the Move (wide immediate) instruction group. + Note that SHIFT is a full shift count, not the 2 bit HW field. */ +static inline void tcg_fmt_Rd_uimm(TCGContext *s, AArch64Insn insn, + TCGType sf, TCGReg rd, uint16_t half, + unsigned shift) +{ + assert((shift & ~0x30) == 0); + tcg_out32(s, insn | sf << 31 | shift << (21 - 4) | half << 5 | rd); +} + static inline void tcg_out_ldst_9(TCGContext *s, enum aarch64_ldst_op_data op_data, enum aarch64_ldst_op_type op_type, @@ -540,38 +555,30 @@ static inline void tcg_out_movr_sp(TCGContext *s, TCGType ext, tcg_fmt_Rdn_aimm(s, INSN_ADDI, ext, rd, rn, 0); } -static inline void tcg_out_movi_aux(TCGContext *s, - TCGReg rd, uint64_t value) +static void tcg_out_movi(TCGContext *s, TCGType type, TCGReg rd, + tcg_target_long value) { - uint32_t half, base, shift, movk = 0; - /* construct halfwords of the immediate with MOVZ/MOVK with LSL */ - /* using MOVZ 0x52800000 | extended reg.. */ - base = (value > 0xffffffff) ? 0xd2800000 : 0x52800000; + AArch64Insn insn; + + if (type == TCG_TYPE_I32) { + value = (uint32_t)value; + } + /* count trailing zeros in 16 bit steps, mapping 64 to 0. Emit the first MOVZ with the half-word immediate skipping the zeros, with a shift - (LSL) equal to this number. Then morph all next instructions into MOVKs. + (LSL) equal to this number. Then all next instructions use MOVKs. Zero the processed half-word in the value, continue until empty. We build the final result 16bits at a time with up to 4 instructions, but do not emit instructions for 16bit zero holes. */ + insn = INSN_MOVZ; do { - shift = ctz64(value) & (63 & -16); - half = (value >> shift) & 0xffff; - tcg_out32(s, base | movk | shift << 17 | half << 5 | rd); - movk = 0x20000000; /* morph next MOVZs into MOVKs */ + unsigned shift = ctz64(value) & (63 & -16); + tcg_fmt_Rd_uimm(s, insn, shift >= 32, rd, value >> shift, shift); value &= ~(0xffffUL << shift); + insn = INSN_MOVK; } while (value); } -static inline void tcg_out_movi(TCGContext *s, TCGType type, - TCGReg rd, tcg_target_long value) -{ - if (type == TCG_TYPE_I64) { - tcg_out_movi_aux(s, rd, value); - } else { - tcg_out_movi_aux(s, rd, value & 0xffffffff); - } -} - static inline void tcg_out_ldst_r(TCGContext *s, enum aarch64_ldst_op_data op_data, enum aarch64_ldst_op_type op_type, -- 1.8.3.1