tcg.c

来自「xen虚拟机源代码安装包」· C语言 代码 · 共 1,895 行 · 第 1/4 页

C
1,895
字号
            nb_args = args[-1];            args -= nb_args;            nb_iargs = args[0] & 0xffff;            nb_oargs = args[0] >> 16;            args++;            /* output args are dead */            for(i = 0; i < nb_oargs; i++) {                arg = args[i];                dead_temps[arg] = 1;            }                        /* globals are live (they may be used by the call) */            memset(dead_temps, 0, s->nb_globals);            /* input args are live */            dead_iargs = 0;            for(i = 0; i < nb_iargs; i++) {                arg = args[i + nb_oargs];                if (dead_temps[arg]) {                    dead_iargs |= (1 << i);                }                dead_temps[arg] = 0;            }            s->op_dead_iargs[op_index] = dead_iargs;            args--;            break;        case INDEX_op_set_label:            args--;            /* mark end of basic block */            tcg_la_bb_end(s, dead_temps);            break;        case INDEX_op_nopn:            nb_args = args[-1];            args -= nb_args;            break;        case INDEX_op_discard:            args--;            /* mark the temporary as dead */            dead_temps[args[0]] = 1;            break;        case INDEX_op_macro_2:            {                int dead_args[2], macro_id;                int saved_op_index, saved_arg_index;                int macro_op_index, macro_arg_index;                int macro_end_op_index, macro_end_arg_index;                int last_nb_temps;                                nb_args = 3;                args -= nb_args;                dead_args[0] = dead_temps[args[0]];                dead_args[1] = dead_temps[args[1]];                macro_id = args[2];                /* call the macro function which generate code                   depending on the live outputs */                saved_op_index = op_index;                saved_arg_index = args - gen_opparam_buf;                /* add a macro start instruction */                *gen_opc_ptr++ = INDEX_op_macro_start;                *gen_opparam_ptr++ = saved_op_index;                *gen_opparam_ptr++ = saved_arg_index;                macro_op_index = gen_opc_ptr - gen_opc_buf;                macro_arg_index = gen_opparam_ptr -  gen_opparam_buf;                last_nb_temps = s->nb_temps;                s->macro_func(s, macro_id, dead_args);                /* realloc temp info (XXX: make it faster) */                if (s->nb_temps > last_nb_temps) {                    uint8_t *new_dead_temps;                    new_dead_temps = tcg_malloc(s->nb_temps);                    memcpy(new_dead_temps, dead_temps, last_nb_temps);                    memset(new_dead_temps + last_nb_temps, 1,                            s->nb_temps - last_nb_temps);                    dead_temps = new_dead_temps;                }                macro_end_op_index = gen_opc_ptr - gen_opc_buf;                macro_end_arg_index = gen_opparam_ptr - gen_opparam_buf;                /* end of macro: add a goto to the next instruction */                *gen_opc_ptr++ = INDEX_op_macro_end;                *gen_opparam_ptr++ = op_index + 1;                *gen_opparam_ptr++ = saved_arg_index + nb_args;                /* modify the macro operation to be a macro_goto */                gen_opc_buf[op_index] = INDEX_op_macro_goto;                args[0] = macro_op_index;                args[1] = macro_arg_index;                args[2] = 0; /* dummy third arg to match the                                 macro parameters */                /* set the next instruction to the end of the macro */                op_index = macro_end_op_index;                args = macro_end_arg_index + gen_opparam_buf;            }            break;        case INDEX_op_macro_start:            args -= 2;            op_index = args[0];            args = gen_opparam_buf + args[1];            break;        case INDEX_op_macro_goto:        case INDEX_op_macro_end:            tcg_abort(); /* should never happen in liveness analysis */        case INDEX_op_end:            break;            /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */        default:            if (op > INDEX_op_end) {                args -= def->nb_args;                nb_iargs = def->nb_iargs;                nb_oargs = def->nb_oargs;                /* Test if the operation can be removed because all                   its outputs are dead. We assume that nb_oargs == 0                   implies side effects */                if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {                    for(i = 0; i < nb_oargs; i++) {                        arg = args[i];                        if (!dead_temps[arg])                            goto do_not_remove;                    }                    tcg_set_nop(s, gen_opc_buf + op_index, args, def->nb_args);#ifdef CONFIG_PROFILER                    {                        extern int64_t dyngen_tcg_del_op_count;                        dyngen_tcg_del_op_count++;                    }#endif                } else {                do_not_remove:                    /* output args are dead */                    for(i = 0; i < nb_oargs; i++) {                        arg = args[i];                        dead_temps[arg] = 1;                    }                                        /* if end of basic block, update */                    if (def->flags & TCG_OPF_BB_END) {                        tcg_la_bb_end(s, dead_temps);                    } else if (def->flags & TCG_OPF_CALL_CLOBBER) {                        /* globals are live */                        memset(dead_temps, 0, s->nb_globals);                    }                                        /* input args are live */                    dead_iargs = 0;                    for(i = 0; i < nb_iargs; i++) {                        arg = args[i + nb_oargs];                        if (dead_temps[arg]) {                            dead_iargs |= (1 << i);                        }                        dead_temps[arg] = 0;                    }                    s->op_dead_iargs[op_index] = dead_iargs;                }            } else {                /* legacy dyngen operations */                args -= def->nb_args;                /* mark end of basic block */                tcg_la_bb_end(s, dead_temps);            }            break;        }        op_index--;    }    if (args != gen_opparam_buf)        tcg_abort();}#else/* dummy liveness analysis */void tcg_liveness_analysis(TCGContext *s){    int nb_ops;    nb_ops = gen_opc_ptr - gen_opc_buf;    s->op_dead_iargs = tcg_malloc(nb_ops * sizeof(uint16_t));    memset(s->op_dead_iargs, 0, nb_ops * sizeof(uint16_t));}#endif#ifndef NDEBUGstatic void dump_regs(TCGContext *s){    TCGTemp *ts;    int i;    char buf[64];    for(i = 0; i < s->nb_temps; i++) {        ts = &s->temps[i];        printf("  %10s: ", tcg_get_arg_str_idx(s, buf, sizeof(buf), i));        switch(ts->val_type) {        case TEMP_VAL_REG:            printf("%s", tcg_target_reg_names[ts->reg]);            break;        case TEMP_VAL_MEM:            printf("%d(%s)", (int)ts->mem_offset, tcg_target_reg_names[ts->mem_reg]);            break;        case TEMP_VAL_CONST:            printf("$0x%" TCG_PRIlx, ts->val);            break;        case TEMP_VAL_DEAD:            printf("D");            break;        default:            printf("???");            break;        }        printf("\n");    }    for(i = 0; i < TCG_TARGET_NB_REGS; i++) {        if (s->reg_to_temp[i] >= 0) {            printf("%s: %s\n",                    tcg_target_reg_names[i],                    tcg_get_arg_str_idx(s, buf, sizeof(buf), s->reg_to_temp[i]));        }    }}static void check_regs(TCGContext *s){    int reg, k;    TCGTemp *ts;    char buf[64];    for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {        k = s->reg_to_temp[reg];        if (k >= 0) {            ts = &s->temps[k];            if (ts->val_type != TEMP_VAL_REG ||                ts->reg != reg) {                printf("Inconsistency for register %s:\n",                        tcg_target_reg_names[reg]);                goto fail;            }        }    }    for(k = 0; k < s->nb_temps; k++) {        ts = &s->temps[k];        if (ts->val_type == TEMP_VAL_REG &&            !ts->fixed_reg &&            s->reg_to_temp[ts->reg] != k) {                printf("Inconsistency for temp %s:\n",                        tcg_get_arg_str_idx(s, buf, sizeof(buf), k));        fail:                printf("reg state:\n");                dump_regs(s);                tcg_abort();        }        if (ts->val_type == TEMP_VAL_CONST && k < s->nb_globals) {            printf("constant forbidden in global %s\n",                   tcg_get_arg_str_idx(s, buf, sizeof(buf), k));            goto fail;        }    }}#endifstatic void temp_allocate_frame(TCGContext *s, int temp){    TCGTemp *ts;    ts = &s->temps[temp];    s->current_frame_offset = (s->current_frame_offset + sizeof(tcg_target_long) - 1) & ~(sizeof(tcg_target_long) - 1);    if (s->current_frame_offset + sizeof(tcg_target_long) > s->frame_end)        tcg_abort();    ts->mem_offset = s->current_frame_offset;    ts->mem_reg = s->frame_reg;    ts->mem_allocated = 1;    s->current_frame_offset += sizeof(tcg_target_long);}/* free register 'reg' by spilling the corresponding temporary if necessary */static void tcg_reg_free(TCGContext *s, int reg){    TCGTemp *ts;    int temp;    temp = s->reg_to_temp[reg];    if (temp != -1) {        ts = &s->temps[temp];        assert(ts->val_type == TEMP_VAL_REG);        if (!ts->mem_coherent) {            if (!ts->mem_allocated)                 temp_allocate_frame(s, temp);            tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset);        }        ts->val_type = TEMP_VAL_MEM;        s->reg_to_temp[reg] = -1;    }}/* Allocate a register belonging to reg1 & ~reg2 */static int tcg_reg_alloc(TCGContext *s, TCGRegSet reg1, TCGRegSet reg2){    int i, reg;    TCGRegSet reg_ct;    tcg_regset_andnot(reg_ct, reg1, reg2);    /* first try free registers */    for(i = 0; i < ARRAY_SIZE(tcg_target_reg_alloc_order); i++) {        reg = tcg_target_reg_alloc_order[i];        if (tcg_regset_test_reg(reg_ct, reg) && s->reg_to_temp[reg] == -1)            return reg;    }    /* XXX: do better spill choice */    for(i = 0; i < ARRAY_SIZE(tcg_target_reg_alloc_order); i++) {        reg = tcg_target_reg_alloc_order[i];        if (tcg_regset_test_reg(reg_ct, reg)) {            tcg_reg_free(s, reg);            return reg;        }    }    tcg_abort();}/* at the end of a basic block, we assume all temporaries are dead and   all globals are stored at their canonical location *//* XXX: optimize by handling constants in another array ? */void tcg_reg_alloc_bb_end(TCGContext *s){    TCGTemp *ts;    int i;    for(i = 0; i < s->nb_globals; i++) {        ts = &s->temps[i];        if (!ts->fixed_reg) {            if (ts->val_type == TEMP_VAL_REG) {                tcg_reg_free(s, ts->reg);            }        }    }    for(i = s->nb_globals; i < s->nb_temps; i++) {        ts = &s->temps[i];        if (ts->val_type != TEMP_VAL_CONST) {            if (ts->val_type == TEMP_VAL_REG) {                s->reg_to_temp[ts->reg] = -1;            }            ts->val_type = TEMP_VAL_DEAD;        }    }}#define IS_DEAD_IARG(n) ((dead_iargs >> (n)) & 1)static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def,                              const TCGArg *args,                              unsigned int dead_iargs){    TCGTemp *ts, *ots;    int reg;    const TCGArgConstraint *arg_ct;    ots = &s->temps[args[0]];    ts = &s->temps[args[1]];    arg_ct = &def->args_ct[0];    if (ts->val_type == TEMP_VAL_REG) {        if (IS_DEAD_IARG(0) && !ts->fixed_reg && !ots->fixed_reg) {            /* the mov can be suppressed */            if (ots->val_type == TEMP_VAL_REG)                s->reg_to_temp[ots->reg] = -1;            reg = ts->reg;            s->reg_to_temp[reg] = -1;            ts->val_type = TEMP_VAL_DEAD;        } else {            if (ots->val_type == TEMP_VAL_REG) {                reg = ots->reg;            } else {                reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs);            }            if (ts->reg != reg) {                tcg_out_mov(s, reg, ts->reg);            }        }    } else if (ts->val_type == TEMP_VAL_MEM) {        if (ots->val_type == TEMP_VAL_REG) {            reg = ots->reg;        } else {            reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs);        }        tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);    } else if (ts->val_type == TEMP_VAL_CONST) {        if (ots->val_type == TEMP_VAL_REG) {            reg = ots->reg;        } else {            reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs);        }        tcg_out_movi(s, ots->type, reg, ts->val);    } else {        tcg_abort();    }    s->reg_to_temp[reg] = args[0];    ots->reg = reg;    ots->val_type = TEMP_VAL_REG;    ots->mem_coherent = 0;}static void tcg_reg_alloc_op(TCGContext *s,                              const TCGOpDef *def, int opc,                             const TCGArg *args,                             unsigned int dead_iargs){    TCGRegSet allocated_regs;    int i, k, nb_iargs, nb_oargs, reg;    TCGArg arg;    const TCGArgConstraint *arg_ct;    TCGTemp *ts;    TCGArg new_args[TCG_MAX_OP_ARGS];    int const_args[TCG_MAX_OP_ARGS];    nb_oargs = def->nb_oargs;    nb_iargs = def->nb_iargs;    /* copy constants */    memcpy(new_args + nb_oargs + nb_iargs,            args + nb_oargs + nb_iargs,            sizeof(TCGArg) * def->nb_cargs);    /* satisfy input constraints */     tcg_regset_set(allocated_regs, s->reserved_regs);    for(k = 0; k < nb_iargs; k++) {        i = def->sorted_args[nb_oargs + k];        arg = args[i];        arg_ct = &def->args_ct[i];        ts = &s->temps[arg];        if (ts->val_type == TEMP_VAL_MEM) {            reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);            tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);            ts->val_type = TEMP_VAL_REG;            ts->reg = reg;            ts->mem_coherent = 1;            s->reg_to_temp[reg] = arg;        } else if (ts->val_type == TEMP_VAL_CONST) {            if (tcg_target_const_match(ts->val, arg_ct)) {                /* constant is OK for instruction */                const_args[i] = 1;                new_args[i] = ts->val;                goto iarg_end;            } else {                /* need to move to a register*/                reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);                tcg_out_movi(s, ts->type, reg, ts->val);                goto iarg_end1;            }        }        assert(ts->val_type == TEMP_VAL_REG);        if (arg_ct->ct & TCG_CT_IALIAS) {            if (ts->fixed_reg) {                /* if fixed register, we must allocate a new register                   if the alias is not the same register */                if (arg != args[arg_ct->alias_index])                    goto allocate_in_reg;            } else {                /* if the input is aliased to an output and if it is                   not dead after the instruction, we must allocate                   a new register and move it */                if (!IS_DEAD_IARG(i - nb_oargs))                     goto allocate_in_reg;            }        }

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?