From 9e8c927036ea32989ce422b43cdd56bc86bd04d8 Mon Sep 17 00:00:00 2001 From: Denis Drakhnya Date: Sun, 24 Jan 2021 21:00:43 +0200 Subject: [PATCH] e2k: Add delayed window bounds static/dynamic checks. --- target/e2k/translate.c | 76 +++++++++++++++++++++- target/e2k/translate.h | 7 +- target/e2k/translate/alc.c | 115 +++++++++++++++++++++++++++++---- target/e2k/translate/alops.inc | 1 - 4 files changed, 184 insertions(+), 15 deletions(-) diff --git a/target/e2k/translate.c b/target/e2k/translate.c index 77299f17d7..d5fad0e27c 100644 --- a/target/e2k/translate.c +++ b/target/e2k/translate.c @@ -533,6 +533,7 @@ static inline void gen_setwd(DisasContext *ctx) TCGv_i32 t0 = tcg_const_i32(setr->wsz); TCGv_i32 t1 = tcg_const_i32(setr->nfx); TCGv_i32 t2 = tcg_const_i32(setr->dbl); + ctx->wd_size = setr->wsz * 2; gen_helper_setwd(cpu_env, t0, t1, t2); tcg_temp_free_i32(t2); tcg_temp_free_i32(t1); @@ -546,6 +547,7 @@ static inline void gen_setbn(DisasContext *ctx) Cs1Setr *setr = &cs1->setr; if (cs1->type == CS1_SETR && (setr->type & SETR_BN)) { + ctx->bsize = (setr->rsz + 1) * 2; tcg_gen_movi_i32(e2k_cs.boff, setr->rbs * 2); tcg_gen_movi_i32(e2k_cs.bsize, (setr->rsz + 1) * 2); tcg_gen_movi_i32(e2k_cs.bcur, setr->rcur * 2); @@ -923,6 +925,64 @@ static inline target_ulong do_decode(DisasContext *ctx, CPUState *cs) return ctx->pc + len; } +static inline void gen_maperr_condi_i32(TCGCond cond, TCGv_i32 arg1, int arg2) +{ + TCGLabel *l0 = gen_new_label(); + tcg_gen_brcondi_i32(tcg_invert_cond(cond), arg1, arg2, l0); + e2k_gen_exception(E2K_EXCP_MAPERR); + gen_set_label(l0); +} + +static inline void do_checks(DisasContext *ctx) +{ + const Bundle *b = &ctx->bundle2; + const Cs1Setr *setr = &b->cs1.setr; + + if (ctx->wd_size != DYNAMIC) { + /* %rN src static check */ + if (ctx->wd_size <= ctx->max_r_src) { + e2k_tr_gen_exception(ctx, E2K_EXCP_MAPERR); + } + /* %rN dst static check */ + if (b->cs1.type == CS1_SETR && (setr->type & SETR_WD)) { + if (setr->wsz * 2 <= ctx->max_r_dst) { + e2k_tr_gen_exception(ctx, E2K_EXCP_MAPERR); + } + } else if (ctx->wd_size <= ctx->max_r_dst) { + e2k_tr_gen_exception(ctx, E2K_EXCP_MAPERR); + } + } else if (b->cs1.type == CS1_SETR && (setr->type & SETR_WD)) { + /* %rN src dynamic check */ + if (ctx->max_r < ctx->max_r_src) { + ctx->max_r = ctx->max_r_src; + gen_maperr_condi_i32(TCG_COND_LE, e2k_cs.wd_size, ctx->max_r_src); + } + + /* %rN dst static check */ + if (setr->wsz * 2 <= ctx->max_r_dst) { + e2k_tr_gen_exception(ctx, E2K_EXCP_MAPERR); + } + } else { + /* %rN src/dst dynamic check */ + int max = MAX(ctx->max_r_src, ctx->max_r_dst); + if (ctx->max_r < max) { + ctx->max_r = max; + gen_maperr_condi_i32(TCG_COND_LE, e2k_cs.wd_size, max); + } + } + + if (ctx->bsize != DYNAMIC) { + /* %b[N] src/dst static check */ + if (ctx->bsize <= ctx->max_b_cur) { + e2k_tr_gen_exception(ctx, E2K_EXCP_MAPERR); + } + } else if (ctx->max_b < ctx->max_b_cur) { + /* %b[N] src/dst dynamic check */ + ctx->max_b = ctx->max_b_cur; + gen_maperr_condi_i32(TCG_COND_LE, e2k_cs.bsize, ctx->max_b); + } +} + /* * Executes instructions from a bundle and store the results to * temporary buffer. @@ -1040,10 +1100,18 @@ static void e2k_tr_init_disas_context(DisasContextBase *db, CPUState *cs) static void e2k_tr_tb_start(DisasContextBase *db, CPUState *cs) { -// DisasContext *ctx = container_of(db, DisasContext, base); + DisasContext *ctx = container_of(db, DisasContext, base); E2KCPU *cpu = E2K_CPU(cs); CPUE2KState *env = &cpu->env; + ctx->wd_size = DYNAMIC; + ctx->max_r = -1; + ctx->max_r_src = -1; + ctx->max_r_dst = -1; + ctx->bsize = DYNAMIC; + ctx->max_b = -1; + ctx->max_b_cur = -1; + tcg_gen_movi_i32(e2k_cs.ct_cond, 0); if (env->is_bp) { @@ -1062,6 +1130,11 @@ static void e2k_tr_insn_start(DisasContextBase *db, CPUState *cs) memset(ctx->mas, 0, sizeof(ctx->mas)); memset(&ctx->bundle2, 0, sizeof(ctx->bundle2)); + + ctx->max_r_src = -1; + ctx->max_r_dst = -1; + ctx->max_b_cur = -1; + ctx->do_check_illtag = false; ctx->illtag = e2k_get_temp_i32(ctx); tcg_gen_movi_i32(ctx->illtag, 0); @@ -1074,6 +1147,7 @@ static void e2k_tr_translate_insn(DisasContextBase *db, CPUState *cs) pc_next = do_decode(ctx, cs); do_execute(ctx); + do_checks(ctx); do_commit(ctx); do_branch(ctx, pc_next); diff --git a/target/e2k/translate.h b/target/e2k/translate.h index 1b519006ca..7a04d8c3a7 100644 --- a/target/e2k/translate.h +++ b/target/e2k/translate.h @@ -4,6 +4,8 @@ #include "tcg/tcg-op.h" #include "exec/translator.h" +#define DYNAMIC -1 + #define IS_BASED(i) (((i) & 0x80) == 0) #define IS_REGULAR(i) (((i) & 0xc0) == 0x80) #define IS_IMM5(i) (((i) & 0xe0) == 0xc0) @@ -355,8 +357,11 @@ typedef struct DisasContext { bool do_check_illtag; /* Delayed window bounds check */ + int wd_size; int max_r; - int max_r_cur; + int max_r_src; + int max_r_dst; + int bsize; int max_b; int max_b_cur; diff --git a/target/e2k/translate/alc.c b/target/e2k/translate/alc.c index 29076d56b2..13b831c035 100644 --- a/target/e2k/translate/alc.c +++ b/target/e2k/translate/alc.c @@ -1462,7 +1462,7 @@ static inline void gen_puttag_i32(Instr *instr) set_al_result_reg32_tag(instr, dst, tag, false, false); } -static inline void gen_insert_field_i64(TCGv_i64 ret, TCGv_i64 src1, +static inline void gen_insfd(TCGv_i64 ret, TCGv_i64 src1, TCGv_i64 src2, TCGv_i64 src3) { TCGv_i64 one = tcg_const_i64(1); @@ -1496,7 +1496,7 @@ static inline void gen_insert_field_i64(TCGv_i64 ret, TCGv_i64 src1, tcg_temp_free_i64(one); } -static inline void gen_insert_field_i32(TCGv_i32 ret, TCGv_i32 src1, +static inline void gen_insfs(TCGv_i32 ret, TCGv_i32 src1, TCGv_i32 src2, TCGv_i32 src3) { TCGv_i32 one = tcg_const_i32(1); @@ -2922,7 +2922,7 @@ static inline void gen_alopf2_dx(Instr *instr, gen_al_result_i80(instr, res.lo, res.hi, res.tag); } -static Alop find_op(Instr *instr) +static AlopDesc *find_op(Instr *instr) { /* ALES2/5 may be allocated but must not be used */ int opc2 = instr->ales_present & ALES_PRESENT ? instr->opc2 : 0; @@ -2965,25 +2965,109 @@ static Alop find_op(Instr *instr) case ALOPF16: is_match = desc->extra1 == instr->opce2; break; + default: + g_assert_not_reached(); + break; } if (is_match) { - return desc->op; + return desc; } index = desc->next[instr->chan]; } - return OP_NONE; + return NULL; +} + +static inline void check_reg_src(DisasContext *ctx, uint8_t src) +{ + if (IS_REGULAR(src)) { + ctx->max_r_src = MAX(ctx->max_r_src, GET_REGULAR(src)); + } else if (IS_BASED(src)) { + ctx->max_b_cur = MAX(ctx->max_b_cur, GET_BASED(src)); + } +} + +static inline void check_reg_dst(DisasContext *ctx, uint8_t dst) +{ + if (IS_REGULAR(dst)) { + ctx->max_r_dst = MAX(ctx->max_r_dst, GET_REGULAR(dst)); + } else if (IS_BASED(dst)) { + ctx->max_b_cur = MAX(ctx->max_b_cur, GET_BASED(dst)); + } +} + +static void check_args(Alopf alopf, Instr *instr) +{ + DisasContext *ctx = instr->ctx; + + switch(alopf) { + case ALOPF1: + case ALOPF1_MERGE: + case ALOPF11: + case ALOPF11_MERGE: + case ALOPF11_LIT8: + check_reg_src(ctx, instr->src1); + check_reg_src(ctx, instr->src2); + check_reg_dst(ctx, instr->dst); + break; + case ALOPF2: + case ALOPF12: + case ALOPF12_PSHUFH: + case ALOPF15: + case ALOPF22: + check_reg_src(ctx, instr->src2); + check_reg_dst(ctx, instr->dst); + break; + case ALOPF3: + check_reg_src(ctx, instr->src1); + check_reg_src(ctx, instr->src2); + check_reg_src(ctx, instr->src4); + break; + case ALOPF7: + case ALOPF17: + check_reg_src(ctx, instr->src1); + check_reg_src(ctx, instr->src2); + break; + case ALOPF8: + check_reg_src(ctx, instr->src2); + break; + case ALOPF10: + check_reg_src(ctx, instr->src4); + break; + case ALOPF13: + // FIXME: not tested + e2k_todo(ctx, "check_args ALOPF13"); + check_reg_src(ctx, instr->src1); + check_reg_src(ctx, instr->src2); + check_reg_src(ctx, instr->src4); + break; + case ALOPF16: + check_reg_dst(ctx, instr->dst); + break; + case ALOPF21: + check_reg_src(ctx, instr->src1); + check_reg_src(ctx, instr->src2); + check_reg_src(ctx, instr->src3); + check_reg_dst(ctx, instr->dst); + break; + default: + e2k_todo(ctx, "check_args %d", alopf); + break; + } } static void gen_op(DisasContext *ctx, Instr *instr) { int chan = instr->chan; - Alop op = find_op(instr); - - switch(op) { - case OP_NONE: e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPC); break; + AlopDesc *desc = find_op(instr); + if (desc == NULL) { + e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPC); + return; + } + check_args(desc->alopf, instr); + switch(desc->op) { case OP_ANDS: gen_alopf1_sss(instr, tcg_gen_and_i32); break; case OP_ANDD: gen_alopf1_ddd(instr, tcg_gen_and_i64); break; case OP_ANDNS: gen_alopf1_sss(instr, gen_andn_i32); break; @@ -3809,7 +3893,7 @@ static void gen_op(DisasContext *ctx, Instr *instr) case OP_QPFMSAS: case OP_QPFMASD: case OP_QPFMSAD: - e2k_todo_illop(ctx, "unimplemented %d\n", op); break; + e2k_todo_illop(ctx, "unimplemented %d\n", desc->op); break; } } @@ -4245,18 +4329,21 @@ static void gen_icmb3(DisasContext *ctx, Instr *instr) case 0x6c: if (is_chan_0134(instr->chan) && ctx->version >= 4) { /* insfs */ - gen_alopf21_i32(ctx, instr, gen_insert_field_i32); + check_args(ALOPF21, instr); + gen_alopf21_i32(ctx, instr, gen_insfs); return; } break; case 0x6d: if (is_chan_0134(instr->chan) && ctx->version>= 4) { /* insfd */ - gen_alopf21_i64(ctx, instr, gen_insert_field_i64); + check_args(ALOPF21, instr); + gen_alopf21_i64(ctx, instr, gen_insfd); return; } break; default: + check_args(ALOPF21, instr); gen_icmb012(ctx, instr); break; } @@ -4408,6 +4495,8 @@ gen_illopc: static void gen_fcmb(DisasContext *ctx, Instr *instr) { + check_args(ALOPF21, instr); + if (instr->opc1 & 1) { execute_fcomb_i64(ctx, instr); } else { @@ -4421,6 +4510,7 @@ static void gen_pfcmb1(DisasContext *ctx, Instr *instr) case 0x4d: if (is_chan_0134(instr->chan) && ctx->version >= 2) { /* pshufb */ + check_args(ALOPF21, instr); gen_alopf21_i64(ctx, instr, gen_helper_pshufb); return; } @@ -4443,6 +4533,7 @@ static void gen_lcmbd(DisasContext *ctx, Instr *instr, uint32_t base) TCGv_i64 dst = e2k_get_temp_i64(ctx); TCGv_i32 opc = tcg_const_i32(base + instr->opc1); + check_args(ALOPF21, instr); gen_tag3_i64(tag, s1.tag, s2.tag, s3.tag); gen_helper_plog(dst, opc, s1.value, s2.value, s3.value); gen_al_result_i64(instr, dst, tag); diff --git a/target/e2k/translate/alops.inc b/target/e2k/translate/alops.inc index 51dfb46d44..e1372da986 100644 --- a/target/e2k/translate/alops.inc +++ b/target/e2k/translate/alops.inc @@ -1,5 +1,4 @@ typedef enum { - OP_NONE, OP_ANDS, OP_ANDD, OP_ANDNS,