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