|
1 /* Helpers for instruction counting code generation. */ |
|
2 |
|
3 static TCGArg *icount_arg; |
|
4 static int icount_label; |
|
5 |
|
6 static inline void gen_icount_start(void) |
|
7 { |
|
8 TCGv_i32 count; |
|
9 |
|
10 if (!use_icount) |
|
11 return; |
|
12 |
|
13 icount_label = gen_new_label(); |
|
14 /* FIXME: This generates lousy code. We can't use tcg_new_temp because |
|
15 count needs to live over the conditional branch. To workaround this |
|
16 we allow the target to supply a convenient register temporary. */ |
|
17 #ifndef ICOUNT_TEMP |
|
18 count = tcg_temp_local_new_i32(); |
|
19 #else |
|
20 count = ICOUNT_TEMP; |
|
21 #endif |
|
22 tcg_gen_ld_i32(count, cpu_env, offsetof(CPUState, icount_decr.u32)); |
|
23 /* This is a horrid hack to allow fixing up the value later. */ |
|
24 icount_arg = gen_opparam_ptr + 1; |
|
25 tcg_gen_subi_i32(count, count, 0xdeadbeef); |
|
26 |
|
27 tcg_gen_brcondi_i32(TCG_COND_LT, count, 0, icount_label); |
|
28 tcg_gen_st16_i32(count, cpu_env, offsetof(CPUState, icount_decr.u16.low)); |
|
29 #ifndef ICOUNT_TEMP |
|
30 tcg_temp_free_i32(count); |
|
31 #endif |
|
32 } |
|
33 |
|
34 static void gen_icount_end(TranslationBlock *tb, int num_insns) |
|
35 { |
|
36 if (use_icount) { |
|
37 *icount_arg = num_insns; |
|
38 gen_set_label(icount_label); |
|
39 tcg_gen_exit_tb((long)tb + 2); |
|
40 } |
|
41 } |
|
42 |
|
43 static void inline gen_io_start(void) |
|
44 { |
|
45 TCGv_i32 tmp = tcg_const_i32(1); |
|
46 tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, can_do_io)); |
|
47 tcg_temp_free_i32(tmp); |
|
48 } |
|
49 |
|
50 static inline void gen_io_end(void) |
|
51 { |
|
52 TCGv_i32 tmp = tcg_const_i32(0); |
|
53 tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, can_do_io)); |
|
54 tcg_temp_free_i32(tmp); |
|
55 } |