2021-02-08 08:45:57 +03:00
|
|
|
/*
|
2023-03-07 05:58:18 +03:00
|
|
|
* Copyright(c) 2019-2023 Qualcomm Innovation Center, Inc. All Rights Reserved.
|
2021-02-08 08:45:57 +03:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program 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 General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "qemu/osdep.h"
|
2021-07-17 13:30:17 +03:00
|
|
|
#include "qemu/log.h"
|
|
|
|
#include "exec/exec-all.h"
|
2021-07-13 18:51:33 +03:00
|
|
|
#include "exec/cpu_ldst.h"
|
2021-02-08 08:45:57 +03:00
|
|
|
#include "exec/helper-proto.h"
|
|
|
|
#include "fpu/softfloat.h"
|
|
|
|
#include "cpu.h"
|
|
|
|
#include "internal.h"
|
|
|
|
#include "macros.h"
|
|
|
|
#include "arch.h"
|
|
|
|
#include "hex_arch_types.h"
|
|
|
|
#include "fma_emu.h"
|
2021-09-30 19:07:00 +03:00
|
|
|
#include "mmvec/mmvec.h"
|
|
|
|
#include "mmvec/macros.h"
|
2022-09-23 20:38:24 +03:00
|
|
|
#include "op_helper.h"
|
Hexagon (target/hexagon) Reduce manipulation of slot_cancelled
We only need to track slot for predicated stores and predicated HVX
instructions.
Add arguments to the probe helper functions to indicate if the slot
is predicated.
Here is a simple example of the differences in the TCG code generated:
IN:
0x00400094: 0xf900c102 { if (P0) R2 = and(R0,R1) }
BEFORE
---- 00400094
mov_i32 slot_cancelled,$0x0
mov_i32 new_r2,r2
and_i32 tmp0,p0,$0x1
brcond_i32 tmp0,$0x0,eq,$L1
and_i32 tmp0,r0,r1
mov_i32 new_r2,tmp0
br $L2
set_label $L1
or_i32 slot_cancelled,slot_cancelled,$0x8
set_label $L2
mov_i32 r2,new_r2
AFTER
---- 00400094
mov_i32 new_r2,r2
and_i32 tmp0,p0,$0x1
brcond_i32 tmp0,$0x0,eq,$L1
and_i32 tmp0,r0,r1
mov_i32 new_r2,tmp0
br $L2
set_label $L1
set_label $L2
mov_i32 r2,new_r2
Signed-off-by: Taylor Simpson <tsimpson@quicinc.com>
Reviewed-by: Anton Johansson <anjo@rev.ng>
Message-Id: <20230307025828.1612809-14-tsimpson@quicinc.com>
2023-03-07 05:58:27 +03:00
|
|
|
#include "translate.h"
|
2021-02-08 08:45:57 +03:00
|
|
|
|
|
|
|
#define SF_BIAS 127
|
|
|
|
#define SF_MANTBITS 23
|
|
|
|
|
|
|
|
/* Exceptions processing helpers */
|
2024-05-03 19:53:15 +03:00
|
|
|
G_NORETURN void hexagon_raise_exception_err(CPUHexagonState *env,
|
|
|
|
uint32_t exception,
|
|
|
|
uintptr_t pc)
|
2021-02-08 08:45:57 +03:00
|
|
|
{
|
2021-04-09 04:07:32 +03:00
|
|
|
CPUState *cs = env_cpu(env);
|
2021-02-08 08:45:57 +03:00
|
|
|
qemu_log_mask(CPU_LOG_INT, "%s: %d\n", __func__, exception);
|
|
|
|
cs->exception_index = exception;
|
|
|
|
cpu_loop_exit_restore(cs, pc);
|
|
|
|
}
|
|
|
|
|
2022-04-20 16:26:02 +03:00
|
|
|
G_NORETURN void HELPER(raise_exception)(CPUHexagonState *env, uint32_t excp)
|
2021-02-08 08:45:57 +03:00
|
|
|
{
|
2024-05-03 19:53:15 +03:00
|
|
|
hexagon_raise_exception_err(env, excp, 0);
|
2021-02-08 08:45:57 +03:00
|
|
|
}
|
|
|
|
|
2022-09-23 20:38:24 +03:00
|
|
|
void log_store32(CPUHexagonState *env, target_ulong addr,
|
|
|
|
target_ulong val, int width, int slot)
|
2021-02-08 08:45:57 +03:00
|
|
|
{
|
|
|
|
HEX_DEBUG_LOG("log_store%d(0x" TARGET_FMT_lx
|
|
|
|
", %" PRId32 " [0x08%" PRIx32 "])\n",
|
|
|
|
width, addr, val, val);
|
|
|
|
env->mem_log_stores[slot].va = addr;
|
|
|
|
env->mem_log_stores[slot].width = width;
|
|
|
|
env->mem_log_stores[slot].data32 = val;
|
|
|
|
}
|
|
|
|
|
2022-09-23 20:38:24 +03:00
|
|
|
void log_store64(CPUHexagonState *env, target_ulong addr,
|
|
|
|
int64_t val, int width, int slot)
|
2021-02-08 08:45:57 +03:00
|
|
|
{
|
|
|
|
HEX_DEBUG_LOG("log_store%d(0x" TARGET_FMT_lx
|
|
|
|
", %" PRId64 " [0x016%" PRIx64 "])\n",
|
|
|
|
width, addr, val, val);
|
|
|
|
env->mem_log_stores[slot].va = addr;
|
|
|
|
env->mem_log_stores[slot].width = width;
|
|
|
|
env->mem_log_stores[slot].data64 = val;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Handy place to set a breakpoint */
|
|
|
|
void HELPER(debug_start_packet)(CPUHexagonState *env)
|
|
|
|
{
|
|
|
|
HEX_DEBUG_LOG("Start packet: pc = 0x" TARGET_FMT_lx "\n",
|
|
|
|
env->gpr[HEX_REG_PC]);
|
|
|
|
|
|
|
|
for (int i = 0; i < TOTAL_PER_THREAD_REGS; i++) {
|
|
|
|
env->reg_written[i] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Checks for bookkeeping errors between disassembly context and runtime */
|
|
|
|
void HELPER(debug_check_store_width)(CPUHexagonState *env, int slot, int check)
|
|
|
|
{
|
|
|
|
if (env->mem_log_stores[slot].width != check) {
|
|
|
|
HEX_DEBUG_LOG("ERROR: %d != %d\n",
|
|
|
|
env->mem_log_stores[slot].width, check);
|
|
|
|
g_assert_not_reached();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
target/hexagon: move GETPC() calls to top level helpers
As docs/devel/loads-stores.rst states:
``GETPC()`` should be used with great care: calling
it in other functions that are *not* the top level
``HELPER(foo)`` will cause unexpected behavior. Instead, the
value of ``GETPC()`` should be read from the helper and passed
if needed to the functions that the helper calls.
Let's fix the GETPC() usage in Hexagon, making sure it's always called
from top level helpers and passed down to the places where it's
needed. There are a few snippets where that is not currently the case:
- probe_store(), which is only called from two helpers, so it's easy to
move GETPC() up.
- mem_load*() functions, which are also called directly from helpers,
but through the MEM_LOAD*() set of macros. Note that this are only
used when compiling with --disable-hexagon-idef-parser.
In this case, we also take this opportunity to simplify the code,
unifying the mem_load*() functions.
- HELPER(probe_hvx_stores), when called from another helper, ends up
using its own GETPC() expansion instead of the top level caller.
Signed-off-by: Matheus Tavares Bernardino <quic_mathbern@quicinc.com>
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Message-Id: <2c74c3696946edba7cc5b2942cf296a5af532052.1689070412.git.quic_mathbern@quicinc.com>-ne
Reviewed-by: Brian Cain <bcain@quicinc.com>
Signed-off-by: Brian Cain <bcain@quicinc.com>
Message-Id: <20231008220945.983643-2-bcain@quicinc.com>
2023-10-09 01:09:43 +03:00
|
|
|
static void commit_store(CPUHexagonState *env, int slot_num, uintptr_t ra)
|
2021-02-08 08:45:57 +03:00
|
|
|
{
|
2021-07-13 18:51:33 +03:00
|
|
|
uint8_t width = env->mem_log_stores[slot_num].width;
|
|
|
|
target_ulong va = env->mem_log_stores[slot_num].va;
|
|
|
|
|
|
|
|
switch (width) {
|
2021-02-08 08:45:57 +03:00
|
|
|
case 1:
|
2021-07-13 18:51:33 +03:00
|
|
|
cpu_stb_data_ra(env, va, env->mem_log_stores[slot_num].data32, ra);
|
2021-02-08 08:45:57 +03:00
|
|
|
break;
|
|
|
|
case 2:
|
2021-07-13 18:51:33 +03:00
|
|
|
cpu_stw_data_ra(env, va, env->mem_log_stores[slot_num].data32, ra);
|
2021-02-08 08:45:57 +03:00
|
|
|
break;
|
|
|
|
case 4:
|
2021-07-13 18:51:33 +03:00
|
|
|
cpu_stl_data_ra(env, va, env->mem_log_stores[slot_num].data32, ra);
|
2021-02-08 08:45:57 +03:00
|
|
|
break;
|
|
|
|
case 8:
|
2021-07-13 18:51:33 +03:00
|
|
|
cpu_stq_data_ra(env, va, env->mem_log_stores[slot_num].data64, ra);
|
2021-02-08 08:45:57 +03:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
g_assert_not_reached();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
target/hexagon: move GETPC() calls to top level helpers
As docs/devel/loads-stores.rst states:
``GETPC()`` should be used with great care: calling
it in other functions that are *not* the top level
``HELPER(foo)`` will cause unexpected behavior. Instead, the
value of ``GETPC()`` should be read from the helper and passed
if needed to the functions that the helper calls.
Let's fix the GETPC() usage in Hexagon, making sure it's always called
from top level helpers and passed down to the places where it's
needed. There are a few snippets where that is not currently the case:
- probe_store(), which is only called from two helpers, so it's easy to
move GETPC() up.
- mem_load*() functions, which are also called directly from helpers,
but through the MEM_LOAD*() set of macros. Note that this are only
used when compiling with --disable-hexagon-idef-parser.
In this case, we also take this opportunity to simplify the code,
unifying the mem_load*() functions.
- HELPER(probe_hvx_stores), when called from another helper, ends up
using its own GETPC() expansion instead of the top level caller.
Signed-off-by: Matheus Tavares Bernardino <quic_mathbern@quicinc.com>
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Message-Id: <2c74c3696946edba7cc5b2942cf296a5af532052.1689070412.git.quic_mathbern@quicinc.com>-ne
Reviewed-by: Brian Cain <bcain@quicinc.com>
Signed-off-by: Brian Cain <bcain@quicinc.com>
Message-Id: <20231008220945.983643-2-bcain@quicinc.com>
2023-10-09 01:09:43 +03:00
|
|
|
void HELPER(commit_store)(CPUHexagonState *env, int slot_num)
|
|
|
|
{
|
|
|
|
uintptr_t ra = GETPC();
|
|
|
|
commit_store(env, slot_num, ra);
|
|
|
|
}
|
|
|
|
|
2021-09-30 19:07:00 +03:00
|
|
|
void HELPER(gather_store)(CPUHexagonState *env, uint32_t addr, int slot)
|
|
|
|
{
|
|
|
|
mem_gather_store(env, addr, slot);
|
|
|
|
}
|
|
|
|
|
|
|
|
void HELPER(commit_hvx_stores)(CPUHexagonState *env)
|
|
|
|
{
|
|
|
|
uintptr_t ra = GETPC();
|
|
|
|
|
|
|
|
/* Normal (possibly masked) vector store */
|
2023-10-09 01:09:44 +03:00
|
|
|
for (int i = 0; i < VSTORES_MAX; i++) {
|
2021-09-30 19:07:00 +03:00
|
|
|
if (env->vstore_pending[i]) {
|
|
|
|
env->vstore_pending[i] = 0;
|
|
|
|
target_ulong va = env->vstore[i].va;
|
|
|
|
int size = env->vstore[i].size;
|
|
|
|
for (int j = 0; j < size; j++) {
|
|
|
|
if (test_bit(j, env->vstore[i].mask)) {
|
|
|
|
cpu_stb_data_ra(env, va + j, env->vstore[i].data.ub[j], ra);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Scatter store */
|
|
|
|
if (env->vtcm_pending) {
|
|
|
|
env->vtcm_pending = false;
|
|
|
|
if (env->vtcm_log.op) {
|
|
|
|
/* Need to perform the scatter read/modify/write at commit time */
|
|
|
|
if (env->vtcm_log.op_size == 2) {
|
|
|
|
SCATTER_OP_WRITE_TO_MEM(uint16_t);
|
|
|
|
} else if (env->vtcm_log.op_size == 4) {
|
|
|
|
/* Word Scatter += */
|
|
|
|
SCATTER_OP_WRITE_TO_MEM(uint32_t);
|
|
|
|
} else {
|
|
|
|
g_assert_not_reached();
|
|
|
|
}
|
|
|
|
} else {
|
2023-10-09 01:09:44 +03:00
|
|
|
for (int i = 0; i < sizeof(MMVector); i++) {
|
2021-09-30 19:07:00 +03:00
|
|
|
if (test_bit(i, env->vtcm_log.mask)) {
|
|
|
|
cpu_stb_data_ra(env, env->vtcm_log.va[i],
|
|
|
|
env->vtcm_log.data.ub[i], ra);
|
|
|
|
clear_bit(i, env->vtcm_log.mask);
|
|
|
|
env->vtcm_log.data.ub[i] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-08 08:45:57 +03:00
|
|
|
static void print_store(CPUHexagonState *env, int slot)
|
|
|
|
{
|
|
|
|
if (!(env->slot_cancelled & (1 << slot))) {
|
|
|
|
uint8_t width = env->mem_log_stores[slot].width;
|
|
|
|
if (width == 1) {
|
|
|
|
uint32_t data = env->mem_log_stores[slot].data32 & 0xff;
|
|
|
|
HEX_DEBUG_LOG("\tmemb[0x" TARGET_FMT_lx "] = %" PRId32
|
|
|
|
" (0x%02" PRIx32 ")\n",
|
|
|
|
env->mem_log_stores[slot].va, data, data);
|
|
|
|
} else if (width == 2) {
|
|
|
|
uint32_t data = env->mem_log_stores[slot].data32 & 0xffff;
|
|
|
|
HEX_DEBUG_LOG("\tmemh[0x" TARGET_FMT_lx "] = %" PRId32
|
|
|
|
" (0x%04" PRIx32 ")\n",
|
|
|
|
env->mem_log_stores[slot].va, data, data);
|
|
|
|
} else if (width == 4) {
|
|
|
|
uint32_t data = env->mem_log_stores[slot].data32;
|
|
|
|
HEX_DEBUG_LOG("\tmemw[0x" TARGET_FMT_lx "] = %" PRId32
|
|
|
|
" (0x%08" PRIx32 ")\n",
|
|
|
|
env->mem_log_stores[slot].va, data, data);
|
|
|
|
} else if (width == 8) {
|
|
|
|
HEX_DEBUG_LOG("\tmemd[0x" TARGET_FMT_lx "] = %" PRId64
|
|
|
|
" (0x%016" PRIx64 ")\n",
|
|
|
|
env->mem_log_stores[slot].va,
|
|
|
|
env->mem_log_stores[slot].data64,
|
|
|
|
env->mem_log_stores[slot].data64);
|
|
|
|
} else {
|
|
|
|
HEX_DEBUG_LOG("\tBad store width %d\n", width);
|
|
|
|
g_assert_not_reached();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This function is a handy place to set a breakpoint */
|
2023-04-28 02:00:12 +03:00
|
|
|
void HELPER(debug_commit_end)(CPUHexagonState *env, uint32_t this_PC,
|
2023-04-28 02:00:10 +03:00
|
|
|
int pred_written, int has_st0, int has_st1)
|
2021-02-08 08:45:57 +03:00
|
|
|
{
|
|
|
|
bool reg_printed = false;
|
|
|
|
bool pred_printed = false;
|
|
|
|
int i;
|
|
|
|
|
2023-04-28 02:00:12 +03:00
|
|
|
HEX_DEBUG_LOG("Packet committed: pc = 0x" TARGET_FMT_lx "\n", this_PC);
|
2021-02-08 08:45:57 +03:00
|
|
|
HEX_DEBUG_LOG("slot_cancelled = %d\n", env->slot_cancelled);
|
|
|
|
|
|
|
|
for (i = 0; i < TOTAL_PER_THREAD_REGS; i++) {
|
|
|
|
if (env->reg_written[i]) {
|
|
|
|
if (!reg_printed) {
|
|
|
|
HEX_DEBUG_LOG("Regs written\n");
|
|
|
|
reg_printed = true;
|
|
|
|
}
|
|
|
|
HEX_DEBUG_LOG("\tr%d = " TARGET_FMT_ld " (0x" TARGET_FMT_lx ")\n",
|
Hexagon (target/hexagon) Short-circuit packet register writes
In certain cases, we can avoid the overhead of writing to hex_new_value
and write directly to hex_gpr. We add need_commit field to DisasContext
indicating if the end-of-packet commit is needed. If it is not needed,
get_result_gpr() and get_result_gpr_pair() can return hex_gpr.
We pass the ctx->need_commit to helpers when needed.
Finally, we can early-exit from gen_reg_writes during packet commit.
There are a few instructions whose semantics write to the result before
reading all the inputs. Therefore, the idef-parser generated code is
incompatible with short-circuit. We tell idef-parser to skip them.
For debugging purposes, we add a cpu property to turn off short-circuit.
When the short-circuit property is false, we skip the analysis and force
the end-of-packet commit.
Here's a simple example of the TCG generated for
0x004000b4: 0x7800c020 { R0 = #0x1 }
BEFORE:
---- 004000b4
movi_i32 new_r0,$0x1
mov_i32 r0,new_r0
AFTER:
---- 004000b4
movi_i32 r0,$0x1
This patch reintroduces a use of check_for_attrib, so we remove the
G_GNUC_UNUSED added earlier in this series.
Signed-off-by: Taylor Simpson <tsimpson@quicinc.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Brian Cain <bcain@quicinc.com>
Message-Id: <20230427230012.3800327-12-tsimpson@quicinc.com>
2023-04-28 02:00:02 +03:00
|
|
|
i, env->gpr[i], env->gpr[i]);
|
2021-02-08 08:45:57 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < NUM_PREGS; i++) {
|
2023-04-28 02:00:10 +03:00
|
|
|
if (pred_written & (1 << i)) {
|
2021-02-08 08:45:57 +03:00
|
|
|
if (!pred_printed) {
|
|
|
|
HEX_DEBUG_LOG("Predicates written\n");
|
|
|
|
pred_printed = true;
|
|
|
|
}
|
|
|
|
HEX_DEBUG_LOG("\tp%d = 0x" TARGET_FMT_lx "\n",
|
2023-04-28 02:00:09 +03:00
|
|
|
i, env->pred[i]);
|
2021-02-08 08:45:57 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (has_st0 || has_st1) {
|
|
|
|
HEX_DEBUG_LOG("Stores\n");
|
|
|
|
if (has_st0) {
|
|
|
|
print_store(env, 0);
|
|
|
|
}
|
|
|
|
if (has_st1) {
|
|
|
|
print_store(env, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-08 19:29:01 +03:00
|
|
|
HEX_DEBUG_LOG("Next PC = " TARGET_FMT_lx "\n", env->gpr[HEX_REG_PC]);
|
2021-02-08 08:45:57 +03:00
|
|
|
HEX_DEBUG_LOG("Exec counters: pkt = " TARGET_FMT_lx
|
|
|
|
", insn = " TARGET_FMT_lx
|
2021-09-30 19:07:00 +03:00
|
|
|
", hvx = " TARGET_FMT_lx "\n",
|
2021-02-08 08:45:57 +03:00
|
|
|
env->gpr[HEX_REG_QEMU_PKT_CNT],
|
2021-09-30 19:07:00 +03:00
|
|
|
env->gpr[HEX_REG_QEMU_INSN_CNT],
|
|
|
|
env->gpr[HEX_REG_QEMU_HVX_CNT]);
|
2021-02-08 08:45:57 +03:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t HELPER(fcircadd)(int32_t RxV, int32_t offset, int32_t M, int32_t CS)
|
|
|
|
{
|
2022-02-10 05:15:45 +03:00
|
|
|
uint32_t K_const = extract32(M, 24, 4);
|
|
|
|
uint32_t length = extract32(M, 0, 17);
|
2021-02-08 08:45:57 +03:00
|
|
|
uint32_t new_ptr = RxV + offset;
|
2021-04-09 04:07:50 +03:00
|
|
|
uint32_t start_addr;
|
|
|
|
uint32_t end_addr;
|
2021-02-08 08:45:57 +03:00
|
|
|
|
|
|
|
if (K_const == 0 && length >= 4) {
|
2021-04-09 04:07:50 +03:00
|
|
|
start_addr = CS;
|
|
|
|
end_addr = start_addr + length;
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* Versions v3 and earlier used the K value to specify a power-of-2 size
|
|
|
|
* 2^(K+2) that is greater than the buffer length
|
|
|
|
*/
|
|
|
|
int32_t mask = (1 << (K_const + 2)) - 1;
|
|
|
|
start_addr = RxV & (~mask);
|
|
|
|
end_addr = start_addr | length;
|
2021-02-08 08:45:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (new_ptr >= end_addr) {
|
|
|
|
new_ptr -= length;
|
|
|
|
} else if (new_ptr < start_addr) {
|
|
|
|
new_ptr += length;
|
|
|
|
}
|
|
|
|
|
|
|
|
return new_ptr;
|
|
|
|
}
|
|
|
|
|
2021-04-09 04:07:51 +03:00
|
|
|
uint32_t HELPER(fbrev)(uint32_t addr)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Bit reverse the low 16 bits of the address
|
|
|
|
*/
|
|
|
|
return deposit32(addr, 0, 16, revbit16(addr));
|
|
|
|
}
|
|
|
|
|
2021-04-09 04:07:45 +03:00
|
|
|
static float32 build_float32(uint8_t sign, uint32_t exp, uint32_t mant)
|
|
|
|
{
|
|
|
|
return make_float32(
|
|
|
|
((sign & 1) << 31) |
|
|
|
|
((exp & 0xff) << SF_MANTBITS) |
|
|
|
|
(mant & ((1 << SF_MANTBITS) - 1)));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* sfrecipa, sfinvsqrta have two 32-bit results
|
|
|
|
* r0,p0=sfrecipa(r1,r2)
|
|
|
|
* r0,p0=sfinvsqrta(r1)
|
|
|
|
*
|
|
|
|
* Since helpers can only return a single value, we pack the two results
|
|
|
|
* into a 64-bit value.
|
|
|
|
*/
|
|
|
|
uint64_t HELPER(sfrecipa)(CPUHexagonState *env, float32 RsV, float32 RtV)
|
|
|
|
{
|
|
|
|
int32_t PeV = 0;
|
|
|
|
float32 RdV;
|
|
|
|
int idx;
|
|
|
|
int adjust;
|
|
|
|
int mant;
|
|
|
|
int exp;
|
|
|
|
|
|
|
|
arch_fpop_start(env);
|
|
|
|
if (arch_sf_recip_common(&RsV, &RtV, &RdV, &adjust, &env->fp_status)) {
|
|
|
|
PeV = adjust;
|
|
|
|
idx = (RtV >> 16) & 0x7f;
|
|
|
|
mant = (recip_lookup_table[idx] << 15) | 1;
|
|
|
|
exp = SF_BIAS - (float32_getexp(RtV) - SF_BIAS) - 1;
|
|
|
|
RdV = build_float32(extract32(RtV, 31, 1), exp, mant);
|
|
|
|
}
|
|
|
|
arch_fpop_end(env);
|
|
|
|
return ((uint64_t)RdV << 32) | PeV;
|
|
|
|
}
|
|
|
|
|
2021-04-09 04:07:46 +03:00
|
|
|
uint64_t HELPER(sfinvsqrta)(CPUHexagonState *env, float32 RsV)
|
|
|
|
{
|
|
|
|
int PeV = 0;
|
|
|
|
float32 RdV;
|
|
|
|
int idx;
|
|
|
|
int adjust;
|
|
|
|
int mant;
|
|
|
|
int exp;
|
|
|
|
|
|
|
|
arch_fpop_start(env);
|
|
|
|
if (arch_sf_invsqrt_common(&RsV, &RdV, &adjust, &env->fp_status)) {
|
|
|
|
PeV = adjust;
|
|
|
|
idx = (RsV >> 17) & 0x7f;
|
|
|
|
mant = (invsqrt_lookup_table[idx] << 15);
|
|
|
|
exp = SF_BIAS - ((float32_getexp(RsV) - SF_BIAS) >> 1) - 1;
|
|
|
|
RdV = build_float32(extract32(RsV, 31, 1), exp, mant);
|
|
|
|
}
|
|
|
|
arch_fpop_end(env);
|
|
|
|
return ((uint64_t)RdV << 32) | PeV;
|
|
|
|
}
|
|
|
|
|
2021-04-09 04:07:47 +03:00
|
|
|
int64_t HELPER(vacsh_val)(CPUHexagonState *env,
|
Hexagon (target/hexagon) Short-circuit packet register writes
In certain cases, we can avoid the overhead of writing to hex_new_value
and write directly to hex_gpr. We add need_commit field to DisasContext
indicating if the end-of-packet commit is needed. If it is not needed,
get_result_gpr() and get_result_gpr_pair() can return hex_gpr.
We pass the ctx->need_commit to helpers when needed.
Finally, we can early-exit from gen_reg_writes during packet commit.
There are a few instructions whose semantics write to the result before
reading all the inputs. Therefore, the idef-parser generated code is
incompatible with short-circuit. We tell idef-parser to skip them.
For debugging purposes, we add a cpu property to turn off short-circuit.
When the short-circuit property is false, we skip the analysis and force
the end-of-packet commit.
Here's a simple example of the TCG generated for
0x004000b4: 0x7800c020 { R0 = #0x1 }
BEFORE:
---- 004000b4
movi_i32 new_r0,$0x1
mov_i32 r0,new_r0
AFTER:
---- 004000b4
movi_i32 r0,$0x1
This patch reintroduces a use of check_for_attrib, so we remove the
G_GNUC_UNUSED added earlier in this series.
Signed-off-by: Taylor Simpson <tsimpson@quicinc.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Brian Cain <bcain@quicinc.com>
Message-Id: <20230427230012.3800327-12-tsimpson@quicinc.com>
2023-04-28 02:00:02 +03:00
|
|
|
int64_t RxxV, int64_t RssV, int64_t RttV,
|
|
|
|
uint32_t pkt_need_commit)
|
2021-04-09 04:07:47 +03:00
|
|
|
{
|
|
|
|
for (int i = 0; i < 4; i++) {
|
|
|
|
int xv = sextract64(RxxV, i * 16, 16);
|
|
|
|
int sv = sextract64(RssV, i * 16, 16);
|
|
|
|
int tv = sextract64(RttV, i * 16, 16);
|
|
|
|
int max;
|
|
|
|
xv = xv + tv;
|
|
|
|
sv = sv - tv;
|
|
|
|
max = xv > sv ? xv : sv;
|
|
|
|
/* Note that fSATH can set the OVF bit in usr */
|
|
|
|
RxxV = deposit64(RxxV, i * 16, 16, fSATH(max));
|
|
|
|
}
|
|
|
|
return RxxV;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t HELPER(vacsh_pred)(CPUHexagonState *env,
|
|
|
|
int64_t RxxV, int64_t RssV, int64_t RttV)
|
|
|
|
{
|
|
|
|
int32_t PeV = 0;
|
|
|
|
for (int i = 0; i < 4; i++) {
|
|
|
|
int xv = sextract64(RxxV, i * 16, 16);
|
|
|
|
int sv = sextract64(RssV, i * 16, 16);
|
|
|
|
int tv = sextract64(RttV, i * 16, 16);
|
|
|
|
xv = xv + tv;
|
|
|
|
sv = sv - tv;
|
|
|
|
PeV = deposit32(PeV, i * 2, 1, (xv > sv));
|
|
|
|
PeV = deposit32(PeV, i * 2 + 1, 1, (xv > sv));
|
|
|
|
}
|
|
|
|
return PeV;
|
|
|
|
}
|
|
|
|
|
2023-04-28 01:59:58 +03:00
|
|
|
int64_t HELPER(cabacdecbin_val)(int64_t RssV, int64_t RttV)
|
|
|
|
{
|
|
|
|
int64_t RddV = 0;
|
|
|
|
size4u_t state;
|
|
|
|
size4u_t valMPS;
|
|
|
|
size4u_t bitpos;
|
|
|
|
size4u_t range;
|
|
|
|
size4u_t offset;
|
|
|
|
size4u_t rLPS;
|
|
|
|
size4u_t rMPS;
|
|
|
|
|
|
|
|
state = fEXTRACTU_RANGE(fGETWORD(1, RttV), 5, 0);
|
|
|
|
valMPS = fEXTRACTU_RANGE(fGETWORD(1, RttV), 8, 8);
|
|
|
|
bitpos = fEXTRACTU_RANGE(fGETWORD(0, RttV), 4, 0);
|
|
|
|
range = fGETWORD(0, RssV);
|
|
|
|
offset = fGETWORD(1, RssV);
|
|
|
|
|
|
|
|
/* calculate rLPS */
|
|
|
|
range <<= bitpos;
|
|
|
|
offset <<= bitpos;
|
|
|
|
rLPS = rLPS_table_64x4[state][(range >> 29) & 3];
|
|
|
|
rLPS = rLPS << 23; /* left aligned */
|
|
|
|
|
|
|
|
/* calculate rMPS */
|
|
|
|
rMPS = (range & 0xff800000) - rLPS;
|
|
|
|
|
|
|
|
/* most probable region */
|
|
|
|
if (offset < rMPS) {
|
|
|
|
RddV = AC_next_state_MPS_64[state];
|
|
|
|
fINSERT_RANGE(RddV, 8, 8, valMPS);
|
|
|
|
fINSERT_RANGE(RddV, 31, 23, (rMPS >> 23));
|
|
|
|
fSETWORD(1, RddV, offset);
|
|
|
|
}
|
|
|
|
/* least probable region */
|
|
|
|
else {
|
|
|
|
RddV = AC_next_state_LPS_64[state];
|
|
|
|
fINSERT_RANGE(RddV, 8, 8, ((!state) ? (1 - valMPS) : (valMPS)));
|
|
|
|
fINSERT_RANGE(RddV, 31, 23, (rLPS >> 23));
|
|
|
|
fSETWORD(1, RddV, (offset - rMPS));
|
|
|
|
}
|
|
|
|
return RddV;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t HELPER(cabacdecbin_pred)(int64_t RssV, int64_t RttV)
|
|
|
|
{
|
|
|
|
int32_t p0 = 0;
|
|
|
|
size4u_t state;
|
|
|
|
size4u_t valMPS;
|
|
|
|
size4u_t bitpos;
|
|
|
|
size4u_t range;
|
|
|
|
size4u_t offset;
|
|
|
|
size4u_t rLPS;
|
|
|
|
size4u_t rMPS;
|
|
|
|
|
|
|
|
state = fEXTRACTU_RANGE(fGETWORD(1, RttV), 5, 0);
|
|
|
|
valMPS = fEXTRACTU_RANGE(fGETWORD(1, RttV), 8, 8);
|
|
|
|
bitpos = fEXTRACTU_RANGE(fGETWORD(0, RttV), 4, 0);
|
|
|
|
range = fGETWORD(0, RssV);
|
|
|
|
offset = fGETWORD(1, RssV);
|
|
|
|
|
|
|
|
/* calculate rLPS */
|
|
|
|
range <<= bitpos;
|
|
|
|
offset <<= bitpos;
|
|
|
|
rLPS = rLPS_table_64x4[state][(range >> 29) & 3];
|
|
|
|
rLPS = rLPS << 23; /* left aligned */
|
|
|
|
|
|
|
|
/* calculate rMPS */
|
|
|
|
rMPS = (range & 0xff800000) - rLPS;
|
|
|
|
|
|
|
|
/* most probable region */
|
|
|
|
if (offset < rMPS) {
|
|
|
|
p0 = valMPS;
|
|
|
|
|
|
|
|
}
|
|
|
|
/* least probable region */
|
|
|
|
else {
|
|
|
|
p0 = valMPS ^ 1;
|
|
|
|
}
|
|
|
|
return p0;
|
|
|
|
}
|
|
|
|
|
Hexagon (target/hexagon) Reduce manipulation of slot_cancelled
We only need to track slot for predicated stores and predicated HVX
instructions.
Add arguments to the probe helper functions to indicate if the slot
is predicated.
Here is a simple example of the differences in the TCG code generated:
IN:
0x00400094: 0xf900c102 { if (P0) R2 = and(R0,R1) }
BEFORE
---- 00400094
mov_i32 slot_cancelled,$0x0
mov_i32 new_r2,r2
and_i32 tmp0,p0,$0x1
brcond_i32 tmp0,$0x0,eq,$L1
and_i32 tmp0,r0,r1
mov_i32 new_r2,tmp0
br $L2
set_label $L1
or_i32 slot_cancelled,slot_cancelled,$0x8
set_label $L2
mov_i32 r2,new_r2
AFTER
---- 00400094
mov_i32 new_r2,r2
and_i32 tmp0,p0,$0x1
brcond_i32 tmp0,$0x0,eq,$L1
and_i32 tmp0,r0,r1
mov_i32 new_r2,tmp0
br $L2
set_label $L1
set_label $L2
mov_i32 r2,new_r2
Signed-off-by: Taylor Simpson <tsimpson@quicinc.com>
Reviewed-by: Anton Johansson <anjo@rev.ng>
Message-Id: <20230307025828.1612809-14-tsimpson@quicinc.com>
2023-03-07 05:58:27 +03:00
|
|
|
static void probe_store(CPUHexagonState *env, int slot, int mmu_idx,
|
target/hexagon: move GETPC() calls to top level helpers
As docs/devel/loads-stores.rst states:
``GETPC()`` should be used with great care: calling
it in other functions that are *not* the top level
``HELPER(foo)`` will cause unexpected behavior. Instead, the
value of ``GETPC()`` should be read from the helper and passed
if needed to the functions that the helper calls.
Let's fix the GETPC() usage in Hexagon, making sure it's always called
from top level helpers and passed down to the places where it's
needed. There are a few snippets where that is not currently the case:
- probe_store(), which is only called from two helpers, so it's easy to
move GETPC() up.
- mem_load*() functions, which are also called directly from helpers,
but through the MEM_LOAD*() set of macros. Note that this are only
used when compiling with --disable-hexagon-idef-parser.
In this case, we also take this opportunity to simplify the code,
unifying the mem_load*() functions.
- HELPER(probe_hvx_stores), when called from another helper, ends up
using its own GETPC() expansion instead of the top level caller.
Signed-off-by: Matheus Tavares Bernardino <quic_mathbern@quicinc.com>
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Message-Id: <2c74c3696946edba7cc5b2942cf296a5af532052.1689070412.git.quic_mathbern@quicinc.com>-ne
Reviewed-by: Brian Cain <bcain@quicinc.com>
Signed-off-by: Brian Cain <bcain@quicinc.com>
Message-Id: <20231008220945.983643-2-bcain@quicinc.com>
2023-10-09 01:09:43 +03:00
|
|
|
bool is_predicated, uintptr_t retaddr)
|
2021-09-22 18:30:46 +03:00
|
|
|
{
|
Hexagon (target/hexagon) Reduce manipulation of slot_cancelled
We only need to track slot for predicated stores and predicated HVX
instructions.
Add arguments to the probe helper functions to indicate if the slot
is predicated.
Here is a simple example of the differences in the TCG code generated:
IN:
0x00400094: 0xf900c102 { if (P0) R2 = and(R0,R1) }
BEFORE
---- 00400094
mov_i32 slot_cancelled,$0x0
mov_i32 new_r2,r2
and_i32 tmp0,p0,$0x1
brcond_i32 tmp0,$0x0,eq,$L1
and_i32 tmp0,r0,r1
mov_i32 new_r2,tmp0
br $L2
set_label $L1
or_i32 slot_cancelled,slot_cancelled,$0x8
set_label $L2
mov_i32 r2,new_r2
AFTER
---- 00400094
mov_i32 new_r2,r2
and_i32 tmp0,p0,$0x1
brcond_i32 tmp0,$0x0,eq,$L1
and_i32 tmp0,r0,r1
mov_i32 new_r2,tmp0
br $L2
set_label $L1
set_label $L2
mov_i32 r2,new_r2
Signed-off-by: Taylor Simpson <tsimpson@quicinc.com>
Reviewed-by: Anton Johansson <anjo@rev.ng>
Message-Id: <20230307025828.1612809-14-tsimpson@quicinc.com>
2023-03-07 05:58:27 +03:00
|
|
|
if (!is_predicated || !(env->slot_cancelled & (1 << slot))) {
|
2021-09-22 18:30:46 +03:00
|
|
|
size1u_t width = env->mem_log_stores[slot].width;
|
|
|
|
target_ulong va = env->mem_log_stores[slot].va;
|
target/hexagon: move GETPC() calls to top level helpers
As docs/devel/loads-stores.rst states:
``GETPC()`` should be used with great care: calling
it in other functions that are *not* the top level
``HELPER(foo)`` will cause unexpected behavior. Instead, the
value of ``GETPC()`` should be read from the helper and passed
if needed to the functions that the helper calls.
Let's fix the GETPC() usage in Hexagon, making sure it's always called
from top level helpers and passed down to the places where it's
needed. There are a few snippets where that is not currently the case:
- probe_store(), which is only called from two helpers, so it's easy to
move GETPC() up.
- mem_load*() functions, which are also called directly from helpers,
but through the MEM_LOAD*() set of macros. Note that this are only
used when compiling with --disable-hexagon-idef-parser.
In this case, we also take this opportunity to simplify the code,
unifying the mem_load*() functions.
- HELPER(probe_hvx_stores), when called from another helper, ends up
using its own GETPC() expansion instead of the top level caller.
Signed-off-by: Matheus Tavares Bernardino <quic_mathbern@quicinc.com>
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Message-Id: <2c74c3696946edba7cc5b2942cf296a5af532052.1689070412.git.quic_mathbern@quicinc.com>-ne
Reviewed-by: Brian Cain <bcain@quicinc.com>
Signed-off-by: Brian Cain <bcain@quicinc.com>
Message-Id: <20231008220945.983643-2-bcain@quicinc.com>
2023-10-09 01:09:43 +03:00
|
|
|
probe_write(env, va, width, mmu_idx, retaddr);
|
2021-09-22 18:30:46 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-08 00:05:46 +03:00
|
|
|
/*
|
|
|
|
* Called from a mem_noshuf packet to make sure the load doesn't
|
|
|
|
* raise an exception
|
|
|
|
*/
|
|
|
|
void HELPER(probe_noshuf_load)(CPUHexagonState *env, target_ulong va,
|
|
|
|
int size, int mmu_idx)
|
|
|
|
{
|
|
|
|
uintptr_t retaddr = GETPC();
|
|
|
|
probe_read(env, va, size, mmu_idx, retaddr);
|
|
|
|
}
|
|
|
|
|
2021-09-22 18:30:46 +03:00
|
|
|
/* Called during packet commit when there are two scalar stores */
|
Hexagon (target/hexagon) Reduce manipulation of slot_cancelled
We only need to track slot for predicated stores and predicated HVX
instructions.
Add arguments to the probe helper functions to indicate if the slot
is predicated.
Here is a simple example of the differences in the TCG code generated:
IN:
0x00400094: 0xf900c102 { if (P0) R2 = and(R0,R1) }
BEFORE
---- 00400094
mov_i32 slot_cancelled,$0x0
mov_i32 new_r2,r2
and_i32 tmp0,p0,$0x1
brcond_i32 tmp0,$0x0,eq,$L1
and_i32 tmp0,r0,r1
mov_i32 new_r2,tmp0
br $L2
set_label $L1
or_i32 slot_cancelled,slot_cancelled,$0x8
set_label $L2
mov_i32 r2,new_r2
AFTER
---- 00400094
mov_i32 new_r2,r2
and_i32 tmp0,p0,$0x1
brcond_i32 tmp0,$0x0,eq,$L1
and_i32 tmp0,r0,r1
mov_i32 new_r2,tmp0
br $L2
set_label $L1
set_label $L2
mov_i32 r2,new_r2
Signed-off-by: Taylor Simpson <tsimpson@quicinc.com>
Reviewed-by: Anton Johansson <anjo@rev.ng>
Message-Id: <20230307025828.1612809-14-tsimpson@quicinc.com>
2023-03-07 05:58:27 +03:00
|
|
|
void HELPER(probe_pkt_scalar_store_s0)(CPUHexagonState *env, int args)
|
2021-09-22 18:30:46 +03:00
|
|
|
{
|
Hexagon (target/hexagon) Reduce manipulation of slot_cancelled
We only need to track slot for predicated stores and predicated HVX
instructions.
Add arguments to the probe helper functions to indicate if the slot
is predicated.
Here is a simple example of the differences in the TCG code generated:
IN:
0x00400094: 0xf900c102 { if (P0) R2 = and(R0,R1) }
BEFORE
---- 00400094
mov_i32 slot_cancelled,$0x0
mov_i32 new_r2,r2
and_i32 tmp0,p0,$0x1
brcond_i32 tmp0,$0x0,eq,$L1
and_i32 tmp0,r0,r1
mov_i32 new_r2,tmp0
br $L2
set_label $L1
or_i32 slot_cancelled,slot_cancelled,$0x8
set_label $L2
mov_i32 r2,new_r2
AFTER
---- 00400094
mov_i32 new_r2,r2
and_i32 tmp0,p0,$0x1
brcond_i32 tmp0,$0x0,eq,$L1
and_i32 tmp0,r0,r1
mov_i32 new_r2,tmp0
br $L2
set_label $L1
set_label $L2
mov_i32 r2,new_r2
Signed-off-by: Taylor Simpson <tsimpson@quicinc.com>
Reviewed-by: Anton Johansson <anjo@rev.ng>
Message-Id: <20230307025828.1612809-14-tsimpson@quicinc.com>
2023-03-07 05:58:27 +03:00
|
|
|
int mmu_idx = FIELD_EX32(args, PROBE_PKT_SCALAR_STORE_S0, MMU_IDX);
|
|
|
|
bool is_predicated =
|
|
|
|
FIELD_EX32(args, PROBE_PKT_SCALAR_STORE_S0, IS_PREDICATED);
|
target/hexagon: move GETPC() calls to top level helpers
As docs/devel/loads-stores.rst states:
``GETPC()`` should be used with great care: calling
it in other functions that are *not* the top level
``HELPER(foo)`` will cause unexpected behavior. Instead, the
value of ``GETPC()`` should be read from the helper and passed
if needed to the functions that the helper calls.
Let's fix the GETPC() usage in Hexagon, making sure it's always called
from top level helpers and passed down to the places where it's
needed. There are a few snippets where that is not currently the case:
- probe_store(), which is only called from two helpers, so it's easy to
move GETPC() up.
- mem_load*() functions, which are also called directly from helpers,
but through the MEM_LOAD*() set of macros. Note that this are only
used when compiling with --disable-hexagon-idef-parser.
In this case, we also take this opportunity to simplify the code,
unifying the mem_load*() functions.
- HELPER(probe_hvx_stores), when called from another helper, ends up
using its own GETPC() expansion instead of the top level caller.
Signed-off-by: Matheus Tavares Bernardino <quic_mathbern@quicinc.com>
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Message-Id: <2c74c3696946edba7cc5b2942cf296a5af532052.1689070412.git.quic_mathbern@quicinc.com>-ne
Reviewed-by: Brian Cain <bcain@quicinc.com>
Signed-off-by: Brian Cain <bcain@quicinc.com>
Message-Id: <20231008220945.983643-2-bcain@quicinc.com>
2023-10-09 01:09:43 +03:00
|
|
|
uintptr_t ra = GETPC();
|
|
|
|
probe_store(env, 0, mmu_idx, is_predicated, ra);
|
2021-09-22 18:30:46 +03:00
|
|
|
}
|
|
|
|
|
target/hexagon: move GETPC() calls to top level helpers
As docs/devel/loads-stores.rst states:
``GETPC()`` should be used with great care: calling
it in other functions that are *not* the top level
``HELPER(foo)`` will cause unexpected behavior. Instead, the
value of ``GETPC()`` should be read from the helper and passed
if needed to the functions that the helper calls.
Let's fix the GETPC() usage in Hexagon, making sure it's always called
from top level helpers and passed down to the places where it's
needed. There are a few snippets where that is not currently the case:
- probe_store(), which is only called from two helpers, so it's easy to
move GETPC() up.
- mem_load*() functions, which are also called directly from helpers,
but through the MEM_LOAD*() set of macros. Note that this are only
used when compiling with --disable-hexagon-idef-parser.
In this case, we also take this opportunity to simplify the code,
unifying the mem_load*() functions.
- HELPER(probe_hvx_stores), when called from another helper, ends up
using its own GETPC() expansion instead of the top level caller.
Signed-off-by: Matheus Tavares Bernardino <quic_mathbern@quicinc.com>
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Message-Id: <2c74c3696946edba7cc5b2942cf296a5af532052.1689070412.git.quic_mathbern@quicinc.com>-ne
Reviewed-by: Brian Cain <bcain@quicinc.com>
Signed-off-by: Brian Cain <bcain@quicinc.com>
Message-Id: <20231008220945.983643-2-bcain@quicinc.com>
2023-10-09 01:09:43 +03:00
|
|
|
static void probe_hvx_stores(CPUHexagonState *env, int mmu_idx,
|
|
|
|
uintptr_t retaddr)
|
2021-09-30 19:07:00 +03:00
|
|
|
{
|
|
|
|
/* Normal (possibly masked) vector store */
|
2023-10-09 01:09:44 +03:00
|
|
|
for (int i = 0; i < VSTORES_MAX; i++) {
|
2021-09-30 19:07:00 +03:00
|
|
|
if (env->vstore_pending[i]) {
|
|
|
|
target_ulong va = env->vstore[i].va;
|
|
|
|
int size = env->vstore[i].size;
|
|
|
|
for (int j = 0; j < size; j++) {
|
|
|
|
if (test_bit(j, env->vstore[i].mask)) {
|
|
|
|
probe_write(env, va + j, 1, mmu_idx, retaddr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Scatter store */
|
|
|
|
if (env->vtcm_pending) {
|
|
|
|
if (env->vtcm_log.op) {
|
|
|
|
/* Need to perform the scatter read/modify/write at commit time */
|
|
|
|
if (env->vtcm_log.op_size == 2) {
|
|
|
|
SCATTER_OP_PROBE_MEM(size2u_t, mmu_idx, retaddr);
|
|
|
|
} else if (env->vtcm_log.op_size == 4) {
|
|
|
|
/* Word Scatter += */
|
|
|
|
SCATTER_OP_PROBE_MEM(size4u_t, mmu_idx, retaddr);
|
|
|
|
} else {
|
|
|
|
g_assert_not_reached();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (int i = 0; i < sizeof(MMVector); i++) {
|
|
|
|
if (test_bit(i, env->vtcm_log.mask)) {
|
|
|
|
probe_write(env, env->vtcm_log.va[i], 1, mmu_idx, retaddr);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
target/hexagon: move GETPC() calls to top level helpers
As docs/devel/loads-stores.rst states:
``GETPC()`` should be used with great care: calling
it in other functions that are *not* the top level
``HELPER(foo)`` will cause unexpected behavior. Instead, the
value of ``GETPC()`` should be read from the helper and passed
if needed to the functions that the helper calls.
Let's fix the GETPC() usage in Hexagon, making sure it's always called
from top level helpers and passed down to the places where it's
needed. There are a few snippets where that is not currently the case:
- probe_store(), which is only called from two helpers, so it's easy to
move GETPC() up.
- mem_load*() functions, which are also called directly from helpers,
but through the MEM_LOAD*() set of macros. Note that this are only
used when compiling with --disable-hexagon-idef-parser.
In this case, we also take this opportunity to simplify the code,
unifying the mem_load*() functions.
- HELPER(probe_hvx_stores), when called from another helper, ends up
using its own GETPC() expansion instead of the top level caller.
Signed-off-by: Matheus Tavares Bernardino <quic_mathbern@quicinc.com>
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Message-Id: <2c74c3696946edba7cc5b2942cf296a5af532052.1689070412.git.quic_mathbern@quicinc.com>-ne
Reviewed-by: Brian Cain <bcain@quicinc.com>
Signed-off-by: Brian Cain <bcain@quicinc.com>
Message-Id: <20231008220945.983643-2-bcain@quicinc.com>
2023-10-09 01:09:43 +03:00
|
|
|
void HELPER(probe_hvx_stores)(CPUHexagonState *env, int mmu_idx)
|
|
|
|
{
|
|
|
|
uintptr_t retaddr = GETPC();
|
|
|
|
probe_hvx_stores(env, mmu_idx, retaddr);
|
|
|
|
}
|
|
|
|
|
2023-04-05 19:42:10 +03:00
|
|
|
void HELPER(probe_pkt_scalar_hvx_stores)(CPUHexagonState *env, int mask)
|
2021-09-30 19:07:00 +03:00
|
|
|
{
|
Hexagon (target/hexagon) Reduce manipulation of slot_cancelled
We only need to track slot for predicated stores and predicated HVX
instructions.
Add arguments to the probe helper functions to indicate if the slot
is predicated.
Here is a simple example of the differences in the TCG code generated:
IN:
0x00400094: 0xf900c102 { if (P0) R2 = and(R0,R1) }
BEFORE
---- 00400094
mov_i32 slot_cancelled,$0x0
mov_i32 new_r2,r2
and_i32 tmp0,p0,$0x1
brcond_i32 tmp0,$0x0,eq,$L1
and_i32 tmp0,r0,r1
mov_i32 new_r2,tmp0
br $L2
set_label $L1
or_i32 slot_cancelled,slot_cancelled,$0x8
set_label $L2
mov_i32 r2,new_r2
AFTER
---- 00400094
mov_i32 new_r2,r2
and_i32 tmp0,p0,$0x1
brcond_i32 tmp0,$0x0,eq,$L1
and_i32 tmp0,r0,r1
mov_i32 new_r2,tmp0
br $L2
set_label $L1
set_label $L2
mov_i32 r2,new_r2
Signed-off-by: Taylor Simpson <tsimpson@quicinc.com>
Reviewed-by: Anton Johansson <anjo@rev.ng>
Message-Id: <20230307025828.1612809-14-tsimpson@quicinc.com>
2023-03-07 05:58:27 +03:00
|
|
|
bool has_st0 = FIELD_EX32(mask, PROBE_PKT_SCALAR_HVX_STORES, HAS_ST0);
|
|
|
|
bool has_st1 = FIELD_EX32(mask, PROBE_PKT_SCALAR_HVX_STORES, HAS_ST1);
|
|
|
|
bool has_hvx_stores =
|
|
|
|
FIELD_EX32(mask, PROBE_PKT_SCALAR_HVX_STORES, HAS_HVX_STORES);
|
|
|
|
bool s0_is_pred = FIELD_EX32(mask, PROBE_PKT_SCALAR_HVX_STORES, S0_IS_PRED);
|
|
|
|
bool s1_is_pred = FIELD_EX32(mask, PROBE_PKT_SCALAR_HVX_STORES, S1_IS_PRED);
|
2023-04-05 19:42:10 +03:00
|
|
|
int mmu_idx = FIELD_EX32(mask, PROBE_PKT_SCALAR_HVX_STORES, MMU_IDX);
|
target/hexagon: move GETPC() calls to top level helpers
As docs/devel/loads-stores.rst states:
``GETPC()`` should be used with great care: calling
it in other functions that are *not* the top level
``HELPER(foo)`` will cause unexpected behavior. Instead, the
value of ``GETPC()`` should be read from the helper and passed
if needed to the functions that the helper calls.
Let's fix the GETPC() usage in Hexagon, making sure it's always called
from top level helpers and passed down to the places where it's
needed. There are a few snippets where that is not currently the case:
- probe_store(), which is only called from two helpers, so it's easy to
move GETPC() up.
- mem_load*() functions, which are also called directly from helpers,
but through the MEM_LOAD*() set of macros. Note that this are only
used when compiling with --disable-hexagon-idef-parser.
In this case, we also take this opportunity to simplify the code,
unifying the mem_load*() functions.
- HELPER(probe_hvx_stores), when called from another helper, ends up
using its own GETPC() expansion instead of the top level caller.
Signed-off-by: Matheus Tavares Bernardino <quic_mathbern@quicinc.com>
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Message-Id: <2c74c3696946edba7cc5b2942cf296a5af532052.1689070412.git.quic_mathbern@quicinc.com>-ne
Reviewed-by: Brian Cain <bcain@quicinc.com>
Signed-off-by: Brian Cain <bcain@quicinc.com>
Message-Id: <20231008220945.983643-2-bcain@quicinc.com>
2023-10-09 01:09:43 +03:00
|
|
|
uintptr_t ra = GETPC();
|
2021-09-30 19:07:00 +03:00
|
|
|
|
|
|
|
if (has_st0) {
|
target/hexagon: move GETPC() calls to top level helpers
As docs/devel/loads-stores.rst states:
``GETPC()`` should be used with great care: calling
it in other functions that are *not* the top level
``HELPER(foo)`` will cause unexpected behavior. Instead, the
value of ``GETPC()`` should be read from the helper and passed
if needed to the functions that the helper calls.
Let's fix the GETPC() usage in Hexagon, making sure it's always called
from top level helpers and passed down to the places where it's
needed. There are a few snippets where that is not currently the case:
- probe_store(), which is only called from two helpers, so it's easy to
move GETPC() up.
- mem_load*() functions, which are also called directly from helpers,
but through the MEM_LOAD*() set of macros. Note that this are only
used when compiling with --disable-hexagon-idef-parser.
In this case, we also take this opportunity to simplify the code,
unifying the mem_load*() functions.
- HELPER(probe_hvx_stores), when called from another helper, ends up
using its own GETPC() expansion instead of the top level caller.
Signed-off-by: Matheus Tavares Bernardino <quic_mathbern@quicinc.com>
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Message-Id: <2c74c3696946edba7cc5b2942cf296a5af532052.1689070412.git.quic_mathbern@quicinc.com>-ne
Reviewed-by: Brian Cain <bcain@quicinc.com>
Signed-off-by: Brian Cain <bcain@quicinc.com>
Message-Id: <20231008220945.983643-2-bcain@quicinc.com>
2023-10-09 01:09:43 +03:00
|
|
|
probe_store(env, 0, mmu_idx, s0_is_pred, ra);
|
2021-09-30 19:07:00 +03:00
|
|
|
}
|
|
|
|
if (has_st1) {
|
target/hexagon: move GETPC() calls to top level helpers
As docs/devel/loads-stores.rst states:
``GETPC()`` should be used with great care: calling
it in other functions that are *not* the top level
``HELPER(foo)`` will cause unexpected behavior. Instead, the
value of ``GETPC()`` should be read from the helper and passed
if needed to the functions that the helper calls.
Let's fix the GETPC() usage in Hexagon, making sure it's always called
from top level helpers and passed down to the places where it's
needed. There are a few snippets where that is not currently the case:
- probe_store(), which is only called from two helpers, so it's easy to
move GETPC() up.
- mem_load*() functions, which are also called directly from helpers,
but through the MEM_LOAD*() set of macros. Note that this are only
used when compiling with --disable-hexagon-idef-parser.
In this case, we also take this opportunity to simplify the code,
unifying the mem_load*() functions.
- HELPER(probe_hvx_stores), when called from another helper, ends up
using its own GETPC() expansion instead of the top level caller.
Signed-off-by: Matheus Tavares Bernardino <quic_mathbern@quicinc.com>
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Message-Id: <2c74c3696946edba7cc5b2942cf296a5af532052.1689070412.git.quic_mathbern@quicinc.com>-ne
Reviewed-by: Brian Cain <bcain@quicinc.com>
Signed-off-by: Brian Cain <bcain@quicinc.com>
Message-Id: <20231008220945.983643-2-bcain@quicinc.com>
2023-10-09 01:09:43 +03:00
|
|
|
probe_store(env, 1, mmu_idx, s1_is_pred, ra);
|
2021-09-30 19:07:00 +03:00
|
|
|
}
|
|
|
|
if (has_hvx_stores) {
|
target/hexagon: move GETPC() calls to top level helpers
As docs/devel/loads-stores.rst states:
``GETPC()`` should be used with great care: calling
it in other functions that are *not* the top level
``HELPER(foo)`` will cause unexpected behavior. Instead, the
value of ``GETPC()`` should be read from the helper and passed
if needed to the functions that the helper calls.
Let's fix the GETPC() usage in Hexagon, making sure it's always called
from top level helpers and passed down to the places where it's
needed. There are a few snippets where that is not currently the case:
- probe_store(), which is only called from two helpers, so it's easy to
move GETPC() up.
- mem_load*() functions, which are also called directly from helpers,
but through the MEM_LOAD*() set of macros. Note that this are only
used when compiling with --disable-hexagon-idef-parser.
In this case, we also take this opportunity to simplify the code,
unifying the mem_load*() functions.
- HELPER(probe_hvx_stores), when called from another helper, ends up
using its own GETPC() expansion instead of the top level caller.
Signed-off-by: Matheus Tavares Bernardino <quic_mathbern@quicinc.com>
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Message-Id: <2c74c3696946edba7cc5b2942cf296a5af532052.1689070412.git.quic_mathbern@quicinc.com>-ne
Reviewed-by: Brian Cain <bcain@quicinc.com>
Signed-off-by: Brian Cain <bcain@quicinc.com>
Message-Id: <20231008220945.983643-2-bcain@quicinc.com>
2023-10-09 01:09:43 +03:00
|
|
|
probe_hvx_stores(env, mmu_idx, ra);
|
2021-09-30 19:07:00 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
target/hexagon: move GETPC() calls to top level helpers
As docs/devel/loads-stores.rst states:
``GETPC()`` should be used with great care: calling
it in other functions that are *not* the top level
``HELPER(foo)`` will cause unexpected behavior. Instead, the
value of ``GETPC()`` should be read from the helper and passed
if needed to the functions that the helper calls.
Let's fix the GETPC() usage in Hexagon, making sure it's always called
from top level helpers and passed down to the places where it's
needed. There are a few snippets where that is not currently the case:
- probe_store(), which is only called from two helpers, so it's easy to
move GETPC() up.
- mem_load*() functions, which are also called directly from helpers,
but through the MEM_LOAD*() set of macros. Note that this are only
used when compiling with --disable-hexagon-idef-parser.
In this case, we also take this opportunity to simplify the code,
unifying the mem_load*() functions.
- HELPER(probe_hvx_stores), when called from another helper, ends up
using its own GETPC() expansion instead of the top level caller.
Signed-off-by: Matheus Tavares Bernardino <quic_mathbern@quicinc.com>
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Message-Id: <2c74c3696946edba7cc5b2942cf296a5af532052.1689070412.git.quic_mathbern@quicinc.com>-ne
Reviewed-by: Brian Cain <bcain@quicinc.com>
Signed-off-by: Brian Cain <bcain@quicinc.com>
Message-Id: <20231008220945.983643-2-bcain@quicinc.com>
2023-10-09 01:09:43 +03:00
|
|
|
#ifndef CONFIG_HEXAGON_IDEF_PARSER
|
2021-02-08 08:45:57 +03:00
|
|
|
/*
|
|
|
|
* mem_noshuf
|
|
|
|
* Section 5.5 of the Hexagon V67 Programmer's Reference Manual
|
|
|
|
*
|
|
|
|
* If the load is in slot 0 and there is a store in slot1 (that
|
|
|
|
* wasn't cancelled), we have to do the store first.
|
|
|
|
*/
|
2023-04-28 02:00:11 +03:00
|
|
|
static void check_noshuf(CPUHexagonState *env, bool pkt_has_store_s1,
|
target/hexagon: move GETPC() calls to top level helpers
As docs/devel/loads-stores.rst states:
``GETPC()`` should be used with great care: calling
it in other functions that are *not* the top level
``HELPER(foo)`` will cause unexpected behavior. Instead, the
value of ``GETPC()`` should be read from the helper and passed
if needed to the functions that the helper calls.
Let's fix the GETPC() usage in Hexagon, making sure it's always called
from top level helpers and passed down to the places where it's
needed. There are a few snippets where that is not currently the case:
- probe_store(), which is only called from two helpers, so it's easy to
move GETPC() up.
- mem_load*() functions, which are also called directly from helpers,
but through the MEM_LOAD*() set of macros. Note that this are only
used when compiling with --disable-hexagon-idef-parser.
In this case, we also take this opportunity to simplify the code,
unifying the mem_load*() functions.
- HELPER(probe_hvx_stores), when called from another helper, ends up
using its own GETPC() expansion instead of the top level caller.
Signed-off-by: Matheus Tavares Bernardino <quic_mathbern@quicinc.com>
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Message-Id: <2c74c3696946edba7cc5b2942cf296a5af532052.1689070412.git.quic_mathbern@quicinc.com>-ne
Reviewed-by: Brian Cain <bcain@quicinc.com>
Signed-off-by: Brian Cain <bcain@quicinc.com>
Message-Id: <20231008220945.983643-2-bcain@quicinc.com>
2023-10-09 01:09:43 +03:00
|
|
|
uint32_t slot, target_ulong vaddr, int size,
|
|
|
|
uintptr_t ra)
|
2021-02-08 08:45:57 +03:00
|
|
|
{
|
2023-04-28 02:00:11 +03:00
|
|
|
if (slot == 0 && pkt_has_store_s1 &&
|
2021-02-08 08:45:57 +03:00
|
|
|
((env->slot_cancelled & (1 << 1)) == 0)) {
|
target/hexagon: move GETPC() calls to top level helpers
As docs/devel/loads-stores.rst states:
``GETPC()`` should be used with great care: calling
it in other functions that are *not* the top level
``HELPER(foo)`` will cause unexpected behavior. Instead, the
value of ``GETPC()`` should be read from the helper and passed
if needed to the functions that the helper calls.
Let's fix the GETPC() usage in Hexagon, making sure it's always called
from top level helpers and passed down to the places where it's
needed. There are a few snippets where that is not currently the case:
- probe_store(), which is only called from two helpers, so it's easy to
move GETPC() up.
- mem_load*() functions, which are also called directly from helpers,
but through the MEM_LOAD*() set of macros. Note that this are only
used when compiling with --disable-hexagon-idef-parser.
In this case, we also take this opportunity to simplify the code,
unifying the mem_load*() functions.
- HELPER(probe_hvx_stores), when called from another helper, ends up
using its own GETPC() expansion instead of the top level caller.
Signed-off-by: Matheus Tavares Bernardino <quic_mathbern@quicinc.com>
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Message-Id: <2c74c3696946edba7cc5b2942cf296a5af532052.1689070412.git.quic_mathbern@quicinc.com>-ne
Reviewed-by: Brian Cain <bcain@quicinc.com>
Signed-off-by: Brian Cain <bcain@quicinc.com>
Message-Id: <20231008220945.983643-2-bcain@quicinc.com>
2023-10-09 01:09:43 +03:00
|
|
|
probe_read(env, vaddr, size, MMU_USER_IDX, ra);
|
|
|
|
commit_store(env, 1, ra);
|
2021-02-08 08:45:57 +03:00
|
|
|
}
|
|
|
|
}
|
target/hexagon: move GETPC() calls to top level helpers
As docs/devel/loads-stores.rst states:
``GETPC()`` should be used with great care: calling
it in other functions that are *not* the top level
``HELPER(foo)`` will cause unexpected behavior. Instead, the
value of ``GETPC()`` should be read from the helper and passed
if needed to the functions that the helper calls.
Let's fix the GETPC() usage in Hexagon, making sure it's always called
from top level helpers and passed down to the places where it's
needed. There are a few snippets where that is not currently the case:
- probe_store(), which is only called from two helpers, so it's easy to
move GETPC() up.
- mem_load*() functions, which are also called directly from helpers,
but through the MEM_LOAD*() set of macros. Note that this are only
used when compiling with --disable-hexagon-idef-parser.
In this case, we also take this opportunity to simplify the code,
unifying the mem_load*() functions.
- HELPER(probe_hvx_stores), when called from another helper, ends up
using its own GETPC() expansion instead of the top level caller.
Signed-off-by: Matheus Tavares Bernardino <quic_mathbern@quicinc.com>
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Message-Id: <2c74c3696946edba7cc5b2942cf296a5af532052.1689070412.git.quic_mathbern@quicinc.com>-ne
Reviewed-by: Brian Cain <bcain@quicinc.com>
Signed-off-by: Brian Cain <bcain@quicinc.com>
Message-Id: <20231008220945.983643-2-bcain@quicinc.com>
2023-10-09 01:09:43 +03:00
|
|
|
#endif
|
2021-02-08 08:45:57 +03:00
|
|
|
|
|
|
|
/* Floating point */
|
|
|
|
float64 HELPER(conv_sf2df)(CPUHexagonState *env, float32 RsV)
|
|
|
|
{
|
|
|
|
float64 out_f64;
|
|
|
|
arch_fpop_start(env);
|
|
|
|
out_f64 = float32_to_float64(RsV, &env->fp_status);
|
|
|
|
arch_fpop_end(env);
|
|
|
|
return out_f64;
|
|
|
|
}
|
|
|
|
|
|
|
|
float32 HELPER(conv_df2sf)(CPUHexagonState *env, float64 RssV)
|
|
|
|
{
|
|
|
|
float32 out_f32;
|
|
|
|
arch_fpop_start(env);
|
|
|
|
out_f32 = float64_to_float32(RssV, &env->fp_status);
|
|
|
|
arch_fpop_end(env);
|
|
|
|
return out_f32;
|
|
|
|
}
|
|
|
|
|
|
|
|
float32 HELPER(conv_uw2sf)(CPUHexagonState *env, int32_t RsV)
|
|
|
|
{
|
|
|
|
float32 RdV;
|
|
|
|
arch_fpop_start(env);
|
|
|
|
RdV = uint32_to_float32(RsV, &env->fp_status);
|
|
|
|
arch_fpop_end(env);
|
|
|
|
return RdV;
|
|
|
|
}
|
|
|
|
|
|
|
|
float64 HELPER(conv_uw2df)(CPUHexagonState *env, int32_t RsV)
|
|
|
|
{
|
|
|
|
float64 RddV;
|
|
|
|
arch_fpop_start(env);
|
|
|
|
RddV = uint32_to_float64(RsV, &env->fp_status);
|
|
|
|
arch_fpop_end(env);
|
|
|
|
return RddV;
|
|
|
|
}
|
|
|
|
|
|
|
|
float32 HELPER(conv_w2sf)(CPUHexagonState *env, int32_t RsV)
|
|
|
|
{
|
|
|
|
float32 RdV;
|
|
|
|
arch_fpop_start(env);
|
|
|
|
RdV = int32_to_float32(RsV, &env->fp_status);
|
|
|
|
arch_fpop_end(env);
|
|
|
|
return RdV;
|
|
|
|
}
|
|
|
|
|
|
|
|
float64 HELPER(conv_w2df)(CPUHexagonState *env, int32_t RsV)
|
|
|
|
{
|
|
|
|
float64 RddV;
|
|
|
|
arch_fpop_start(env);
|
|
|
|
RddV = int32_to_float64(RsV, &env->fp_status);
|
|
|
|
arch_fpop_end(env);
|
|
|
|
return RddV;
|
|
|
|
}
|
|
|
|
|
|
|
|
float32 HELPER(conv_ud2sf)(CPUHexagonState *env, int64_t RssV)
|
|
|
|
{
|
|
|
|
float32 RdV;
|
|
|
|
arch_fpop_start(env);
|
|
|
|
RdV = uint64_to_float32(RssV, &env->fp_status);
|
|
|
|
arch_fpop_end(env);
|
|
|
|
return RdV;
|
|
|
|
}
|
|
|
|
|
|
|
|
float64 HELPER(conv_ud2df)(CPUHexagonState *env, int64_t RssV)
|
|
|
|
{
|
|
|
|
float64 RddV;
|
|
|
|
arch_fpop_start(env);
|
|
|
|
RddV = uint64_to_float64(RssV, &env->fp_status);
|
|
|
|
arch_fpop_end(env);
|
|
|
|
return RddV;
|
|
|
|
}
|
|
|
|
|
|
|
|
float32 HELPER(conv_d2sf)(CPUHexagonState *env, int64_t RssV)
|
|
|
|
{
|
|
|
|
float32 RdV;
|
|
|
|
arch_fpop_start(env);
|
|
|
|
RdV = int64_to_float32(RssV, &env->fp_status);
|
|
|
|
arch_fpop_end(env);
|
|
|
|
return RdV;
|
|
|
|
}
|
|
|
|
|
|
|
|
float64 HELPER(conv_d2df)(CPUHexagonState *env, int64_t RssV)
|
|
|
|
{
|
|
|
|
float64 RddV;
|
|
|
|
arch_fpop_start(env);
|
|
|
|
RddV = int64_to_float64(RssV, &env->fp_status);
|
|
|
|
arch_fpop_end(env);
|
|
|
|
return RddV;
|
|
|
|
}
|
|
|
|
|
2021-04-09 04:07:40 +03:00
|
|
|
uint32_t HELPER(conv_sf2uw)(CPUHexagonState *env, float32 RsV)
|
2021-02-08 08:45:57 +03:00
|
|
|
{
|
2021-04-09 04:07:40 +03:00
|
|
|
uint32_t RdV;
|
2021-02-08 08:45:57 +03:00
|
|
|
arch_fpop_start(env);
|
2021-04-09 04:07:40 +03:00
|
|
|
/* Hexagon checks the sign before rounding */
|
|
|
|
if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
|
|
|
|
float_raise(float_flag_invalid, &env->fp_status);
|
|
|
|
RdV = 0;
|
|
|
|
} else {
|
|
|
|
RdV = float32_to_uint32(RsV, &env->fp_status);
|
|
|
|
}
|
2021-02-08 08:45:57 +03:00
|
|
|
arch_fpop_end(env);
|
|
|
|
return RdV;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t HELPER(conv_sf2w)(CPUHexagonState *env, float32 RsV)
|
|
|
|
{
|
|
|
|
int32_t RdV;
|
|
|
|
arch_fpop_start(env);
|
2021-04-09 04:07:40 +03:00
|
|
|
/* Hexagon returns -1 for NaN */
|
|
|
|
if (float32_is_any_nan(RsV)) {
|
|
|
|
float_raise(float_flag_invalid, &env->fp_status);
|
|
|
|
RdV = -1;
|
|
|
|
} else {
|
|
|
|
RdV = float32_to_int32(RsV, &env->fp_status);
|
|
|
|
}
|
2021-02-08 08:45:57 +03:00
|
|
|
arch_fpop_end(env);
|
|
|
|
return RdV;
|
|
|
|
}
|
|
|
|
|
2021-04-09 04:07:40 +03:00
|
|
|
uint64_t HELPER(conv_sf2ud)(CPUHexagonState *env, float32 RsV)
|
2021-02-08 08:45:57 +03:00
|
|
|
{
|
2021-04-09 04:07:40 +03:00
|
|
|
uint64_t RddV;
|
2021-02-08 08:45:57 +03:00
|
|
|
arch_fpop_start(env);
|
2021-04-09 04:07:40 +03:00
|
|
|
/* Hexagon checks the sign before rounding */
|
|
|
|
if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
|
|
|
|
float_raise(float_flag_invalid, &env->fp_status);
|
|
|
|
RddV = 0;
|
|
|
|
} else {
|
|
|
|
RddV = float32_to_uint64(RsV, &env->fp_status);
|
|
|
|
}
|
2021-02-08 08:45:57 +03:00
|
|
|
arch_fpop_end(env);
|
|
|
|
return RddV;
|
|
|
|
}
|
|
|
|
|
|
|
|
int64_t HELPER(conv_sf2d)(CPUHexagonState *env, float32 RsV)
|
|
|
|
{
|
|
|
|
int64_t RddV;
|
|
|
|
arch_fpop_start(env);
|
2021-04-09 04:07:40 +03:00
|
|
|
/* Hexagon returns -1 for NaN */
|
|
|
|
if (float32_is_any_nan(RsV)) {
|
|
|
|
float_raise(float_flag_invalid, &env->fp_status);
|
|
|
|
RddV = -1;
|
|
|
|
} else {
|
|
|
|
RddV = float32_to_int64(RsV, &env->fp_status);
|
|
|
|
}
|
2021-02-08 08:45:57 +03:00
|
|
|
arch_fpop_end(env);
|
|
|
|
return RddV;
|
|
|
|
}
|
|
|
|
|
2021-04-09 04:07:40 +03:00
|
|
|
uint32_t HELPER(conv_df2uw)(CPUHexagonState *env, float64 RssV)
|
2021-02-08 08:45:57 +03:00
|
|
|
{
|
2021-04-09 04:07:40 +03:00
|
|
|
uint32_t RdV;
|
2021-02-08 08:45:57 +03:00
|
|
|
arch_fpop_start(env);
|
2021-04-09 04:07:40 +03:00
|
|
|
/* Hexagon checks the sign before rounding */
|
|
|
|
if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) {
|
|
|
|
float_raise(float_flag_invalid, &env->fp_status);
|
|
|
|
RdV = 0;
|
|
|
|
} else {
|
|
|
|
RdV = float64_to_uint32(RssV, &env->fp_status);
|
|
|
|
}
|
2021-02-08 08:45:57 +03:00
|
|
|
arch_fpop_end(env);
|
|
|
|
return RdV;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t HELPER(conv_df2w)(CPUHexagonState *env, float64 RssV)
|
|
|
|
{
|
|
|
|
int32_t RdV;
|
|
|
|
arch_fpop_start(env);
|
2021-04-09 04:07:40 +03:00
|
|
|
/* Hexagon returns -1 for NaN */
|
|
|
|
if (float64_is_any_nan(RssV)) {
|
|
|
|
float_raise(float_flag_invalid, &env->fp_status);
|
|
|
|
RdV = -1;
|
|
|
|
} else {
|
|
|
|
RdV = float64_to_int32(RssV, &env->fp_status);
|
|
|
|
}
|
2021-02-08 08:45:57 +03:00
|
|
|
arch_fpop_end(env);
|
|
|
|
return RdV;
|
|
|
|
}
|
|
|
|
|
2021-04-09 04:07:40 +03:00
|
|
|
uint64_t HELPER(conv_df2ud)(CPUHexagonState *env, float64 RssV)
|
2021-02-08 08:45:57 +03:00
|
|
|
{
|
2021-04-09 04:07:40 +03:00
|
|
|
uint64_t RddV;
|
2021-02-08 08:45:57 +03:00
|
|
|
arch_fpop_start(env);
|
2021-04-09 04:07:40 +03:00
|
|
|
/* Hexagon checks the sign before rounding */
|
|
|
|
if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) {
|
|
|
|
float_raise(float_flag_invalid, &env->fp_status);
|
|
|
|
RddV = 0;
|
|
|
|
} else {
|
|
|
|
RddV = float64_to_uint64(RssV, &env->fp_status);
|
|
|
|
}
|
2021-02-08 08:45:57 +03:00
|
|
|
arch_fpop_end(env);
|
|
|
|
return RddV;
|
|
|
|
}
|
|
|
|
|
|
|
|
int64_t HELPER(conv_df2d)(CPUHexagonState *env, float64 RssV)
|
|
|
|
{
|
|
|
|
int64_t RddV;
|
|
|
|
arch_fpop_start(env);
|
2021-04-09 04:07:40 +03:00
|
|
|
/* Hexagon returns -1 for NaN */
|
|
|
|
if (float64_is_any_nan(RssV)) {
|
|
|
|
float_raise(float_flag_invalid, &env->fp_status);
|
|
|
|
RddV = -1;
|
|
|
|
} else {
|
|
|
|
RddV = float64_to_int64(RssV, &env->fp_status);
|
|
|
|
}
|
2021-02-08 08:45:57 +03:00
|
|
|
arch_fpop_end(env);
|
|
|
|
return RddV;
|
|
|
|
}
|
|
|
|
|
2021-04-09 04:07:40 +03:00
|
|
|
uint32_t HELPER(conv_sf2uw_chop)(CPUHexagonState *env, float32 RsV)
|
2021-02-08 08:45:57 +03:00
|
|
|
{
|
2021-04-09 04:07:40 +03:00
|
|
|
uint32_t RdV;
|
2021-02-08 08:45:57 +03:00
|
|
|
arch_fpop_start(env);
|
2021-04-09 04:07:40 +03:00
|
|
|
/* Hexagon checks the sign before rounding */
|
|
|
|
if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
|
|
|
|
float_raise(float_flag_invalid, &env->fp_status);
|
|
|
|
RdV = 0;
|
|
|
|
} else {
|
|
|
|
RdV = float32_to_uint32_round_to_zero(RsV, &env->fp_status);
|
|
|
|
}
|
2021-02-08 08:45:57 +03:00
|
|
|
arch_fpop_end(env);
|
|
|
|
return RdV;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t HELPER(conv_sf2w_chop)(CPUHexagonState *env, float32 RsV)
|
|
|
|
{
|
|
|
|
int32_t RdV;
|
|
|
|
arch_fpop_start(env);
|
2021-04-09 04:07:40 +03:00
|
|
|
/* Hexagon returns -1 for NaN */
|
|
|
|
if (float32_is_any_nan(RsV)) {
|
|
|
|
float_raise(float_flag_invalid, &env->fp_status);
|
|
|
|
RdV = -1;
|
|
|
|
} else {
|
|
|
|
RdV = float32_to_int32_round_to_zero(RsV, &env->fp_status);
|
|
|
|
}
|
2021-02-08 08:45:57 +03:00
|
|
|
arch_fpop_end(env);
|
|
|
|
return RdV;
|
|
|
|
}
|
|
|
|
|
2021-04-09 04:07:40 +03:00
|
|
|
uint64_t HELPER(conv_sf2ud_chop)(CPUHexagonState *env, float32 RsV)
|
2021-02-08 08:45:57 +03:00
|
|
|
{
|
2021-04-09 04:07:40 +03:00
|
|
|
uint64_t RddV;
|
2021-02-08 08:45:57 +03:00
|
|
|
arch_fpop_start(env);
|
2021-04-09 04:07:40 +03:00
|
|
|
/* Hexagon checks the sign before rounding */
|
|
|
|
if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
|
|
|
|
float_raise(float_flag_invalid, &env->fp_status);
|
|
|
|
RddV = 0;
|
|
|
|
} else {
|
|
|
|
RddV = float32_to_uint64_round_to_zero(RsV, &env->fp_status);
|
|
|
|
}
|
2021-02-08 08:45:57 +03:00
|
|
|
arch_fpop_end(env);
|
|
|
|
return RddV;
|
|
|
|
}
|
|
|
|
|
|
|
|
int64_t HELPER(conv_sf2d_chop)(CPUHexagonState *env, float32 RsV)
|
|
|
|
{
|
|
|
|
int64_t RddV;
|
|
|
|
arch_fpop_start(env);
|
2021-04-09 04:07:40 +03:00
|
|
|
/* Hexagon returns -1 for NaN */
|
|
|
|
if (float32_is_any_nan(RsV)) {
|
|
|
|
float_raise(float_flag_invalid, &env->fp_status);
|
|
|
|
RddV = -1;
|
|
|
|
} else {
|
|
|
|
RddV = float32_to_int64_round_to_zero(RsV, &env->fp_status);
|
|
|
|
}
|
2021-02-08 08:45:57 +03:00
|
|
|
arch_fpop_end(env);
|
|
|
|
return RddV;
|
|
|
|
}
|
|
|
|
|
2021-04-09 04:07:40 +03:00
|
|
|
uint32_t HELPER(conv_df2uw_chop)(CPUHexagonState *env, float64 RssV)
|
2021-02-08 08:45:57 +03:00
|
|
|
{
|
2021-04-09 04:07:40 +03:00
|
|
|
uint32_t RdV;
|
2021-02-08 08:45:57 +03:00
|
|
|
arch_fpop_start(env);
|
2021-04-09 04:07:40 +03:00
|
|
|
/* Hexagon checks the sign before rounding */
|
2022-02-10 05:15:54 +03:00
|
|
|
if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) {
|
2021-04-09 04:07:40 +03:00
|
|
|
float_raise(float_flag_invalid, &env->fp_status);
|
|
|
|
RdV = 0;
|
|
|
|
} else {
|
|
|
|
RdV = float64_to_uint32_round_to_zero(RssV, &env->fp_status);
|
|
|
|
}
|
2021-02-08 08:45:57 +03:00
|
|
|
arch_fpop_end(env);
|
|
|
|
return RdV;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t HELPER(conv_df2w_chop)(CPUHexagonState *env, float64 RssV)
|
|
|
|
{
|
|
|
|
int32_t RdV;
|
|
|
|
arch_fpop_start(env);
|
2021-04-09 04:07:40 +03:00
|
|
|
/* Hexagon returns -1 for NaN */
|
|
|
|
if (float64_is_any_nan(RssV)) {
|
|
|
|
float_raise(float_flag_invalid, &env->fp_status);
|
|
|
|
RdV = -1;
|
|
|
|
} else {
|
|
|
|
RdV = float64_to_int32_round_to_zero(RssV, &env->fp_status);
|
|
|
|
}
|
2021-02-08 08:45:57 +03:00
|
|
|
arch_fpop_end(env);
|
|
|
|
return RdV;
|
|
|
|
}
|
|
|
|
|
2021-04-09 04:07:40 +03:00
|
|
|
uint64_t HELPER(conv_df2ud_chop)(CPUHexagonState *env, float64 RssV)
|
2021-02-08 08:45:57 +03:00
|
|
|
{
|
2021-04-09 04:07:40 +03:00
|
|
|
uint64_t RddV;
|
2021-02-08 08:45:57 +03:00
|
|
|
arch_fpop_start(env);
|
2021-04-09 04:07:40 +03:00
|
|
|
/* Hexagon checks the sign before rounding */
|
|
|
|
if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) {
|
|
|
|
float_raise(float_flag_invalid, &env->fp_status);
|
|
|
|
RddV = 0;
|
|
|
|
} else {
|
|
|
|
RddV = float64_to_uint64_round_to_zero(RssV, &env->fp_status);
|
|
|
|
}
|
2021-02-08 08:45:57 +03:00
|
|
|
arch_fpop_end(env);
|
|
|
|
return RddV;
|
|
|
|
}
|
|
|
|
|
|
|
|
int64_t HELPER(conv_df2d_chop)(CPUHexagonState *env, float64 RssV)
|
|
|
|
{
|
|
|
|
int64_t RddV;
|
|
|
|
arch_fpop_start(env);
|
2021-04-09 04:07:40 +03:00
|
|
|
/* Hexagon returns -1 for NaN */
|
|
|
|
if (float64_is_any_nan(RssV)) {
|
|
|
|
float_raise(float_flag_invalid, &env->fp_status);
|
|
|
|
RddV = -1;
|
|
|
|
} else {
|
|
|
|
RddV = float64_to_int64_round_to_zero(RssV, &env->fp_status);
|
|
|
|
}
|
2021-02-08 08:45:57 +03:00
|
|
|
arch_fpop_end(env);
|
|
|
|
return RddV;
|
|
|
|
}
|
|
|
|
|
|
|
|
float32 HELPER(sfadd)(CPUHexagonState *env, float32 RsV, float32 RtV)
|
|
|
|
{
|
|
|
|
float32 RdV;
|
|
|
|
arch_fpop_start(env);
|
|
|
|
RdV = float32_add(RsV, RtV, &env->fp_status);
|
|
|
|
arch_fpop_end(env);
|
|
|
|
return RdV;
|
|
|
|
}
|
|
|
|
|
|
|
|
float32 HELPER(sfsub)(CPUHexagonState *env, float32 RsV, float32 RtV)
|
|
|
|
{
|
|
|
|
float32 RdV;
|
|
|
|
arch_fpop_start(env);
|
|
|
|
RdV = float32_sub(RsV, RtV, &env->fp_status);
|
|
|
|
arch_fpop_end(env);
|
|
|
|
return RdV;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t HELPER(sfcmpeq)(CPUHexagonState *env, float32 RsV, float32 RtV)
|
|
|
|
{
|
|
|
|
int32_t PdV;
|
|
|
|
arch_fpop_start(env);
|
|
|
|
PdV = f8BITSOF(float32_eq_quiet(RsV, RtV, &env->fp_status));
|
|
|
|
arch_fpop_end(env);
|
|
|
|
return PdV;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t HELPER(sfcmpgt)(CPUHexagonState *env, float32 RsV, float32 RtV)
|
|
|
|
{
|
|
|
|
int cmp;
|
|
|
|
int32_t PdV;
|
|
|
|
arch_fpop_start(env);
|
|
|
|
cmp = float32_compare_quiet(RsV, RtV, &env->fp_status);
|
|
|
|
PdV = f8BITSOF(cmp == float_relation_greater);
|
|
|
|
arch_fpop_end(env);
|
|
|
|
return PdV;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t HELPER(sfcmpge)(CPUHexagonState *env, float32 RsV, float32 RtV)
|
|
|
|
{
|
|
|
|
int cmp;
|
|
|
|
int32_t PdV;
|
|
|
|
arch_fpop_start(env);
|
|
|
|
cmp = float32_compare_quiet(RsV, RtV, &env->fp_status);
|
|
|
|
PdV = f8BITSOF(cmp == float_relation_greater ||
|
|
|
|
cmp == float_relation_equal);
|
|
|
|
arch_fpop_end(env);
|
|
|
|
return PdV;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t HELPER(sfcmpuo)(CPUHexagonState *env, float32 RsV, float32 RtV)
|
|
|
|
{
|
|
|
|
int32_t PdV;
|
|
|
|
arch_fpop_start(env);
|
2022-02-10 05:15:47 +03:00
|
|
|
PdV = f8BITSOF(float32_unordered_quiet(RsV, RtV, &env->fp_status));
|
2021-02-08 08:45:57 +03:00
|
|
|
arch_fpop_end(env);
|
|
|
|
return PdV;
|
|
|
|
}
|
|
|
|
|
|
|
|
float32 HELPER(sfmax)(CPUHexagonState *env, float32 RsV, float32 RtV)
|
|
|
|
{
|
|
|
|
float32 RdV;
|
|
|
|
arch_fpop_start(env);
|
2022-02-16 07:39:39 +03:00
|
|
|
RdV = float32_maximum_number(RsV, RtV, &env->fp_status);
|
2021-02-08 08:45:57 +03:00
|
|
|
arch_fpop_end(env);
|
|
|
|
return RdV;
|
|
|
|
}
|
|
|
|
|
|
|
|
float32 HELPER(sfmin)(CPUHexagonState *env, float32 RsV, float32 RtV)
|
|
|
|
{
|
|
|
|
float32 RdV;
|
|
|
|
arch_fpop_start(env);
|
2022-02-16 07:39:39 +03:00
|
|
|
RdV = float32_minimum_number(RsV, RtV, &env->fp_status);
|
2021-02-08 08:45:57 +03:00
|
|
|
arch_fpop_end(env);
|
|
|
|
return RdV;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t HELPER(sfclass)(CPUHexagonState *env, float32 RsV, int32_t uiV)
|
|
|
|
{
|
|
|
|
int32_t PdV = 0;
|
|
|
|
arch_fpop_start(env);
|
|
|
|
if (fGETBIT(0, uiV) && float32_is_zero(RsV)) {
|
|
|
|
PdV = 0xff;
|
|
|
|
}
|
|
|
|
if (fGETBIT(1, uiV) && float32_is_normal(RsV)) {
|
|
|
|
PdV = 0xff;
|
|
|
|
}
|
|
|
|
if (fGETBIT(2, uiV) && float32_is_denormal(RsV)) {
|
|
|
|
PdV = 0xff;
|
|
|
|
}
|
|
|
|
if (fGETBIT(3, uiV) && float32_is_infinity(RsV)) {
|
|
|
|
PdV = 0xff;
|
|
|
|
}
|
|
|
|
if (fGETBIT(4, uiV) && float32_is_any_nan(RsV)) {
|
|
|
|
PdV = 0xff;
|
|
|
|
}
|
|
|
|
set_float_exception_flags(0, &env->fp_status);
|
|
|
|
arch_fpop_end(env);
|
|
|
|
return PdV;
|
|
|
|
}
|
|
|
|
|
|
|
|
float32 HELPER(sffixupn)(CPUHexagonState *env, float32 RsV, float32 RtV)
|
|
|
|
{
|
|
|
|
float32 RdV = 0;
|
|
|
|
int adjust;
|
|
|
|
arch_fpop_start(env);
|
|
|
|
arch_sf_recip_common(&RsV, &RtV, &RdV, &adjust, &env->fp_status);
|
|
|
|
RdV = RsV;
|
|
|
|
arch_fpop_end(env);
|
|
|
|
return RdV;
|
|
|
|
}
|
|
|
|
|
|
|
|
float32 HELPER(sffixupd)(CPUHexagonState *env, float32 RsV, float32 RtV)
|
|
|
|
{
|
|
|
|
float32 RdV = 0;
|
|
|
|
int adjust;
|
|
|
|
arch_fpop_start(env);
|
|
|
|
arch_sf_recip_common(&RsV, &RtV, &RdV, &adjust, &env->fp_status);
|
|
|
|
RdV = RtV;
|
|
|
|
arch_fpop_end(env);
|
|
|
|
return RdV;
|
|
|
|
}
|
|
|
|
|
|
|
|
float32 HELPER(sffixupr)(CPUHexagonState *env, float32 RsV)
|
|
|
|
{
|
|
|
|
float32 RdV = 0;
|
|
|
|
int adjust;
|
|
|
|
arch_fpop_start(env);
|
|
|
|
arch_sf_invsqrt_common(&RsV, &RdV, &adjust, &env->fp_status);
|
|
|
|
RdV = RsV;
|
|
|
|
arch_fpop_end(env);
|
|
|
|
return RdV;
|
|
|
|
}
|
|
|
|
|
|
|
|
float64 HELPER(dfadd)(CPUHexagonState *env, float64 RssV, float64 RttV)
|
|
|
|
{
|
|
|
|
float64 RddV;
|
|
|
|
arch_fpop_start(env);
|
|
|
|
RddV = float64_add(RssV, RttV, &env->fp_status);
|
|
|
|
arch_fpop_end(env);
|
|
|
|
return RddV;
|
|
|
|
}
|
|
|
|
|
|
|
|
float64 HELPER(dfsub)(CPUHexagonState *env, float64 RssV, float64 RttV)
|
|
|
|
{
|
|
|
|
float64 RddV;
|
|
|
|
arch_fpop_start(env);
|
|
|
|
RddV = float64_sub(RssV, RttV, &env->fp_status);
|
|
|
|
arch_fpop_end(env);
|
|
|
|
return RddV;
|
|
|
|
}
|
|
|
|
|
|
|
|
float64 HELPER(dfmax)(CPUHexagonState *env, float64 RssV, float64 RttV)
|
|
|
|
{
|
|
|
|
float64 RddV;
|
|
|
|
arch_fpop_start(env);
|
2022-02-16 07:39:39 +03:00
|
|
|
RddV = float64_maximum_number(RssV, RttV, &env->fp_status);
|
2021-02-08 08:45:57 +03:00
|
|
|
arch_fpop_end(env);
|
|
|
|
return RddV;
|
|
|
|
}
|
|
|
|
|
|
|
|
float64 HELPER(dfmin)(CPUHexagonState *env, float64 RssV, float64 RttV)
|
|
|
|
{
|
|
|
|
float64 RddV;
|
|
|
|
arch_fpop_start(env);
|
2022-02-16 07:39:39 +03:00
|
|
|
RddV = float64_minimum_number(RssV, RttV, &env->fp_status);
|
2021-02-08 08:45:57 +03:00
|
|
|
arch_fpop_end(env);
|
|
|
|
return RddV;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t HELPER(dfcmpeq)(CPUHexagonState *env, float64 RssV, float64 RttV)
|
|
|
|
{
|
|
|
|
int32_t PdV;
|
|
|
|
arch_fpop_start(env);
|
|
|
|
PdV = f8BITSOF(float64_eq_quiet(RssV, RttV, &env->fp_status));
|
|
|
|
arch_fpop_end(env);
|
|
|
|
return PdV;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t HELPER(dfcmpgt)(CPUHexagonState *env, float64 RssV, float64 RttV)
|
|
|
|
{
|
|
|
|
int cmp;
|
|
|
|
int32_t PdV;
|
|
|
|
arch_fpop_start(env);
|
|
|
|
cmp = float64_compare_quiet(RssV, RttV, &env->fp_status);
|
|
|
|
PdV = f8BITSOF(cmp == float_relation_greater);
|
|
|
|
arch_fpop_end(env);
|
|
|
|
return PdV;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t HELPER(dfcmpge)(CPUHexagonState *env, float64 RssV, float64 RttV)
|
|
|
|
{
|
|
|
|
int cmp;
|
|
|
|
int32_t PdV;
|
|
|
|
arch_fpop_start(env);
|
|
|
|
cmp = float64_compare_quiet(RssV, RttV, &env->fp_status);
|
|
|
|
PdV = f8BITSOF(cmp == float_relation_greater ||
|
|
|
|
cmp == float_relation_equal);
|
|
|
|
arch_fpop_end(env);
|
|
|
|
return PdV;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t HELPER(dfcmpuo)(CPUHexagonState *env, float64 RssV, float64 RttV)
|
|
|
|
{
|
|
|
|
int32_t PdV;
|
|
|
|
arch_fpop_start(env);
|
2022-02-10 05:15:47 +03:00
|
|
|
PdV = f8BITSOF(float64_unordered_quiet(RssV, RttV, &env->fp_status));
|
2021-02-08 08:45:57 +03:00
|
|
|
arch_fpop_end(env);
|
|
|
|
return PdV;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t HELPER(dfclass)(CPUHexagonState *env, float64 RssV, int32_t uiV)
|
|
|
|
{
|
|
|
|
int32_t PdV = 0;
|
|
|
|
arch_fpop_start(env);
|
|
|
|
if (fGETBIT(0, uiV) && float64_is_zero(RssV)) {
|
|
|
|
PdV = 0xff;
|
|
|
|
}
|
|
|
|
if (fGETBIT(1, uiV) && float64_is_normal(RssV)) {
|
|
|
|
PdV = 0xff;
|
|
|
|
}
|
|
|
|
if (fGETBIT(2, uiV) && float64_is_denormal(RssV)) {
|
|
|
|
PdV = 0xff;
|
|
|
|
}
|
|
|
|
if (fGETBIT(3, uiV) && float64_is_infinity(RssV)) {
|
|
|
|
PdV = 0xff;
|
|
|
|
}
|
|
|
|
if (fGETBIT(4, uiV) && float64_is_any_nan(RssV)) {
|
|
|
|
PdV = 0xff;
|
|
|
|
}
|
|
|
|
set_float_exception_flags(0, &env->fp_status);
|
|
|
|
arch_fpop_end(env);
|
|
|
|
return PdV;
|
|
|
|
}
|
|
|
|
|
|
|
|
float32 HELPER(sfmpy)(CPUHexagonState *env, float32 RsV, float32 RtV)
|
|
|
|
{
|
|
|
|
float32 RdV;
|
|
|
|
arch_fpop_start(env);
|
|
|
|
RdV = internal_mpyf(RsV, RtV, &env->fp_status);
|
|
|
|
arch_fpop_end(env);
|
|
|
|
return RdV;
|
|
|
|
}
|
|
|
|
|
|
|
|
float32 HELPER(sffma)(CPUHexagonState *env, float32 RxV,
|
|
|
|
float32 RsV, float32 RtV)
|
|
|
|
{
|
|
|
|
arch_fpop_start(env);
|
|
|
|
RxV = internal_fmafx(RsV, RtV, RxV, 0, &env->fp_status);
|
|
|
|
arch_fpop_end(env);
|
|
|
|
return RxV;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool is_zero_prod(float32 a, float32 b)
|
|
|
|
{
|
|
|
|
return ((float32_is_zero(a) && is_finite(b)) ||
|
|
|
|
(float32_is_zero(b) && is_finite(a)));
|
|
|
|
}
|
|
|
|
|
|
|
|
static float32 check_nan(float32 dst, float32 x, float_status *fp_status)
|
|
|
|
{
|
|
|
|
float32 ret = dst;
|
|
|
|
if (float32_is_any_nan(x)) {
|
|
|
|
if (extract32(x, 22, 1) == 0) {
|
|
|
|
float_raise(float_flag_invalid, fp_status);
|
|
|
|
}
|
|
|
|
ret = make_float32(0xffffffff); /* nan */
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
float32 HELPER(sffma_sc)(CPUHexagonState *env, float32 RxV,
|
|
|
|
float32 RsV, float32 RtV, float32 PuV)
|
|
|
|
{
|
|
|
|
size4s_t tmp;
|
|
|
|
arch_fpop_start(env);
|
|
|
|
RxV = check_nan(RxV, RxV, &env->fp_status);
|
|
|
|
RxV = check_nan(RxV, RsV, &env->fp_status);
|
|
|
|
RxV = check_nan(RxV, RtV, &env->fp_status);
|
|
|
|
tmp = internal_fmafx(RsV, RtV, RxV, fSXTN(8, 64, PuV), &env->fp_status);
|
|
|
|
if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) {
|
|
|
|
RxV = tmp;
|
|
|
|
}
|
|
|
|
arch_fpop_end(env);
|
|
|
|
return RxV;
|
|
|
|
}
|
|
|
|
|
|
|
|
float32 HELPER(sffms)(CPUHexagonState *env, float32 RxV,
|
|
|
|
float32 RsV, float32 RtV)
|
|
|
|
{
|
|
|
|
float32 neg_RsV;
|
|
|
|
arch_fpop_start(env);
|
2023-03-07 05:58:25 +03:00
|
|
|
neg_RsV = float32_set_sign(RsV, float32_is_neg(RsV) ? 0 : 1);
|
2021-02-08 08:45:57 +03:00
|
|
|
RxV = internal_fmafx(neg_RsV, RtV, RxV, 0, &env->fp_status);
|
|
|
|
arch_fpop_end(env);
|
|
|
|
return RxV;
|
|
|
|
}
|
|
|
|
|
2021-04-09 04:07:31 +03:00
|
|
|
static bool is_inf_prod(int32_t a, int32_t b)
|
2021-02-08 08:45:57 +03:00
|
|
|
{
|
|
|
|
return (float32_is_infinity(a) && float32_is_infinity(b)) ||
|
|
|
|
(float32_is_infinity(a) && is_finite(b) && !float32_is_zero(b)) ||
|
|
|
|
(float32_is_infinity(b) && is_finite(a) && !float32_is_zero(a));
|
|
|
|
}
|
|
|
|
|
|
|
|
float32 HELPER(sffma_lib)(CPUHexagonState *env, float32 RxV,
|
|
|
|
float32 RsV, float32 RtV)
|
|
|
|
{
|
2021-04-09 04:07:35 +03:00
|
|
|
bool infinp;
|
|
|
|
bool infminusinf;
|
2021-02-08 08:45:57 +03:00
|
|
|
float32 tmp;
|
|
|
|
|
|
|
|
arch_fpop_start(env);
|
|
|
|
set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
|
|
|
|
infminusinf = float32_is_infinity(RxV) &&
|
|
|
|
is_inf_prod(RsV, RtV) &&
|
|
|
|
(fGETBIT(31, RsV ^ RxV ^ RtV) != 0);
|
|
|
|
infinp = float32_is_infinity(RxV) ||
|
|
|
|
float32_is_infinity(RtV) ||
|
|
|
|
float32_is_infinity(RsV);
|
|
|
|
RxV = check_nan(RxV, RxV, &env->fp_status);
|
|
|
|
RxV = check_nan(RxV, RsV, &env->fp_status);
|
|
|
|
RxV = check_nan(RxV, RtV, &env->fp_status);
|
|
|
|
tmp = internal_fmafx(RsV, RtV, RxV, 0, &env->fp_status);
|
|
|
|
if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) {
|
|
|
|
RxV = tmp;
|
|
|
|
}
|
|
|
|
set_float_exception_flags(0, &env->fp_status);
|
|
|
|
if (float32_is_infinity(RxV) && !infinp) {
|
|
|
|
RxV = RxV - 1;
|
|
|
|
}
|
|
|
|
if (infminusinf) {
|
|
|
|
RxV = 0;
|
|
|
|
}
|
|
|
|
arch_fpop_end(env);
|
|
|
|
return RxV;
|
|
|
|
}
|
|
|
|
|
|
|
|
float32 HELPER(sffms_lib)(CPUHexagonState *env, float32 RxV,
|
|
|
|
float32 RsV, float32 RtV)
|
|
|
|
{
|
2021-04-09 04:07:35 +03:00
|
|
|
bool infinp;
|
|
|
|
bool infminusinf;
|
2021-02-08 08:45:57 +03:00
|
|
|
float32 tmp;
|
|
|
|
|
|
|
|
arch_fpop_start(env);
|
|
|
|
set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
|
|
|
|
infminusinf = float32_is_infinity(RxV) &&
|
|
|
|
is_inf_prod(RsV, RtV) &&
|
|
|
|
(fGETBIT(31, RsV ^ RxV ^ RtV) == 0);
|
|
|
|
infinp = float32_is_infinity(RxV) ||
|
|
|
|
float32_is_infinity(RtV) ||
|
|
|
|
float32_is_infinity(RsV);
|
|
|
|
RxV = check_nan(RxV, RxV, &env->fp_status);
|
|
|
|
RxV = check_nan(RxV, RsV, &env->fp_status);
|
|
|
|
RxV = check_nan(RxV, RtV, &env->fp_status);
|
|
|
|
float32 minus_RsV = float32_sub(float32_zero, RsV, &env->fp_status);
|
|
|
|
tmp = internal_fmafx(minus_RsV, RtV, RxV, 0, &env->fp_status);
|
|
|
|
if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) {
|
|
|
|
RxV = tmp;
|
|
|
|
}
|
|
|
|
set_float_exception_flags(0, &env->fp_status);
|
|
|
|
if (float32_is_infinity(RxV) && !infinp) {
|
|
|
|
RxV = RxV - 1;
|
|
|
|
}
|
|
|
|
if (infminusinf) {
|
|
|
|
RxV = 0;
|
|
|
|
}
|
|
|
|
arch_fpop_end(env);
|
|
|
|
return RxV;
|
|
|
|
}
|
|
|
|
|
|
|
|
float64 HELPER(dfmpyfix)(CPUHexagonState *env, float64 RssV, float64 RttV)
|
|
|
|
{
|
|
|
|
int64_t RddV;
|
|
|
|
arch_fpop_start(env);
|
|
|
|
if (float64_is_denormal(RssV) &&
|
|
|
|
(float64_getexp(RttV) >= 512) &&
|
|
|
|
float64_is_normal(RttV)) {
|
|
|
|
RddV = float64_mul(RssV, make_float64(0x4330000000000000),
|
|
|
|
&env->fp_status);
|
|
|
|
} else if (float64_is_denormal(RttV) &&
|
|
|
|
(float64_getexp(RssV) >= 512) &&
|
|
|
|
float64_is_normal(RssV)) {
|
|
|
|
RddV = float64_mul(RssV, make_float64(0x3cb0000000000000),
|
|
|
|
&env->fp_status);
|
|
|
|
} else {
|
|
|
|
RddV = RssV;
|
|
|
|
}
|
|
|
|
arch_fpop_end(env);
|
|
|
|
return RddV;
|
|
|
|
}
|
|
|
|
|
|
|
|
float64 HELPER(dfmpyhh)(CPUHexagonState *env, float64 RxxV,
|
|
|
|
float64 RssV, float64 RttV)
|
|
|
|
{
|
|
|
|
arch_fpop_start(env);
|
|
|
|
RxxV = internal_mpyhh(RssV, RttV, RxxV, &env->fp_status);
|
|
|
|
arch_fpop_end(env);
|
|
|
|
return RxxV;
|
|
|
|
}
|
|
|
|
|
2021-09-30 19:07:00 +03:00
|
|
|
/* Histogram instructions */
|
|
|
|
|
|
|
|
void HELPER(vhist)(CPUHexagonState *env)
|
|
|
|
{
|
|
|
|
MMVector *input = &env->tmp_VRegs[0];
|
|
|
|
|
|
|
|
for (int lane = 0; lane < 8; lane++) {
|
|
|
|
for (int i = 0; i < sizeof(MMVector) / 8; ++i) {
|
|
|
|
unsigned char value = input->ub[(sizeof(MMVector) / 8) * lane + i];
|
|
|
|
unsigned char regno = value >> 3;
|
|
|
|
unsigned char element = value & 7;
|
|
|
|
|
|
|
|
env->VRegs[regno].uh[(sizeof(MMVector) / 16) * lane + element]++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void HELPER(vhistq)(CPUHexagonState *env)
|
|
|
|
{
|
|
|
|
MMVector *input = &env->tmp_VRegs[0];
|
|
|
|
|
|
|
|
for (int lane = 0; lane < 8; lane++) {
|
|
|
|
for (int i = 0; i < sizeof(MMVector) / 8; ++i) {
|
|
|
|
unsigned char value = input->ub[(sizeof(MMVector) / 8) * lane + i];
|
|
|
|
unsigned char regno = value >> 3;
|
|
|
|
unsigned char element = value & 7;
|
|
|
|
|
|
|
|
if (fGETQBIT(env->qtmp, sizeof(MMVector) / 8 * lane + i)) {
|
|
|
|
env->VRegs[regno].uh[
|
|
|
|
(sizeof(MMVector) / 16) * lane + element]++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void HELPER(vwhist256)(CPUHexagonState *env)
|
|
|
|
{
|
|
|
|
MMVector *input = &env->tmp_VRegs[0];
|
|
|
|
|
|
|
|
for (int i = 0; i < (sizeof(MMVector) / 2); i++) {
|
|
|
|
unsigned int bucket = fGETUBYTE(0, input->h[i]);
|
|
|
|
unsigned int weight = fGETUBYTE(1, input->h[i]);
|
|
|
|
unsigned int vindex = (bucket >> 3) & 0x1F;
|
|
|
|
unsigned int elindex = ((i >> 0) & (~7)) | ((bucket >> 0) & 7);
|
|
|
|
|
|
|
|
env->VRegs[vindex].uh[elindex] =
|
|
|
|
env->VRegs[vindex].uh[elindex] + weight;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void HELPER(vwhist256q)(CPUHexagonState *env)
|
|
|
|
{
|
|
|
|
MMVector *input = &env->tmp_VRegs[0];
|
|
|
|
|
|
|
|
for (int i = 0; i < (sizeof(MMVector) / 2); i++) {
|
|
|
|
unsigned int bucket = fGETUBYTE(0, input->h[i]);
|
|
|
|
unsigned int weight = fGETUBYTE(1, input->h[i]);
|
|
|
|
unsigned int vindex = (bucket >> 3) & 0x1F;
|
|
|
|
unsigned int elindex = ((i >> 0) & (~7)) | ((bucket >> 0) & 7);
|
|
|
|
|
|
|
|
if (fGETQBIT(env->qtmp, 2 * i)) {
|
|
|
|
env->VRegs[vindex].uh[elindex] =
|
|
|
|
env->VRegs[vindex].uh[elindex] + weight;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void HELPER(vwhist256_sat)(CPUHexagonState *env)
|
|
|
|
{
|
|
|
|
MMVector *input = &env->tmp_VRegs[0];
|
|
|
|
|
|
|
|
for (int i = 0; i < (sizeof(MMVector) / 2); i++) {
|
|
|
|
unsigned int bucket = fGETUBYTE(0, input->h[i]);
|
|
|
|
unsigned int weight = fGETUBYTE(1, input->h[i]);
|
|
|
|
unsigned int vindex = (bucket >> 3) & 0x1F;
|
|
|
|
unsigned int elindex = ((i >> 0) & (~7)) | ((bucket >> 0) & 7);
|
|
|
|
|
|
|
|
env->VRegs[vindex].uh[elindex] =
|
|
|
|
fVSATUH(env->VRegs[vindex].uh[elindex] + weight);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void HELPER(vwhist256q_sat)(CPUHexagonState *env)
|
|
|
|
{
|
|
|
|
MMVector *input = &env->tmp_VRegs[0];
|
|
|
|
|
|
|
|
for (int i = 0; i < (sizeof(MMVector) / 2); i++) {
|
|
|
|
unsigned int bucket = fGETUBYTE(0, input->h[i]);
|
|
|
|
unsigned int weight = fGETUBYTE(1, input->h[i]);
|
|
|
|
unsigned int vindex = (bucket >> 3) & 0x1F;
|
|
|
|
unsigned int elindex = ((i >> 0) & (~7)) | ((bucket >> 0) & 7);
|
|
|
|
|
|
|
|
if (fGETQBIT(env->qtmp, 2 * i)) {
|
|
|
|
env->VRegs[vindex].uh[elindex] =
|
|
|
|
fVSATUH(env->VRegs[vindex].uh[elindex] + weight);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void HELPER(vwhist128)(CPUHexagonState *env)
|
|
|
|
{
|
|
|
|
MMVector *input = &env->tmp_VRegs[0];
|
|
|
|
|
|
|
|
for (int i = 0; i < (sizeof(MMVector) / 2); i++) {
|
|
|
|
unsigned int bucket = fGETUBYTE(0, input->h[i]);
|
|
|
|
unsigned int weight = fGETUBYTE(1, input->h[i]);
|
|
|
|
unsigned int vindex = (bucket >> 3) & 0x1F;
|
|
|
|
unsigned int elindex = ((i >> 1) & (~3)) | ((bucket >> 1) & 3);
|
|
|
|
|
|
|
|
env->VRegs[vindex].uw[elindex] =
|
|
|
|
env->VRegs[vindex].uw[elindex] + weight;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void HELPER(vwhist128q)(CPUHexagonState *env)
|
|
|
|
{
|
|
|
|
MMVector *input = &env->tmp_VRegs[0];
|
|
|
|
|
|
|
|
for (int i = 0; i < (sizeof(MMVector) / 2); i++) {
|
|
|
|
unsigned int bucket = fGETUBYTE(0, input->h[i]);
|
|
|
|
unsigned int weight = fGETUBYTE(1, input->h[i]);
|
|
|
|
unsigned int vindex = (bucket >> 3) & 0x1F;
|
|
|
|
unsigned int elindex = ((i >> 1) & (~3)) | ((bucket >> 1) & 3);
|
|
|
|
|
|
|
|
if (fGETQBIT(env->qtmp, 2 * i)) {
|
|
|
|
env->VRegs[vindex].uw[elindex] =
|
|
|
|
env->VRegs[vindex].uw[elindex] + weight;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void HELPER(vwhist128m)(CPUHexagonState *env, int32_t uiV)
|
|
|
|
{
|
|
|
|
MMVector *input = &env->tmp_VRegs[0];
|
|
|
|
|
|
|
|
for (int i = 0; i < (sizeof(MMVector) / 2); i++) {
|
|
|
|
unsigned int bucket = fGETUBYTE(0, input->h[i]);
|
|
|
|
unsigned int weight = fGETUBYTE(1, input->h[i]);
|
|
|
|
unsigned int vindex = (bucket >> 3) & 0x1F;
|
|
|
|
unsigned int elindex = ((i >> 1) & (~3)) | ((bucket >> 1) & 3);
|
|
|
|
|
|
|
|
if ((bucket & 1) == uiV) {
|
|
|
|
env->VRegs[vindex].uw[elindex] =
|
|
|
|
env->VRegs[vindex].uw[elindex] + weight;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void HELPER(vwhist128qm)(CPUHexagonState *env, int32_t uiV)
|
|
|
|
{
|
|
|
|
MMVector *input = &env->tmp_VRegs[0];
|
|
|
|
|
|
|
|
for (int i = 0; i < (sizeof(MMVector) / 2); i++) {
|
|
|
|
unsigned int bucket = fGETUBYTE(0, input->h[i]);
|
|
|
|
unsigned int weight = fGETUBYTE(1, input->h[i]);
|
|
|
|
unsigned int vindex = (bucket >> 3) & 0x1F;
|
|
|
|
unsigned int elindex = ((i >> 1) & (~3)) | ((bucket >> 1) & 3);
|
|
|
|
|
|
|
|
if (((bucket & 1) == uiV) && fGETQBIT(env->qtmp, 2 * i)) {
|
|
|
|
env->VRegs[vindex].uw[elindex] =
|
|
|
|
env->VRegs[vindex].uw[elindex] + weight;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-08 08:45:57 +03:00
|
|
|
/* These macros can be referenced in the generated helper functions */
|
|
|
|
#define warn(...) /* Nothing */
|
|
|
|
#define fatal(...) g_assert_not_reached();
|
|
|
|
|
|
|
|
#define BOGUS_HELPER(tag) \
|
|
|
|
printf("ERROR: bogus helper: " #tag "\n")
|
|
|
|
|
|
|
|
#include "helper_funcs_generated.c.inc"
|