/* * 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; } #define LOGICAL_PPPP(NAME, FUNC) \ void HELPER(NAME)(void *vd, void *vn, void *vm, void *vg, uint32_t desc) \ { \ uintptr_t opr_sz = simd_oprsz(desc); \ uint64_t *d = vd, *n = vn, *m = vm, *g = vg; \ uintptr_t i; \ for (i = 0; i < opr_sz / 8; ++i) { \ d[i] = FUNC(n[i], m[i], g[i]); \ } \ } #define DO_AND(N, M, G) (((N) & (M)) & (G)) #define DO_BIC(N, M, G) (((N) & ~(M)) & (G)) #define DO_EOR(N, M, G) (((N) ^ (M)) & (G)) #define DO_ORR(N, M, G) (((N) | (M)) & (G)) #define DO_ORN(N, M, G) (((N) | ~(M)) & (G)) #define DO_NOR(N, M, G) (~((N) | (M)) & (G)) #define DO_NAND(N, M, G) (~((N) & (M)) & (G)) #define DO_SEL(N, M, G) (((N) & (G)) | ((M) & ~(G))) LOGICAL_PPPP(sve_and_pppp, DO_AND) LOGICAL_PPPP(sve_bic_pppp, DO_BIC) LOGICAL_PPPP(sve_eor_pppp, DO_EOR) LOGICAL_PPPP(sve_sel_pppp, DO_SEL) LOGICAL_PPPP(sve_orr_pppp, DO_ORR) LOGICAL_PPPP(sve_orn_pppp, DO_ORN) LOGICAL_PPPP(sve_nor_pppp, DO_NOR) LOGICAL_PPPP(sve_nand_pppp, DO_NAND) #undef DO_AND #undef DO_BIC #undef DO_EOR #undef DO_ORR #undef DO_ORN #undef DO_NOR #undef DO_NAND #undef DO_SEL #undef LOGICAL_PPPP