e2k: Add delayed window bounds static/dynamic checks.

This commit is contained in:
Denis Drakhnia 2021-01-24 21:00:43 +02:00 committed by Denis Drakhnia
parent f56cad7923
commit 9e8c927036
4 changed files with 184 additions and 15 deletions

View File

@ -533,6 +533,7 @@ static inline void gen_setwd(DisasContext *ctx)
TCGv_i32 t0 = tcg_const_i32(setr->wsz); TCGv_i32 t0 = tcg_const_i32(setr->wsz);
TCGv_i32 t1 = tcg_const_i32(setr->nfx); TCGv_i32 t1 = tcg_const_i32(setr->nfx);
TCGv_i32 t2 = tcg_const_i32(setr->dbl); TCGv_i32 t2 = tcg_const_i32(setr->dbl);
ctx->wd_size = setr->wsz * 2;
gen_helper_setwd(cpu_env, t0, t1, t2); gen_helper_setwd(cpu_env, t0, t1, t2);
tcg_temp_free_i32(t2); tcg_temp_free_i32(t2);
tcg_temp_free_i32(t1); tcg_temp_free_i32(t1);
@ -546,6 +547,7 @@ static inline void gen_setbn(DisasContext *ctx)
Cs1Setr *setr = &cs1->setr; Cs1Setr *setr = &cs1->setr;
if (cs1->type == CS1_SETR && (setr->type & SETR_BN)) { 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.boff, setr->rbs * 2);
tcg_gen_movi_i32(e2k_cs.bsize, (setr->rsz + 1) * 2); tcg_gen_movi_i32(e2k_cs.bsize, (setr->rsz + 1) * 2);
tcg_gen_movi_i32(e2k_cs.bcur, setr->rcur * 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; 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 * Executes instructions from a bundle and store the results to
* temporary buffer. * 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) 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); E2KCPU *cpu = E2K_CPU(cs);
CPUE2KState *env = &cpu->env; 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); tcg_gen_movi_i32(e2k_cs.ct_cond, 0);
if (env->is_bp) { 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->mas, 0, sizeof(ctx->mas));
memset(&ctx->bundle2, 0, sizeof(ctx->bundle2)); 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->do_check_illtag = false;
ctx->illtag = e2k_get_temp_i32(ctx); ctx->illtag = e2k_get_temp_i32(ctx);
tcg_gen_movi_i32(ctx->illtag, 0); 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); pc_next = do_decode(ctx, cs);
do_execute(ctx); do_execute(ctx);
do_checks(ctx);
do_commit(ctx); do_commit(ctx);
do_branch(ctx, pc_next); do_branch(ctx, pc_next);

View File

@ -4,6 +4,8 @@
#include "tcg/tcg-op.h" #include "tcg/tcg-op.h"
#include "exec/translator.h" #include "exec/translator.h"
#define DYNAMIC -1
#define IS_BASED(i) (((i) & 0x80) == 0) #define IS_BASED(i) (((i) & 0x80) == 0)
#define IS_REGULAR(i) (((i) & 0xc0) == 0x80) #define IS_REGULAR(i) (((i) & 0xc0) == 0x80)
#define IS_IMM5(i) (((i) & 0xe0) == 0xc0) #define IS_IMM5(i) (((i) & 0xe0) == 0xc0)
@ -355,8 +357,11 @@ typedef struct DisasContext {
bool do_check_illtag; bool do_check_illtag;
/* Delayed window bounds check */ /* Delayed window bounds check */
int wd_size;
int max_r; int max_r;
int max_r_cur; int max_r_src;
int max_r_dst;
int bsize;
int max_b; int max_b;
int max_b_cur; int max_b_cur;

View File

@ -1462,7 +1462,7 @@ static inline void gen_puttag_i32(Instr *instr)
set_al_result_reg32_tag(instr, dst, tag, false, false); 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 src2, TCGv_i64 src3)
{ {
TCGv_i64 one = tcg_const_i64(1); 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); 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 src2, TCGv_i32 src3)
{ {
TCGv_i32 one = tcg_const_i32(1); 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); 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 */ /* ALES2/5 may be allocated but must not be used */
int opc2 = instr->ales_present & ALES_PRESENT ? instr->opc2 : 0; int opc2 = instr->ales_present & ALES_PRESENT ? instr->opc2 : 0;
@ -2965,25 +2965,109 @@ static Alop find_op(Instr *instr)
case ALOPF16: case ALOPF16:
is_match = desc->extra1 == instr->opce2; is_match = desc->extra1 == instr->opce2;
break; break;
default:
g_assert_not_reached();
break;
} }
if (is_match) { if (is_match) {
return desc->op; return desc;
} }
index = desc->next[instr->chan]; 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) static void gen_op(DisasContext *ctx, Instr *instr)
{ {
int chan = instr->chan; int chan = instr->chan;
Alop op = find_op(instr); AlopDesc *desc = find_op(instr);
if (desc == NULL) {
switch(op) { e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPC);
case OP_NONE: e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPC); break; return;
}
check_args(desc->alopf, instr);
switch(desc->op) {
case OP_ANDS: gen_alopf1_sss(instr, tcg_gen_and_i32); break; 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_ANDD: gen_alopf1_ddd(instr, tcg_gen_and_i64); break;
case OP_ANDNS: gen_alopf1_sss(instr, gen_andn_i32); 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_QPFMSAS:
case OP_QPFMASD: case OP_QPFMASD:
case OP_QPFMSAD: 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: case 0x6c:
if (is_chan_0134(instr->chan) && ctx->version >= 4) { if (is_chan_0134(instr->chan) && ctx->version >= 4) {
/* insfs */ /* insfs */
gen_alopf21_i32(ctx, instr, gen_insert_field_i32); check_args(ALOPF21, instr);
gen_alopf21_i32(ctx, instr, gen_insfs);
return; return;
} }
break; break;
case 0x6d: case 0x6d:
if (is_chan_0134(instr->chan) && ctx->version>= 4) { if (is_chan_0134(instr->chan) && ctx->version>= 4) {
/* insfd */ /* insfd */
gen_alopf21_i64(ctx, instr, gen_insert_field_i64); check_args(ALOPF21, instr);
gen_alopf21_i64(ctx, instr, gen_insfd);
return; return;
} }
break; break;
default: default:
check_args(ALOPF21, instr);
gen_icmb012(ctx, instr); gen_icmb012(ctx, instr);
break; break;
} }
@ -4408,6 +4495,8 @@ gen_illopc:
static void gen_fcmb(DisasContext *ctx, Instr *instr) static void gen_fcmb(DisasContext *ctx, Instr *instr)
{ {
check_args(ALOPF21, instr);
if (instr->opc1 & 1) { if (instr->opc1 & 1) {
execute_fcomb_i64(ctx, instr); execute_fcomb_i64(ctx, instr);
} else { } else {
@ -4421,6 +4510,7 @@ static void gen_pfcmb1(DisasContext *ctx, Instr *instr)
case 0x4d: case 0x4d:
if (is_chan_0134(instr->chan) && ctx->version >= 2) { if (is_chan_0134(instr->chan) && ctx->version >= 2) {
/* pshufb */ /* pshufb */
check_args(ALOPF21, instr);
gen_alopf21_i64(ctx, instr, gen_helper_pshufb); gen_alopf21_i64(ctx, instr, gen_helper_pshufb);
return; 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_i64 dst = e2k_get_temp_i64(ctx);
TCGv_i32 opc = tcg_const_i32(base + instr->opc1); TCGv_i32 opc = tcg_const_i32(base + instr->opc1);
check_args(ALOPF21, instr);
gen_tag3_i64(tag, s1.tag, s2.tag, s3.tag); gen_tag3_i64(tag, s1.tag, s2.tag, s3.tag);
gen_helper_plog(dst, opc, s1.value, s2.value, s3.value); gen_helper_plog(dst, opc, s1.value, s2.value, s3.value);
gen_al_result_i64(instr, dst, tag); gen_al_result_i64(instr, dst, tag);

View File

@ -1,5 +1,4 @@
typedef enum { typedef enum {
OP_NONE,
OP_ANDS, OP_ANDS,
OP_ANDD, OP_ANDD,
OP_ANDNS, OP_ANDNS,