diff --git a/qemu/aarch64.h b/qemu/aarch64.h index d4004c3d..12d044ac 100644 --- a/qemu/aarch64.h +++ b/qemu/aarch64.h @@ -3274,6 +3274,8 @@ #define helper_sdiv64 helper_sdiv64_aarch64 #define helper_simd_tbl helper_simd_tbl_aarch64 #define helper_sqrt_f16 helper_sqrt_f16_aarch64 +#define helper_sve_predtest helper_sve_predtest_aarch64 +#define helper_sve_predtest1 helper_sve_predtest1_aarch64 #define helper_udiv64 helper_udiv64_aarch64 #define helper_vfp_cmpd_a64 helper_vfp_cmpd_a64_aarch64 #define helper_vfp_cmped_a64 helper_vfp_cmped_a64_aarch64 diff --git a/qemu/aarch64eb.h b/qemu/aarch64eb.h index 84aac1d7..3adf32cb 100644 --- a/qemu/aarch64eb.h +++ b/qemu/aarch64eb.h @@ -3274,6 +3274,8 @@ #define helper_sdiv64 helper_sdiv64_aarch64eb #define helper_simd_tbl helper_simd_tbl_aarch64eb #define helper_sqrt_f16 helper_sqrt_f16_aarch64eb +#define helper_sve_predtest helper_sve_predtest_aarch64eb +#define helper_sve_predtest1 helper_sve_predtest1_aarch64eb #define helper_udiv64 helper_udiv64_aarch64eb #define helper_vfp_cmpd_a64 helper_vfp_cmpd_a64_aarch64eb #define helper_vfp_cmped_a64 helper_vfp_cmped_a64_aarch64eb diff --git a/qemu/header_gen.py b/qemu/header_gen.py index 3eb28a2a..64d5e344 100644 --- a/qemu/header_gen.py +++ b/qemu/header_gen.py @@ -3295,6 +3295,8 @@ aarch64_symbols = ( 'helper_sdiv64', 'helper_simd_tbl', 'helper_sqrt_f16', + 'helper_sve_predtest', + 'helper_sve_predtest1', 'helper_udiv64', 'helper_vfp_cmpd_a64', 'helper_vfp_cmped_a64', diff --git a/qemu/target/arm/Makefile.objs b/qemu/target/arm/Makefile.objs index 512218d4..6e70f205 100644 --- a/qemu/target/arm/Makefile.objs +++ b/qemu/target/arm/Makefile.objs @@ -14,4 +14,4 @@ target/arm/decode-sve.inc.c: $(SRC_PATH)/target/arm/sve.decode $(DECODETREE) "GEN", $(TARGET_DIR)$@) target/arm/translate-sve.o: target/arm/decode-sve.inc.c -obj-$(TARGET_AARCH64) += translate-sve.o +obj-$(TARGET_AARCH64) += translate-sve.o sve_helper.o diff --git a/qemu/target/arm/helper-sve.h b/qemu/target/arm/helper-sve.h new file mode 100644 index 00000000..b6e91539 --- /dev/null +++ b/qemu/target/arm/helper-sve.h @@ -0,0 +1,21 @@ +/* + * AArch64 SVE specific helper definitions + * + * Copyright (c) 2018 Linaro, Ltd + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +DEF_HELPER_FLAGS_2(sve_predtest1, TCG_CALL_NO_WG, i32, i64, i64) +DEF_HELPER_FLAGS_3(sve_predtest, TCG_CALL_NO_WG, i32, ptr, ptr, i32) diff --git a/qemu/target/arm/helper.h b/qemu/target/arm/helper.h index 590062fb..0971a0aa 100644 --- a/qemu/target/arm/helper.h +++ b/qemu/target/arm/helper.h @@ -612,4 +612,5 @@ DEF_HELPER_FLAGS_5(gvec_fcmlad, TCG_CALL_NO_RWG, #ifdef TARGET_AARCH64 #include "helper-a64.h" +#include "helper-sve.h" #endif diff --git a/qemu/target/arm/sve.decode b/qemu/target/arm/sve.decode index a2c4450e..a44ca2f5 100644 --- a/qemu/target/arm/sve.decode +++ b/qemu/target/arm/sve.decode @@ -56,6 +56,11 @@ ORR_zzz 00000100 01 1 ..... 001 100 ..... ..... @rd_rn_rm_e0 EOR_zzz 00000100 10 1 ..... 001 100 ..... ..... @rd_rn_rm_e0 BIC_zzz 00000100 11 1 ..... 001 100 ..... ..... @rd_rn_rm_e0 +### SVE Predicate Misc Group + +# SVE predicate test +PTEST 00100101 01 010000 11 pg:4 0 rn:4 0 0000 + ### SVE Memory - 32-bit Gather and Unsized Contiguous Group # SVE load predicate register diff --git a/qemu/target/arm/sve_helper.c b/qemu/target/arm/sve_helper.c new file mode 100644 index 00000000..1ebb67e1 --- /dev/null +++ b/qemu/target/arm/sve_helper.c @@ -0,0 +1,78 @@ +/* + * ARM SVE Operations + * + * Copyright (c) 2018 Linaro, Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "exec/exec-all.h" +#include "exec/cpu_ldst.h" +#include "exec/helper-proto.h" +#include "tcg/tcg-gvec-desc.h" + + +/* Return a value for NZCV as per the ARM PredTest pseudofunction. + * + * The return value has bit 31 set if N is set, bit 1 set if Z is clear, + * and bit 0 set if C is set. Compare the definitions of these variables + * within CPUARMState. + */ + +/* For no G bits set, NZCV = C. */ +#define PREDTEST_INIT 1 + +/* This is an iterative function, called for each Pd and Pg word + * moving forward. + */ +static uint32_t iter_predtest_fwd(uint64_t d, uint64_t g, uint32_t flags) +{ + if (likely(g)) { + /* Compute N from first D & G. + Use bit 2 to signal first G bit seen. */ + if (!(flags & 4)) { + flags |= ((d & (g & -g)) != 0) << 31; + flags |= 4; + } + + /* Accumulate Z from each D & G. */ + flags |= ((d & g) != 0) << 1; + + /* Compute C from last !(D & G). Replace previous. */ + flags = deposit32(flags, 0, 1, (d & pow2floor(g)) == 0); + } + return flags; +} + +/* The same for a single word predicate. */ +uint32_t HELPER(sve_predtest1)(uint64_t d, uint64_t g) +{ + return iter_predtest_fwd(d, g, PREDTEST_INIT); +} + +/* The same for a multi-word predicate. */ +uint32_t HELPER(sve_predtest)(void *vd, void *vg, uint32_t words) +{ + uint32_t flags = PREDTEST_INIT; + uint64_t *d = vd, *g = vg; + uintptr_t i = 0; + + do { + flags = iter_predtest_fwd(d[i], g[i], flags); + } while (++i < words); + + return flags; +} diff --git a/qemu/target/arm/translate-sve.c b/qemu/target/arm/translate-sve.c index 06ce4c2a..588e9167 100644 --- a/qemu/target/arm/translate-sve.c +++ b/qemu/target/arm/translate-sve.c @@ -86,6 +86,46 @@ static bool do_mov_z(DisasContext *s, int rd, int rn) return do_vector2_z(s, tcg_gen_gvec_mov, 0, rd, rn); } +/* Set the cpu flags as per a return from an SVE helper. */ +static void do_pred_flags(DisasContext *s, TCGv_i32 t) +{ + TCGContext *tcg_ctx = s->uc->tcg_ctx; + tcg_gen_mov_i32(tcg_ctx, tcg_ctx->cpu_NF, t); + tcg_gen_andi_i32(tcg_ctx, tcg_ctx->cpu_ZF, t, 2); + tcg_gen_andi_i32(tcg_ctx, tcg_ctx->cpu_CF, t, 1); + tcg_gen_movi_i32(tcg_ctx, tcg_ctx->cpu_VF, 0); +} + +/* Subroutines computing the ARM PredTest psuedofunction. */ +static void do_predtest1(DisasContext *s, TCGv_i64 d, TCGv_i64 g) +{ + TCGContext *tcg_ctx = s->uc->tcg_ctx; + TCGv_i32 t = tcg_temp_new_i32(tcg_ctx); + + gen_helper_sve_predtest1(tcg_ctx, t, d, g); + do_pred_flags(s, t); + tcg_temp_free_i32(tcg_ctx, t); +} + +static void do_predtest(DisasContext *s, int dofs, int gofs, int words) +{ + TCGContext *tcg_ctx = s->uc->tcg_ctx; + TCGv_ptr dptr = tcg_temp_new_ptr(tcg_ctx); + TCGv_ptr gptr = tcg_temp_new_ptr(tcg_ctx); + TCGv_i32 t; + + tcg_gen_addi_ptr(tcg_ctx, dptr, tcg_ctx->cpu_env, dofs); + tcg_gen_addi_ptr(tcg_ctx, gptr, tcg_ctx->cpu_env, gofs); + t = tcg_const_i32(tcg_ctx, words); + + gen_helper_sve_predtest(tcg_ctx, t, dptr, gptr, t); + tcg_temp_free_ptr(tcg_ctx, dptr); + tcg_temp_free_ptr(tcg_ctx, gptr); + + do_pred_flags(s, t); + tcg_temp_free_i32(tcg_ctx, t); +} + /* *** SVE Logical - Unpredicated Group */ @@ -114,6 +154,35 @@ static bool trans_BIC_zzz(DisasContext *s, arg_rrr_esz *a, uint32_t insn) return do_vector3_z(s, tcg_gen_gvec_andc, 0, a->rd, a->rn, a->rm); } +/* + *** SVE Predicate Misc Group + */ + +static bool trans_PTEST(DisasContext *s, arg_PTEST *a, uint32_t insn) +{ + if (sve_access_check(s)) { + TCGContext *tcg_ctx = s->uc->tcg_ctx; + int nofs = pred_full_reg_offset(s, a->rn); + int gofs = pred_full_reg_offset(s, a->pg); + int words = DIV_ROUND_UP(pred_full_reg_size(s), 8); + + if (words == 1) { + TCGv_i64 pn = tcg_temp_new_i64(tcg_ctx); + TCGv_i64 pg = tcg_temp_new_i64(tcg_ctx); + + tcg_gen_ld_i64(tcg_ctx, pn, tcg_ctx->cpu_env, nofs); + tcg_gen_ld_i64(tcg_ctx, pg, tcg_ctx->cpu_env, gofs); + do_predtest1(s, pn, pg); + + tcg_temp_free_i64(tcg_ctx, pn); + tcg_temp_free_i64(tcg_ctx, pg); + } else { + do_predtest(s, nofs, gofs, words); + } + } + return true; +} + /* *** SVE Memory - 32-bit Gather and Unsized Contiguous Group */