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 + -
显示快捷键?