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 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);

View File

@ -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;

View File

@ -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);

View File

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