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,104 +251,109 @@ void OPPROTO op_logic_T1_cc(void) | ||
| 251 | void OPPROTO op_test_eq(void) | 251 | void OPPROTO op_test_eq(void) |
| 252 | { | 252 | { |
| 253 | if (env->NZF == 0) | 253 | if (env->NZF == 0) |
| 254 | - JUMP_TB(op_test_eq, PARAM1, 0, PARAM2); | 254 | + GOTO_LABEL_PARAM(1);; |
| 255 | FORCE_RET(); | 255 | FORCE_RET(); |
| 256 | } | 256 | } |
| 257 | 257 | ||
| 258 | void OPPROTO op_test_ne(void) | 258 | void OPPROTO op_test_ne(void) |
| 259 | { | 259 | { |
| 260 | if (env->NZF != 0) | 260 | if (env->NZF != 0) |
| 261 | - JUMP_TB(op_test_ne, PARAM1, 0, PARAM2); | 261 | + GOTO_LABEL_PARAM(1);; |
| 262 | FORCE_RET(); | 262 | FORCE_RET(); |
| 263 | } | 263 | } |
| 264 | 264 | ||
| 265 | void OPPROTO op_test_cs(void) | 265 | void OPPROTO op_test_cs(void) |
| 266 | { | 266 | { |
| 267 | if (env->CF != 0) | 267 | if (env->CF != 0) |
| 268 | - JUMP_TB(op_test_cs, PARAM1, 0, PARAM2); | 268 | + GOTO_LABEL_PARAM(1); |
| 269 | FORCE_RET(); | 269 | FORCE_RET(); |
| 270 | } | 270 | } |
| 271 | 271 | ||
| 272 | void OPPROTO op_test_cc(void) | 272 | void OPPROTO op_test_cc(void) |
| 273 | { | 273 | { |
| 274 | if (env->CF == 0) | 274 | if (env->CF == 0) |
| 275 | - JUMP_TB(op_test_cc, PARAM1, 0, PARAM2); | 275 | + GOTO_LABEL_PARAM(1); |
| 276 | FORCE_RET(); | 276 | FORCE_RET(); |
| 277 | } | 277 | } |
| 278 | 278 | ||
| 279 | void OPPROTO op_test_mi(void) | 279 | void OPPROTO op_test_mi(void) |
| 280 | { | 280 | { |
| 281 | if ((env->NZF & 0x80000000) != 0) | 281 | if ((env->NZF & 0x80000000) != 0) |
| 282 | - JUMP_TB(op_test_mi, PARAM1, 0, PARAM2); | 282 | + GOTO_LABEL_PARAM(1); |
| 283 | FORCE_RET(); | 283 | FORCE_RET(); |
| 284 | } | 284 | } |
| 285 | 285 | ||
| 286 | void OPPROTO op_test_pl(void) | 286 | void OPPROTO op_test_pl(void) |
| 287 | { | 287 | { |
| 288 | if ((env->NZF & 0x80000000) == 0) | 288 | if ((env->NZF & 0x80000000) == 0) |
| 289 | - JUMP_TB(op_test_pl, PARAM1, 0, PARAM2); | 289 | + GOTO_LABEL_PARAM(1); |
| 290 | FORCE_RET(); | 290 | FORCE_RET(); |
| 291 | } | 291 | } |
| 292 | 292 | ||
| 293 | void OPPROTO op_test_vs(void) | 293 | void OPPROTO op_test_vs(void) |
| 294 | { | 294 | { |
| 295 | if ((env->VF & 0x80000000) != 0) | 295 | if ((env->VF & 0x80000000) != 0) |
| 296 | - JUMP_TB(op_test_vs, PARAM1, 0, PARAM2); | 296 | + GOTO_LABEL_PARAM(1); |
| 297 | FORCE_RET(); | 297 | FORCE_RET(); |
| 298 | } | 298 | } |
| 299 | 299 | ||
| 300 | void OPPROTO op_test_vc(void) | 300 | void OPPROTO op_test_vc(void) |
| 301 | { | 301 | { |
| 302 | if ((env->VF & 0x80000000) == 0) | 302 | if ((env->VF & 0x80000000) == 0) |
| 303 | - JUMP_TB(op_test_vc, PARAM1, 0, PARAM2); | 303 | + GOTO_LABEL_PARAM(1); |
| 304 | FORCE_RET(); | 304 | FORCE_RET(); |
| 305 | } | 305 | } |
| 306 | 306 | ||
| 307 | void OPPROTO op_test_hi(void) | 307 | void OPPROTO op_test_hi(void) |
| 308 | { | 308 | { |
| 309 | if (env->CF != 0 && env->NZF != 0) | 309 | if (env->CF != 0 && env->NZF != 0) |
| 310 | - JUMP_TB(op_test_hi, PARAM1, 0, PARAM2); | 310 | + GOTO_LABEL_PARAM(1); |
| 311 | FORCE_RET(); | 311 | FORCE_RET(); |
| 312 | } | 312 | } |
| 313 | 313 | ||
| 314 | void OPPROTO op_test_ls(void) | 314 | void OPPROTO op_test_ls(void) |
| 315 | { | 315 | { |
| 316 | if (env->CF == 0 || env->NZF == 0) | 316 | if (env->CF == 0 || env->NZF == 0) |
| 317 | - JUMP_TB(op_test_ls, PARAM1, 0, PARAM2); | 317 | + GOTO_LABEL_PARAM(1); |
| 318 | FORCE_RET(); | 318 | FORCE_RET(); |
| 319 | } | 319 | } |
| 320 | 320 | ||
| 321 | void OPPROTO op_test_ge(void) | 321 | void OPPROTO op_test_ge(void) |
| 322 | { | 322 | { |
| 323 | if (((env->VF ^ env->NZF) & 0x80000000) == 0) | 323 | if (((env->VF ^ env->NZF) & 0x80000000) == 0) |
| 324 | - JUMP_TB(op_test_ge, PARAM1, 0, PARAM2); | 324 | + GOTO_LABEL_PARAM(1); |
| 325 | FORCE_RET(); | 325 | FORCE_RET(); |
| 326 | } | 326 | } |
| 327 | 327 | ||
| 328 | void OPPROTO op_test_lt(void) | 328 | void OPPROTO op_test_lt(void) |
| 329 | { | 329 | { |
| 330 | if (((env->VF ^ env->NZF) & 0x80000000) != 0) | 330 | if (((env->VF ^ env->NZF) & 0x80000000) != 0) |
| 331 | - JUMP_TB(op_test_lt, PARAM1, 0, PARAM2); | 331 | + GOTO_LABEL_PARAM(1); |
| 332 | FORCE_RET(); | 332 | FORCE_RET(); |
| 333 | } | 333 | } |
| 334 | 334 | ||
| 335 | void OPPROTO op_test_gt(void) | 335 | void OPPROTO op_test_gt(void) |
| 336 | { | 336 | { |
| 337 | if (env->NZF != 0 && ((env->VF ^ env->NZF) & 0x80000000) == 0) | 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 | FORCE_RET(); | 339 | FORCE_RET(); |
| 340 | } | 340 | } |
| 341 | 341 | ||
| 342 | void OPPROTO op_test_le(void) | 342 | void OPPROTO op_test_le(void) |
| 343 | { | 343 | { |
| 344 | if (env->NZF == 0 || ((env->VF ^ env->NZF) & 0x80000000) != 0) | 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 | FORCE_RET(); | 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 | void OPPROTO op_exit_tb(void) | 359 | void OPPROTO op_exit_tb(void) |
target-arm/translate.c
| @@ -32,6 +32,10 @@ | @@ -32,6 +32,10 @@ | ||
| 32 | typedef struct DisasContext { | 32 | typedef struct DisasContext { |
| 33 | target_ulong pc; | 33 | target_ulong pc; |
| 34 | int is_jmp; | 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 | struct TranslationBlock *tb; | 39 | struct TranslationBlock *tb; |
| 36 | int singlestep_enabled; | 40 | int singlestep_enabled; |
| 37 | } DisasContext; | 41 | } DisasContext; |
| @@ -53,7 +57,7 @@ enum { | @@ -53,7 +57,7 @@ enum { | ||
| 53 | 57 | ||
| 54 | #include "gen-op.h" | 58 | #include "gen-op.h" |
| 55 | 59 | ||
| 56 | -static GenOpFunc2 *gen_test_cc[14] = { | 60 | +static GenOpFunc1 *gen_test_cc[14] = { |
| 57 | gen_op_test_eq, | 61 | gen_op_test_eq, |
| 58 | gen_op_test_ne, | 62 | gen_op_test_ne, |
| 59 | gen_op_test_cs, | 63 | gen_op_test_cs, |
| @@ -896,7 +900,7 @@ static inline void gen_jmp (DisasContext *s, uint32_t dest) | @@ -896,7 +900,7 @@ static inline void gen_jmp (DisasContext *s, uint32_t dest) | ||
| 896 | gen_op_movl_T0_im(dest); | 900 | gen_op_movl_T0_im(dest); |
| 897 | gen_bx(s); | 901 | gen_bx(s); |
| 898 | } else { | 902 | } else { |
| 899 | - gen_op_jmp((long)s->tb, dest); | 903 | + gen_op_jmp0((long)s->tb, dest); |
| 900 | s->is_jmp = DISAS_TB_JUMP; | 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,8 +943,11 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) | ||
| 939 | if (cond != 0xe) { | 943 | if (cond != 0xe) { |
| 940 | /* if not always execute, we generate a conditional jump to | 944 | /* if not always execute, we generate a conditional jump to |
| 941 | next instruction */ | 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 | if ((insn & 0x0f900000) == 0x03000000) { | 952 | if ((insn & 0x0f900000) == 0x03000000) { |
| 946 | if ((insn & 0x0ff0f000) != 0x0360f000) | 953 | if ((insn & 0x0ff0f000) != 0x0360f000) |
| @@ -1961,8 +1968,11 @@ static void disas_thumb_insn(DisasContext *s) | @@ -1961,8 +1968,11 @@ static void disas_thumb_insn(DisasContext *s) | ||
| 1961 | break; | 1968 | break; |
| 1962 | } | 1969 | } |
| 1963 | /* generate a conditional jump to next instruction */ | 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 | gen_movl_T1_reg(s, 15); | 1976 | gen_movl_T1_reg(s, 15); |
| 1967 | 1977 | ||
| 1968 | /* jump to the offset */ | 1978 | /* jump to the offset */ |
| @@ -2034,6 +2044,8 @@ static inline int gen_intermediate_code_internal(CPUState *env, | @@ -2034,6 +2044,8 @@ static inline int gen_intermediate_code_internal(CPUState *env, | ||
| 2034 | dc->is_jmp = DISAS_NEXT; | 2044 | dc->is_jmp = DISAS_NEXT; |
| 2035 | dc->pc = pc_start; | 2045 | dc->pc = pc_start; |
| 2036 | dc->singlestep_enabled = env->singlestep_enabled; | 2046 | dc->singlestep_enabled = env->singlestep_enabled; |
| 2047 | + dc->condjmp = 0; | ||
| 2048 | + nb_gen_labels = 0; | ||
| 2037 | lj = -1; | 2049 | lj = -1; |
| 2038 | do { | 2050 | do { |
| 2039 | if (env->nb_breakpoints > 0) { | 2051 | if (env->nb_breakpoints > 0) { |
| @@ -2057,25 +2069,41 @@ static inline int gen_intermediate_code_internal(CPUState *env, | @@ -2057,25 +2069,41 @@ static inline int gen_intermediate_code_internal(CPUState *env, | ||
| 2057 | gen_opc_pc[lj] = dc->pc; | 2069 | gen_opc_pc[lj] = dc->pc; |
| 2058 | gen_opc_instr_start[lj] = 1; | 2070 | gen_opc_instr_start[lj] = 1; |
| 2059 | } | 2071 | } |
| 2072 | + | ||
| 2060 | if (env->thumb) | 2073 | if (env->thumb) |
| 2061 | disas_thumb_insn(dc); | 2074 | disas_thumb_insn(dc); |
| 2062 | else | 2075 | else |
| 2063 | disas_arm_insn(env, dc); | 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 | } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && | 2085 | } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && |
| 2065 | !env->singlestep_enabled && | 2086 | !env->singlestep_enabled && |
| 2066 | (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32)); | 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 | if (__builtin_expect(env->singlestep_enabled, 0)) { | 2091 | if (__builtin_expect(env->singlestep_enabled, 0)) { |
| 2068 | /* Make sure the pc is updated, and raise a debug exception. */ | 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 | gen_op_movl_T0_im((long)dc->pc); | 2098 | gen_op_movl_T0_im((long)dc->pc); |
| 2071 | gen_op_movl_reg_TN[0][15](); | 2099 | gen_op_movl_reg_TN[0][15](); |
| 2100 | + dc->condjmp = 0; | ||
| 2072 | } | 2101 | } |
| 2073 | gen_op_debug(); | 2102 | gen_op_debug(); |
| 2074 | } else { | 2103 | } else { |
| 2075 | switch(dc->is_jmp) { | 2104 | switch(dc->is_jmp) { |
| 2076 | - case DISAS_JUMP_NEXT: | ||
| 2077 | case DISAS_NEXT: | 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 | break; | 2107 | break; |
| 2080 | default: | 2108 | default: |
| 2081 | case DISAS_JUMP: | 2109 | case DISAS_JUMP: |
| @@ -2088,6 +2116,11 @@ static inline int gen_intermediate_code_internal(CPUState *env, | @@ -2088,6 +2116,11 @@ static inline int gen_intermediate_code_internal(CPUState *env, | ||
| 2088 | /* nothing more to generate */ | 2116 | /* nothing more to generate */ |
| 2089 | break; | 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 | *gen_opc_ptr = INDEX_op_end; | 2125 | *gen_opc_ptr = INDEX_op_end; |
| 2093 | 2126 |