On 8/10/23 05:41, Song Gao wrote:
This patch adds REQUIRE_FP/FP_SP/FP_DP to check CPUCFG2.FP/FP_SP/FP_DP.
Signed-off-by: Song Gao <gaos...@loongson.cn>
---
target/loongarch/cpu.h | 6 +
.../loongarch/insn_trans/trans_farith.c.inc | 132 ++++++++++++------
target/loongarch/insn_trans/trans_fcmp.c.inc | 4 +
target/loongarch/insn_trans/trans_fcnv.c.inc | 56 ++++----
.../loongarch/insn_trans/trans_fmemory.c.inc | 104 ++++++++++----
target/loongarch/insn_trans/trans_fmov.c.inc | 47 +++++--
6 files changed, 247 insertions(+), 102 deletions(-)
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index 9f550793ca..5594d83011 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -459,6 +459,9 @@ static inline void set_pc(CPULoongArchState *env,
uint64_t value)
#define HW_FLAGS_EUEN_FPE 0x04
#define HW_FLAGS_EUEN_SXE 0x08
#define HW_FLAGS_VA32 0x20
+#define HW_FLAGS_FP 0x40
+#define HW_FLAGS_FP_SP 0x80
+#define HW_FLAGS_FP_DP 0x100
static inline void cpu_get_tb_cpu_state(CPULoongArchState *env,
vaddr *pc,
uint64_t *cs_base, uint32_t
*flags)
@@ -469,6 +472,9 @@ static inline void
cpu_get_tb_cpu_state(CPULoongArchState *env, vaddr *pc,
*flags |= FIELD_EX64(env->CSR_EUEN, CSR_EUEN, FPE) *
HW_FLAGS_EUEN_FPE;
*flags |= FIELD_EX64(env->CSR_EUEN, CSR_EUEN, SXE) *
HW_FLAGS_EUEN_SXE;
*flags |= is_va32(env) * HW_FLAGS_VA32;
+ *flags |= FIELD_EX32(env->cpucfg[2], CPUCFG2, FP) * HW_FLAGS_FP;
+ *flags |= FIELD_EX32(env->cpucfg[2], CPUCFG2, FP_SP) *
HW_FLAGS_FP_SP;
+ *flags |= FIELD_EX32(env->cpucfg[2], CPUCFG2, FP_DP) *
HW_FLAGS_FP_DP;
You do not need to put any of these in HW_FLAGS, because CPUCFG space
never changes for the lifetime of the cpu.
You can extract these into DisasContext in loongarch_tr_init_disas_context.
+#define REQUIRE_FP do { \
+ if ((ctx->base.tb->flags & HW_FLAGS_FP) == 0) { \
+ return false; \
+ } \
+} while (0)
+
+#define REQUIRE_FP_SP do { \
+ if ((ctx->base.tb->flags & HW_FLAGS_FP_SP) == 0) { \
+ return false; \
+ } \
+} while (0)
+
+#define REQUIRE_FP_DP do { \
+ if ((ctx->base.tb->flags & HW_FLAGS_FP_DP) == 0) { \
+ return false; \
+ } \
+} while (0)
It would be much better to not create so many of these REQUIRE macros.
+TRANS(fadd_s, gen_fff, 0, gen_helper_fadd_s)
+TRANS(fadd_d, gen_fff, 1, gen_helper_fadd_d)
0 vs 1 is very opaque.
Better is something like Jiajie Chen's TRANS_64,
+/* for LoongArch64-only instructions */
+#define TRANS_64(NAME, FUNC, ...) \
+ static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+ { \
+ return ctx->la64 && FUNC(ctx, a, __VA_ARGS__); \
+ }
But as we now know, we would need at least 7 of these.
Even better would be to generalize this so that every instruction
records the condition under which it is valid.
Perhaps
typedef struct DisasContext {
...
uint32_t cpucfg1;
uint32_t cpucfg2;
};
static void loongarch_tr_init_disas_context(...)
{
...
ctx->cpucfg1 = env->cpucfg[1];
ctx->cpucfg2 = env->cpucfg[2];
}
#define avail_ALL(C) true
#define avail_64(C) FIELD_EX32((C)->cpucfg1, CPUCFG1, ARCH) ==
CPUCFG1_ARCH_LA64
#define avail_FP(C) FIELD_EX32((C)->cpucfg2, CPUCFG2, FP)
etc
#define TRANS(NAME, AVAIL, FUNC, ...) \
static bool trans_##NAME(DisasContext *ctx, arg_##NAME *a) \
{ return avail_##AVAIL(ctx) && FUNC(ctx, a, __VA_ARGS__); }
so that the above becomes
TRANS(fadd_s, FP_SP, gen_fff, gen_helper_fadd_s)
TRANS(fadd_d, FP_DP, gen_fff, gen_helper_fadd_d)
and even simple instructions get
TRANS(add_w, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_SIGN, tcg_gen_add_tl)
TRANS(add_d, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_SIGN, tcg_gen_add_tl)