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 | ... | ... |