On 02/21/2015 07:31 AM, Chen Gang S wrote: > > Oh, we can not only assume y1 and x1 is the last execution in a bundle, > e.g. in __libc_start_main: > > 11330: c6f106c685928d8a { addi r10, sp, 40 ; addi r13, sp, 32 > ; st r25, r30 } > 11338: 2862014010000fca { moveli r10, 0 ; st r10, r0 } > > In this case, r10 will be over written. I have to use tcg temporary > variables for it in each bundle:
Yes. > - We can still use the original pipes order: "y0, y2, y1" and "x0, x1". I guess, sure, though I don't think that'll help as much as you imagine. > - y0, y2, and x0 need to use tcg temporary variables, but y1 and x1 can > still use real variables. Possibly, but I wouldn't structure it that way. I'd have all of the pipes write to temporaries. > - y1 and x1 need to flush the temporary variables, they also need to > consider about jump cases for tcg code (flush tcg temporary variables > after comparing and before jump). I wouldn't do that either. I'd have y1/x1 record that a branch occurred, and the condition, but delay the flushing and branching to common code. For instance: typedef enum ExitStatus { NO_EXIT, /* Fall through to next bundle */ EXIT_JUMP, /* Normal branch exit */ EXIT_NORETURN /* Exception taken (e.g. syscall) */ } ExitStatus; typedef struct DisasContext { struct TranslationBlock *tb; int mem_idx; uint64_t pc; ExitStatus exit; int result_regs[3]; TCGv result_vals[3]; TCGCond branch_cond; TCGv branch_dest; TCGv branch_val1; TCGv branch_val2; } DisasContext; static void translate_one_bundle(DisasContext *dc, uint64_t bundle) { int i; /* Initialize the per-bundle state of DC. */ dc->exit = NO_EXIT; for (i = 0; i < 3; ++i) { dc->result_regs[i] = -1; TCGV_UNUSED_I64(dc->result_vals[i]); } dc->branch_cond = TCG_COND_NEVER; dc->branch_desti = -1; TCGV_UNUSED_I64(dc->branch_dest); TCGV_UNUSED_I64(dc->branch_val1); TCGV_UNUSED_I64(dc->branch_val2); /* Decode all pipes, writing results into DC. */ /* If some pipe raises an exception, nothing left to do. */ if (dc->exit == EXIT_NORETURN) { return; } /* Write back register results from all pipes. */ for (i = 0; i < 3; ++i) { int r = dc->result_regs[i]; if (r >= 0) tcg_gen_mov_i64(cpu_regs[r], dc->result_vals[i]); tcg_temp_free_i64(dc->result_vals[i]); } } /* Write back branch results, i.e. take the branch now. */ if (dc->branch_cond != TCG_COND_NEVER) { if (dc->branch_cond == TCG_COND_ALWAYS) { /* Unconditional branch */ tcg_gen_mov_i64(cpu_pc, dc->branch_dest); } else { /* Conditional branch */ TCGv next_pc = tcg_const_i64(dc->pc + 8); tcg_gen_movcond_i64(dc->branch_cond, cpu_pc, dc->branch_val1, dc->branch_val2, dc->branch_dest, next_pc); tcg_temp_free_i64(dc->branch_val1); tcg_temp_free_i64(dc->branch_val2); tcg_temp_free_i64(next_pc); } tcg_temp_free_i64(dc->branch_dest); dc->exit = EXIT_JUMP; } } This mostly ignores the use of tcg_gen_goto_tb for now. It's slightly more complicated to use, and it makes debugging execution traces a bit harder. Neither of which do you really want while bringing up the decoder. However, the eventual use of goto_tb is why we want to delay performing the branch until after writing back the registers, rather than simply writing to cpu_pc right away. I hope this is enough to get started properly. r~