From fd7a67e4a7fa2a28b7a7bda5a292dcace427722e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 16 May 2019 15:29:02 -0400 Subject: [PATCH] tcg/aarch64: Implement tcg_out_dupm_vec The LD1R instruction does all the work. Note that the only useful addressing mode is a base register with no offset. Backports commit f23e5e15edfd49d5dd72cab2ed2d85ac354b2eeb from qemu --- qemu/tcg/aarch64/tcg-target.inc.c | 37 +++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/qemu/tcg/aarch64/tcg-target.inc.c b/qemu/tcg/aarch64/tcg-target.inc.c index b227c9ce..ef20d191 100644 --- a/qemu/tcg/aarch64/tcg-target.inc.c +++ b/qemu/tcg/aarch64/tcg-target.inc.c @@ -381,6 +381,9 @@ typedef enum { I3207_BLR = 0xd63f0000, I3207_RET = 0xd65f0000, + /* AdvSIMD load/store single structure. */ + I3303_LD1R = 0x0d40c000, + /* Load literal for loading the address at pc-relative offset */ I3305_LDR = 0x58000000, I3305_LDR_v64 = 0x5c000000, @@ -563,7 +566,14 @@ static inline uint32_t tcg_in32(TCGContext *s) #define tcg_out_insn(S, FMT, OP, ...) \ glue(tcg_out_insn_,FMT)(S, glue(glue(glue(I,FMT),_),OP), ## __VA_ARGS__) -static void tcg_out_insn_3305(TCGContext *s, AArch64Insn insn, int imm19, TCGReg rt) +static void tcg_out_insn_3303(TCGContext *s, AArch64Insn insn, bool q, + TCGReg rt, TCGReg rn, unsigned size) +{ + tcg_out32(s, insn | (rt & 0x1f) | (rn << 5) | (size << 10) | (q << 30)); +} + +static void tcg_out_insn_3305(TCGContext *s, AArch64Insn insn, + int imm19, TCGReg rt) { tcg_out32(s, insn | (imm19 & 0x7ffff) << 5 | rt); } @@ -822,7 +832,30 @@ static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece, static bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece, TCGReg r, TCGReg base, intptr_t offset) { - return false; + TCGReg temp = TCG_REG_TMP; + + if (offset < -0xffffff || offset > 0xffffff) { + tcg_out_movi(s, TCG_TYPE_PTR, temp, offset); + tcg_out_insn(s, 3502, ADD, 1, temp, temp, base); + base = temp; + } else { + AArch64Insn add_insn = I3401_ADDI; + + if (offset < 0) { + add_insn = I3401_SUBI; + offset = -offset; + } + if (offset & 0xfff000) { + tcg_out_insn_3401(s, add_insn, 1, temp, base, offset & 0xfff000); + base = temp; + } + if (offset & 0xfff) { + tcg_out_insn_3401(s, add_insn, 1, temp, base, offset & 0xfff); + base = temp; + } + } + tcg_out_insn(s, 3303, LD1R, type == TCG_TYPE_V128, r, base, vece); + return true; } static void tcg_out_movi(TCGContext *s, TCGType type, TCGReg rd,