Commit e50e6a20192616b93d94be316556deb001e4f477
1 parent
430116a1
better arm conditionnal execution implementation (Paul Brook)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1399 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
63 additions
and
25 deletions
target-arm/op.c
... | ... | @@ -251,104 +251,109 @@ void OPPROTO op_logic_T1_cc(void) |
251 | 251 | void OPPROTO op_test_eq(void) |
252 | 252 | { |
253 | 253 | if (env->NZF == 0) |
254 | - JUMP_TB(op_test_eq, PARAM1, 0, PARAM2); | |
254 | + GOTO_LABEL_PARAM(1);; | |
255 | 255 | FORCE_RET(); |
256 | 256 | } |
257 | 257 | |
258 | 258 | void OPPROTO op_test_ne(void) |
259 | 259 | { |
260 | 260 | if (env->NZF != 0) |
261 | - JUMP_TB(op_test_ne, PARAM1, 0, PARAM2); | |
261 | + GOTO_LABEL_PARAM(1);; | |
262 | 262 | FORCE_RET(); |
263 | 263 | } |
264 | 264 | |
265 | 265 | void OPPROTO op_test_cs(void) |
266 | 266 | { |
267 | 267 | if (env->CF != 0) |
268 | - JUMP_TB(op_test_cs, PARAM1, 0, PARAM2); | |
268 | + GOTO_LABEL_PARAM(1); | |
269 | 269 | FORCE_RET(); |
270 | 270 | } |
271 | 271 | |
272 | 272 | void OPPROTO op_test_cc(void) |
273 | 273 | { |
274 | 274 | if (env->CF == 0) |
275 | - JUMP_TB(op_test_cc, PARAM1, 0, PARAM2); | |
275 | + GOTO_LABEL_PARAM(1); | |
276 | 276 | FORCE_RET(); |
277 | 277 | } |
278 | 278 | |
279 | 279 | void OPPROTO op_test_mi(void) |
280 | 280 | { |
281 | 281 | if ((env->NZF & 0x80000000) != 0) |
282 | - JUMP_TB(op_test_mi, PARAM1, 0, PARAM2); | |
282 | + GOTO_LABEL_PARAM(1); | |
283 | 283 | FORCE_RET(); |
284 | 284 | } |
285 | 285 | |
286 | 286 | void OPPROTO op_test_pl(void) |
287 | 287 | { |
288 | 288 | if ((env->NZF & 0x80000000) == 0) |
289 | - JUMP_TB(op_test_pl, PARAM1, 0, PARAM2); | |
289 | + GOTO_LABEL_PARAM(1); | |
290 | 290 | FORCE_RET(); |
291 | 291 | } |
292 | 292 | |
293 | 293 | void OPPROTO op_test_vs(void) |
294 | 294 | { |
295 | 295 | if ((env->VF & 0x80000000) != 0) |
296 | - JUMP_TB(op_test_vs, PARAM1, 0, PARAM2); | |
296 | + GOTO_LABEL_PARAM(1); | |
297 | 297 | FORCE_RET(); |
298 | 298 | } |
299 | 299 | |
300 | 300 | void OPPROTO op_test_vc(void) |
301 | 301 | { |
302 | 302 | if ((env->VF & 0x80000000) == 0) |
303 | - JUMP_TB(op_test_vc, PARAM1, 0, PARAM2); | |
303 | + GOTO_LABEL_PARAM(1); | |
304 | 304 | FORCE_RET(); |
305 | 305 | } |
306 | 306 | |
307 | 307 | void OPPROTO op_test_hi(void) |
308 | 308 | { |
309 | 309 | if (env->CF != 0 && env->NZF != 0) |
310 | - JUMP_TB(op_test_hi, PARAM1, 0, PARAM2); | |
310 | + GOTO_LABEL_PARAM(1); | |
311 | 311 | FORCE_RET(); |
312 | 312 | } |
313 | 313 | |
314 | 314 | void OPPROTO op_test_ls(void) |
315 | 315 | { |
316 | 316 | if (env->CF == 0 || env->NZF == 0) |
317 | - JUMP_TB(op_test_ls, PARAM1, 0, PARAM2); | |
317 | + GOTO_LABEL_PARAM(1); | |
318 | 318 | FORCE_RET(); |
319 | 319 | } |
320 | 320 | |
321 | 321 | void OPPROTO op_test_ge(void) |
322 | 322 | { |
323 | 323 | if (((env->VF ^ env->NZF) & 0x80000000) == 0) |
324 | - JUMP_TB(op_test_ge, PARAM1, 0, PARAM2); | |
324 | + GOTO_LABEL_PARAM(1); | |
325 | 325 | FORCE_RET(); |
326 | 326 | } |
327 | 327 | |
328 | 328 | void OPPROTO op_test_lt(void) |
329 | 329 | { |
330 | 330 | if (((env->VF ^ env->NZF) & 0x80000000) != 0) |
331 | - JUMP_TB(op_test_lt, PARAM1, 0, PARAM2); | |
331 | + GOTO_LABEL_PARAM(1); | |
332 | 332 | FORCE_RET(); |
333 | 333 | } |
334 | 334 | |
335 | 335 | void OPPROTO op_test_gt(void) |
336 | 336 | { |
337 | 337 | if (env->NZF != 0 && ((env->VF ^ env->NZF) & 0x80000000) == 0) |
338 | - JUMP_TB(op_test_gt, PARAM1, 0, PARAM2); | |
338 | + GOTO_LABEL_PARAM(1); | |
339 | 339 | FORCE_RET(); |
340 | 340 | } |
341 | 341 | |
342 | 342 | void OPPROTO op_test_le(void) |
343 | 343 | { |
344 | 344 | if (env->NZF == 0 || ((env->VF ^ env->NZF) & 0x80000000) != 0) |
345 | - JUMP_TB(op_test_le, PARAM1, 0, PARAM2); | |
345 | + GOTO_LABEL_PARAM(1); | |
346 | 346 | FORCE_RET(); |
347 | 347 | } |
348 | 348 | |
349 | -void OPPROTO op_jmp(void) | |
349 | +void OPPROTO op_jmp0(void) | |
350 | 350 | { |
351 | - JUMP_TB(op_jmp, PARAM1, 1, PARAM2); | |
351 | + JUMP_TB(op_jmp0, PARAM1, 0, PARAM2); | |
352 | +} | |
353 | + | |
354 | +void OPPROTO op_jmp1(void) | |
355 | +{ | |
356 | + JUMP_TB(op_jmp1, PARAM1, 1, PARAM2); | |
352 | 357 | } |
353 | 358 | |
354 | 359 | void OPPROTO op_exit_tb(void) | ... | ... |
target-arm/translate.c
... | ... | @@ -32,6 +32,10 @@ |
32 | 32 | typedef struct DisasContext { |
33 | 33 | target_ulong pc; |
34 | 34 | int is_jmp; |
35 | + /* Nonzero if this instruction has been conditionally skipped. */ | |
36 | + int condjmp; | |
37 | + /* The label that will be jumped to when the instruction is skipped. */ | |
38 | + int condlabel; | |
35 | 39 | struct TranslationBlock *tb; |
36 | 40 | int singlestep_enabled; |
37 | 41 | } DisasContext; |
... | ... | @@ -53,7 +57,7 @@ enum { |
53 | 57 | |
54 | 58 | #include "gen-op.h" |
55 | 59 | |
56 | -static GenOpFunc2 *gen_test_cc[14] = { | |
60 | +static GenOpFunc1 *gen_test_cc[14] = { | |
57 | 61 | gen_op_test_eq, |
58 | 62 | gen_op_test_ne, |
59 | 63 | gen_op_test_cs, |
... | ... | @@ -896,7 +900,7 @@ static inline void gen_jmp (DisasContext *s, uint32_t dest) |
896 | 900 | gen_op_movl_T0_im(dest); |
897 | 901 | gen_bx(s); |
898 | 902 | } else { |
899 | - gen_op_jmp((long)s->tb, dest); | |
903 | + gen_op_jmp0((long)s->tb, dest); | |
900 | 904 | s->is_jmp = DISAS_TB_JUMP; |
901 | 905 | } |
902 | 906 | } |
... | ... | @@ -939,8 +943,11 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) |
939 | 943 | if (cond != 0xe) { |
940 | 944 | /* if not always execute, we generate a conditional jump to |
941 | 945 | next instruction */ |
942 | - gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc); | |
943 | - s->is_jmp = DISAS_JUMP_NEXT; | |
946 | + s->condlabel = gen_new_label(); | |
947 | + gen_test_cc[cond ^ 1](s->condlabel); | |
948 | + s->condjmp = 1; | |
949 | + //gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc); | |
950 | + //s->is_jmp = DISAS_JUMP_NEXT; | |
944 | 951 | } |
945 | 952 | if ((insn & 0x0f900000) == 0x03000000) { |
946 | 953 | if ((insn & 0x0ff0f000) != 0x0360f000) |
... | ... | @@ -1961,8 +1968,11 @@ static void disas_thumb_insn(DisasContext *s) |
1961 | 1968 | break; |
1962 | 1969 | } |
1963 | 1970 | /* generate a conditional jump to next instruction */ |
1964 | - gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc); | |
1965 | - s->is_jmp = DISAS_JUMP_NEXT; | |
1971 | + s->condlabel = gen_new_label(); | |
1972 | + gen_test_cc[cond ^ 1](s->condlabel); | |
1973 | + s->condjmp = 1; | |
1974 | + //gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc); | |
1975 | + //s->is_jmp = DISAS_JUMP_NEXT; | |
1966 | 1976 | gen_movl_T1_reg(s, 15); |
1967 | 1977 | |
1968 | 1978 | /* jump to the offset */ |
... | ... | @@ -2034,6 +2044,8 @@ static inline int gen_intermediate_code_internal(CPUState *env, |
2034 | 2044 | dc->is_jmp = DISAS_NEXT; |
2035 | 2045 | dc->pc = pc_start; |
2036 | 2046 | dc->singlestep_enabled = env->singlestep_enabled; |
2047 | + dc->condjmp = 0; | |
2048 | + nb_gen_labels = 0; | |
2037 | 2049 | lj = -1; |
2038 | 2050 | do { |
2039 | 2051 | if (env->nb_breakpoints > 0) { |
... | ... | @@ -2057,25 +2069,41 @@ static inline int gen_intermediate_code_internal(CPUState *env, |
2057 | 2069 | gen_opc_pc[lj] = dc->pc; |
2058 | 2070 | gen_opc_instr_start[lj] = 1; |
2059 | 2071 | } |
2072 | + | |
2060 | 2073 | if (env->thumb) |
2061 | 2074 | disas_thumb_insn(dc); |
2062 | 2075 | else |
2063 | 2076 | disas_arm_insn(env, dc); |
2077 | + | |
2078 | + if (dc->condjmp && !dc->is_jmp) { | |
2079 | + gen_set_label(dc->condlabel); | |
2080 | + dc->condjmp = 0; | |
2081 | + } | |
2082 | + /* Translation stops when a conditional branch is enoutered. | |
2083 | + * Otherwise the subsequent code could get translated several times. | |
2084 | + */ | |
2064 | 2085 | } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && |
2065 | 2086 | !env->singlestep_enabled && |
2066 | 2087 | (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32)); |
2088 | + /* It this stage dc->condjmp will only be set when the skipped | |
2089 | + * instruction was a conditional branch, and teh PC has already been | |
2090 | + * written. */ | |
2067 | 2091 | if (__builtin_expect(env->singlestep_enabled, 0)) { |
2068 | 2092 | /* Make sure the pc is updated, and raise a debug exception. */ |
2069 | - if (dc->is_jmp == DISAS_NEXT || dc->is_jmp == DISAS_JUMP_NEXT) { | |
2093 | + if (dc->condjmp) { | |
2094 | + gen_op_debug(); | |
2095 | + gen_set_label(dc->condlabel); | |
2096 | + } | |
2097 | + if (dc->condjmp || !dc->is_jmp) { | |
2070 | 2098 | gen_op_movl_T0_im((long)dc->pc); |
2071 | 2099 | gen_op_movl_reg_TN[0][15](); |
2100 | + dc->condjmp = 0; | |
2072 | 2101 | } |
2073 | 2102 | gen_op_debug(); |
2074 | 2103 | } else { |
2075 | 2104 | switch(dc->is_jmp) { |
2076 | - case DISAS_JUMP_NEXT: | |
2077 | 2105 | case DISAS_NEXT: |
2078 | - gen_op_jmp((long)dc->tb, (long)dc->pc); | |
2106 | + gen_op_jmp1((long)dc->tb, (long)dc->pc); | |
2079 | 2107 | break; |
2080 | 2108 | default: |
2081 | 2109 | case DISAS_JUMP: |
... | ... | @@ -2088,6 +2116,11 @@ static inline int gen_intermediate_code_internal(CPUState *env, |
2088 | 2116 | /* nothing more to generate */ |
2089 | 2117 | break; |
2090 | 2118 | } |
2119 | + if (dc->condjmp) { | |
2120 | + gen_set_label(dc->condlabel); | |
2121 | + gen_op_jmp1((long)dc->tb, (long)dc->pc); | |
2122 | + dc->condjmp = 0; | |
2123 | + } | |
2091 | 2124 | } |
2092 | 2125 | *gen_opc_ptr = INDEX_op_end; |
2093 | 2126 | ... | ... |