tcg.c

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

C
1,895
字号
        reg = ts->reg;        if (tcg_regset_test_reg(arg_ct->u.regs, reg)) {            /* nothing to do : the constraint is satisfied */        } else {        allocate_in_reg:            /* allocate a new register matching the constraint                and move the temporary register into it */            reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);            tcg_out_mov(s, reg, ts->reg);        }    iarg_end1:        new_args[i] = reg;        const_args[i] = 0;        tcg_regset_set_reg(allocated_regs, reg);    iarg_end: ;    }        /* mark dead temporaries and free the associated registers */    for(i = 0; i < nb_iargs; i++) {        arg = args[nb_oargs + i];        if (IS_DEAD_IARG(i)) {            ts = &s->temps[arg];            if (ts->val_type != TEMP_VAL_CONST && !ts->fixed_reg) {                if (ts->val_type == TEMP_VAL_REG)                    s->reg_to_temp[ts->reg] = -1;                ts->val_type = TEMP_VAL_DEAD;            }        }    }    if (def->flags & TCG_OPF_CALL_CLOBBER) {        /* XXX: permit generic clobber register list ? */         for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {            if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) {                tcg_reg_free(s, reg);            }        }        /* XXX: for load/store we could do that only for the slow path           (i.e. when a memory callback is called) */        /* store globals and free associated registers (we assume the insn           can modify any global. */        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);                }            }        }    }    /* satisfy the output constraints */    tcg_regset_set(allocated_regs, s->reserved_regs);    for(k = 0; k < nb_oargs; k++) {        i = def->sorted_args[k];        arg = args[i];        arg_ct = &def->args_ct[i];        ts = &s->temps[arg];        if (arg_ct->ct & TCG_CT_ALIAS) {            reg = new_args[arg_ct->alias_index];        } else {            /* if fixed register, we try to use it */            reg = ts->reg;            if (ts->fixed_reg &&                tcg_regset_test_reg(arg_ct->u.regs, reg)) {                goto oarg_end;            }            reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);        }        tcg_regset_set_reg(allocated_regs, reg);        /* if a fixed register is used, then a move will be done afterwards */        if (!ts->fixed_reg) {            if (ts->val_type == TEMP_VAL_REG)                s->reg_to_temp[ts->reg] = -1;            ts->val_type = TEMP_VAL_REG;            ts->reg = reg;            /* temp value is modified, so the value kept in memory is               potentially not the same */            ts->mem_coherent = 0;             s->reg_to_temp[reg] = arg;        }    oarg_end:        new_args[i] = reg;    }    if (def->flags & TCG_OPF_BB_END)        tcg_reg_alloc_bb_end(s);    /* emit instruction */    tcg_out_op(s, opc, new_args, const_args);        /* move the outputs in the correct register if needed */    for(i = 0; i < nb_oargs; i++) {        ts = &s->temps[args[i]];        reg = new_args[i];        if (ts->fixed_reg && ts->reg != reg) {            tcg_out_mov(s, ts->reg, reg);        }    }}#ifdef TCG_TARGET_STACK_GROWSUP#define STACK_DIR(x) (-(x))#else#define STACK_DIR(x) (x)#endifstatic int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,                              int opc, const TCGArg *args,                              unsigned int dead_iargs){    int nb_iargs, nb_oargs, flags, nb_regs, i, reg, nb_params;    TCGArg arg, func_arg;    TCGTemp *ts;    tcg_target_long stack_offset, call_stack_size, func_addr;    int const_func_arg, allocate_args;    TCGRegSet allocated_regs;    const TCGArgConstraint *arg_ct;    arg = *args++;    nb_oargs = arg >> 16;    nb_iargs = arg & 0xffff;    nb_params = nb_iargs - 1;    flags = args[nb_oargs + nb_iargs];    nb_regs = tcg_target_get_call_iarg_regs_count(flags);    if (nb_regs > nb_params)        nb_regs = nb_params;    /* assign stack slots first */    /* XXX: preallocate call stack */    call_stack_size = (nb_params - nb_regs) * sizeof(tcg_target_long);    call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) &         ~(TCG_TARGET_STACK_ALIGN - 1);    allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE);    if (allocate_args) {        tcg_out_addi(s, TCG_REG_CALL_STACK, -STACK_DIR(call_stack_size));    }    /* XXX: on some architectures it does not start at zero */    stack_offset = 0;    for(i = nb_regs; i < nb_params; i++) {        arg = args[nb_oargs + i];        ts = &s->temps[arg];        if (ts->val_type == TEMP_VAL_REG) {            tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset);        } else if (ts->val_type == TEMP_VAL_MEM) {            reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],                                 s->reserved_regs);            /* XXX: not correct if reading values from the stack */            tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);            tcg_out_st(s, ts->type, reg, TCG_REG_CALL_STACK, stack_offset);        } else if (ts->val_type == TEMP_VAL_CONST) {            reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],                                 s->reserved_regs);            /* XXX: sign extend may be needed on some targets */            tcg_out_movi(s, ts->type, reg, ts->val);            tcg_out_st(s, ts->type, reg, TCG_REG_CALL_STACK, stack_offset);        } else {            tcg_abort();        }        /* XXX: not necessarily in the same order */        stack_offset += STACK_DIR(sizeof(tcg_target_long));    }        /* assign input registers */    tcg_regset_set(allocated_regs, s->reserved_regs);    for(i = 0; i < nb_regs; i++) {        arg = args[nb_oargs + i];        ts = &s->temps[arg];        reg = tcg_target_call_iarg_regs[i];        tcg_reg_free(s, reg);        if (ts->val_type == TEMP_VAL_REG) {            if (ts->reg != reg) {                tcg_out_mov(s, reg, ts->reg);            }        } else if (ts->val_type == TEMP_VAL_MEM) {            tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);        } else if (ts->val_type == TEMP_VAL_CONST) {            /* XXX: sign extend ? */            tcg_out_movi(s, ts->type, reg, ts->val);        } else {            tcg_abort();        }        tcg_regset_set_reg(allocated_regs, reg);    }        /* assign function address */    func_arg = args[nb_oargs + nb_iargs - 1];    arg_ct = &def->args_ct[0];    ts = &s->temps[func_arg];    func_addr = ts->val;    const_func_arg = 0;    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);        func_arg = reg;    } else if (ts->val_type == TEMP_VAL_REG) {        reg = ts->reg;        if (!tcg_regset_test_reg(arg_ct->u.regs, reg)) {            reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);            tcg_out_mov(s, reg, ts->reg);        }        func_arg = reg;    } else if (ts->val_type == TEMP_VAL_CONST) {        if (tcg_target_const_match(func_addr, arg_ct)) {            const_func_arg = 1;            func_arg = func_addr;        } else {            reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);            tcg_out_movi(s, ts->type, reg, func_addr);            func_arg = reg;        }    } else {        tcg_abort();    }        /* mark dead temporaries and free the associated registers */    for(i = 0; i < nb_params; i++) {        arg = args[nb_oargs + i];        if (IS_DEAD_IARG(i)) {            ts = &s->temps[arg];            if (ts->val_type != TEMP_VAL_CONST && !ts->fixed_reg) {                if (ts->val_type == TEMP_VAL_REG)                    s->reg_to_temp[ts->reg] = -1;                ts->val_type = TEMP_VAL_DEAD;            }        }    }        /* clobber call registers */    for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {        if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) {            tcg_reg_free(s, reg);        }    }        /* store globals and free associated registers (we assume the call       can modify any global. */    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);            }        }    }    tcg_out_op(s, opc, &func_arg, &const_func_arg);        if (allocate_args) {        tcg_out_addi(s, TCG_REG_CALL_STACK, STACK_DIR(call_stack_size));    }    /* assign output registers and emit moves if needed */    for(i = 0; i < nb_oargs; i++) {        arg = args[i];        ts = &s->temps[arg];        reg = tcg_target_call_oarg_regs[i];        tcg_reg_free(s, reg);        if (ts->fixed_reg) {            if (ts->reg != reg) {                tcg_out_mov(s, ts->reg, reg);            }        } else {            if (ts->val_type == TEMP_VAL_REG)                s->reg_to_temp[ts->reg] = -1;            ts->val_type = TEMP_VAL_REG;            ts->reg = reg;            ts->mem_coherent = 0;             s->reg_to_temp[reg] = arg;        }    }        return nb_iargs + nb_oargs + def->nb_cargs + 1;}#ifdef CONFIG_PROFILERstatic int64_t dyngen_table_op_count[NB_OPS];void dump_op_count(void){    int i;    FILE *f;    f = fopen("/tmp/op1.log", "w");    for(i = 0; i < INDEX_op_end; i++) {        fprintf(f, "%s %" PRId64 "\n", tcg_op_defs[i].name, dyngen_table_op_count[i]);    }    fclose(f);    f = fopen("/tmp/op2.log", "w");    for(i = INDEX_op_end; i < NB_OPS; i++) {        fprintf(f, "%s %" PRId64 "\n", tcg_op_defs[i].name, dyngen_table_op_count[i]);    }    fclose(f);}#endifstatic inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf,                                      long search_pc){    int opc, op_index, macro_op_index;    const TCGOpDef *def;    unsigned int dead_iargs;    const TCGArg *args;#ifdef DEBUG_DISAS    if (unlikely(loglevel & CPU_LOG_TB_OP)) {        fprintf(logfile, "OP:\n");        tcg_dump_ops(s, logfile);        fprintf(logfile, "\n");    }#endif    tcg_liveness_analysis(s);#ifdef DEBUG_DISAS    if (unlikely(loglevel & CPU_LOG_TB_OP_OPT)) {        fprintf(logfile, "OP after la:\n");        tcg_dump_ops(s, logfile);        fprintf(logfile, "\n");    }#endif    tcg_reg_alloc_start(s);    s->code_buf = gen_code_buf;    s->code_ptr = gen_code_buf;    macro_op_index = -1;    args = gen_opparam_buf;    op_index = 0;    for(;;) {        opc = gen_opc_buf[op_index];#ifdef CONFIG_PROFILER        dyngen_table_op_count[opc]++;#endif        def = &tcg_op_defs[opc];#if 0        printf("%s: %d %d %d\n", def->name,               def->nb_oargs, def->nb_iargs, def->nb_cargs);        //        dump_regs(s);#endif        switch(opc) {        case INDEX_op_mov_i32:#if TCG_TARGET_REG_BITS == 64        case INDEX_op_mov_i64:#endif            dead_iargs = s->op_dead_iargs[op_index];            tcg_reg_alloc_mov(s, def, args, dead_iargs);            break;        case INDEX_op_nop:        case INDEX_op_nop1:        case INDEX_op_nop2:        case INDEX_op_nop3:            break;        case INDEX_op_nopn:            args += args[0];            goto next;        case INDEX_op_discard:            {                TCGTemp *ts;                ts = &s->temps[args[0]];                /* mark the temporary as dead */                if (ts->val_type != TEMP_VAL_CONST && !ts->fixed_reg) {                    if (ts->val_type == TEMP_VAL_REG)                        s->reg_to_temp[ts->reg] = -1;                    ts->val_type = TEMP_VAL_DEAD;                }            }            break;        case INDEX_op_macro_goto:            macro_op_index = op_index; /* only used for exceptions */            op_index = args[0] - 1;            args = gen_opparam_buf + args[1];            goto next;        case INDEX_op_macro_end:            macro_op_index = -1; /* only used for exceptions */            op_index = args[0] - 1;            args = gen_opparam_buf + args[1];            goto next;        case INDEX_op_macro_start:            /* must never happen here */            tcg_abort();        case INDEX_op_set_label:            tcg_reg_alloc_bb_end(s);            tcg_out_label(s, args[0], (long)s->code_ptr);            break;        case INDEX_op_call:            dead_iargs = s->op_dead_iargs[op_index];            args += tcg_reg_alloc_call(s, def, opc, args, dead_iargs);            goto next;        case INDEX_op_end:            goto the_end;#ifdef CONFIG_DYNGEN_OP        case 0 ... INDEX_op_end - 1:            /* legacy dyngen ops */#ifdef CONFIG_PROFILER            {                extern int64_t dyngen_old_op_count;                dyngen_old_op_count++;            }#endif            tcg_reg_alloc_bb_end(s);            if (search_pc >= 0) {                s->code_ptr += def->copy_size;                args += def->nb_args;            } else {                args = dyngen_op(s, opc, args);            }            goto next;#endif        default:            /* Note: in order to speed up the code, it would be much               faster to have specialized register allocator functions for               some common argument patterns */            dead_iargs = s->op_dead_iargs[op_index];            tcg_reg_alloc_op(s, def, opc, args, dead_iargs);            break;        }        args += def->nb_args;    next: ;        if (search_pc >= 0 && search_pc < s->code_ptr - gen_code_buf) {            if (macro_op_index >= 0)                return macro_op_index;            else                return op_index;        }        op_index++;#ifndef NDEBUG        check_regs(s);#endif    } the_end:    return -1;}int dyngen_code(TCGContext *s, uint8_t *gen_code_buf){#ifdef CONFIG_PROFILER    {        extern int64_t dyngen_op_count;        extern int dyngen_op_count_max;        int n;        n = (gen_opc_ptr - gen_opc_buf);        dyngen_op_count += n;        if (n > dyngen_op_count_max)            dyngen_op_count_max = n;    }#endif    tcg_gen_code_common(s, gen_code_buf, -1);    /* flush instruction cache */    flush_icache_range((unsigned long)gen_code_buf,                        (unsigned long)s->code_ptr);    return s->code_ptr -  gen_code_buf;}/* Return the index of the micro operation such as the pc after is <   offset bytes from the start of the TB.  The contents of gen_code_buf must   not be changed, though writing the same values is ok.   Return -1 if not found. */int dyngen_code_search_pc(TCGContext *s, uint8_t *gen_code_buf, long offset){    return tcg_gen_code_common(s, gen_code_buf, offset);}

⌨️ 快捷键说明

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