qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [patch] Arm conditional execution


From: Paul Brook
Subject: [Qemu-devel] [patch] Arm conditional execution
Date: Sun, 24 Apr 2005 01:18:10 +0100
User-agent: KMail/1.7.2

The attached patch changes arm conditional execution so a conditional 
non-branch instruction no longer terminates the translation block. The patch 
has no measurable effect on performance. However it does make single-stepping 
work properly.

Paul
? target-arm/p
Index: target-arm/op.c
===================================================================
RCS file: /cvsroot/qemu/qemu/target-arm/op.c,v
retrieving revision 1.11
diff -u -p -r1.11 op.c
--- target-arm/op.c     17 Apr 2005 19:16:13 -0000      1.11
+++ target-arm/op.c     24 Apr 2005 00:08:53 -0000
@@ -251,104 +251,109 @@ void OPPROTO op_logic_T1_cc(void)
 void OPPROTO op_test_eq(void)
 {
     if (env->NZF == 0)
-        JUMP_TB(op_test_eq, PARAM1, 0, PARAM2);
+        GOTO_LABEL_PARAM(1);;
     FORCE_RET();
 }
 
 void OPPROTO op_test_ne(void)
 {
     if (env->NZF != 0)
-        JUMP_TB(op_test_ne, PARAM1, 0, PARAM2);
+        GOTO_LABEL_PARAM(1);;
     FORCE_RET();
 }
 
 void OPPROTO op_test_cs(void)
 {
     if (env->CF != 0)
-        JUMP_TB(op_test_cs, PARAM1, 0, PARAM2);
+        GOTO_LABEL_PARAM(1);
     FORCE_RET();
 }
 
 void OPPROTO op_test_cc(void)
 {
     if (env->CF == 0)
-        JUMP_TB(op_test_cc, PARAM1, 0, PARAM2);
+        GOTO_LABEL_PARAM(1);
     FORCE_RET();
 }
 
 void OPPROTO op_test_mi(void)
 {
     if ((env->NZF & 0x80000000) != 0)
-        JUMP_TB(op_test_mi, PARAM1, 0, PARAM2);
+        GOTO_LABEL_PARAM(1);
     FORCE_RET();
 }
 
 void OPPROTO op_test_pl(void)
 {
     if ((env->NZF & 0x80000000) == 0)
-        JUMP_TB(op_test_pl, PARAM1, 0, PARAM2);
+        GOTO_LABEL_PARAM(1);
     FORCE_RET();
 }
 
 void OPPROTO op_test_vs(void)
 {
     if ((env->VF & 0x80000000) != 0)
-        JUMP_TB(op_test_vs, PARAM1, 0, PARAM2);
+        GOTO_LABEL_PARAM(1);
     FORCE_RET();
 }
 
 void OPPROTO op_test_vc(void)
 {
     if ((env->VF & 0x80000000) == 0)
-        JUMP_TB(op_test_vc, PARAM1, 0, PARAM2);
+        GOTO_LABEL_PARAM(1);
     FORCE_RET();
 }
 
 void OPPROTO op_test_hi(void)
 {
     if (env->CF != 0 && env->NZF != 0)
-        JUMP_TB(op_test_hi, PARAM1, 0, PARAM2);
+        GOTO_LABEL_PARAM(1);
     FORCE_RET();
 }
 
 void OPPROTO op_test_ls(void)
 {
     if (env->CF == 0 || env->NZF == 0)
-        JUMP_TB(op_test_ls, PARAM1, 0, PARAM2);
+        GOTO_LABEL_PARAM(1);
     FORCE_RET();
 }
 
 void OPPROTO op_test_ge(void)
 {
     if (((env->VF ^ env->NZF) & 0x80000000) == 0)
-        JUMP_TB(op_test_ge, PARAM1, 0, PARAM2);
+        GOTO_LABEL_PARAM(1);
     FORCE_RET();
 }
 
 void OPPROTO op_test_lt(void)
 {
     if (((env->VF ^ env->NZF) & 0x80000000) != 0)
-        JUMP_TB(op_test_lt, PARAM1, 0, PARAM2);
+        GOTO_LABEL_PARAM(1);
     FORCE_RET();
 }
 
 void OPPROTO op_test_gt(void)
 {
     if (env->NZF != 0 && ((env->VF ^ env->NZF) & 0x80000000) == 0)
-        JUMP_TB(op_test_gt, PARAM1, 0, PARAM2);
+        GOTO_LABEL_PARAM(1);
     FORCE_RET();
 }
 
 void OPPROTO op_test_le(void)
 {
     if (env->NZF == 0 || ((env->VF ^ env->NZF) & 0x80000000) != 0)
-        JUMP_TB(op_test_le, PARAM1, 0, PARAM2);
+        GOTO_LABEL_PARAM(1);
     FORCE_RET();
 }
 
-void OPPROTO op_jmp(void)
+void OPPROTO op_jmp0(void)
 {
-    JUMP_TB(op_jmp, PARAM1, 1, PARAM2);
+    JUMP_TB(op_jmp0, PARAM1, 0, PARAM2);
+}
+
+void OPPROTO op_jmp1(void)
+{
+    JUMP_TB(op_jmp1, PARAM1, 1, PARAM2);
 }
 
 void OPPROTO op_exit_tb(void)
Index: target-arm/translate.c
===================================================================
RCS file: /cvsroot/qemu/qemu/target-arm/translate.c,v
retrieving revision 1.22
diff -u -p -r1.22 translate.c
--- target-arm/translate.c      23 Apr 2005 18:46:03 -0000      1.22
+++ target-arm/translate.c      24 Apr 2005 00:08:53 -0000
@@ -32,6 +32,10 @@
 typedef struct DisasContext {
     target_ulong pc;
     int is_jmp;
+    /* Nonzero if this instruction has been conditionally skipped.  */
+    int condjmp;
+    /* The label that will be jumped to when the instruction is skipped.  */
+    int condlabel;
     struct TranslationBlock *tb;
     int singlestep_enabled;
 } DisasContext;
@@ -53,7 +57,7 @@ enum {
 
 #include "gen-op.h"
 
-static GenOpFunc2 *gen_test_cc[14] = {
+static GenOpFunc1 *gen_test_cc[14] = {
     gen_op_test_eq,
     gen_op_test_ne,
     gen_op_test_cs,
@@ -896,7 +900,7 @@ static inline void gen_jmp (DisasContext
         gen_op_movl_T0_im(dest);
         gen_bx(s);
     } else {
-        gen_op_jmp((long)s->tb, dest);
+        gen_op_jmp0((long)s->tb, dest);
         s->is_jmp = DISAS_TB_JUMP;
     }
 }
@@ -939,8 +943,11 @@ static void disas_arm_insn(CPUState * en
     if (cond != 0xe) {
         /* if not always execute, we generate a conditional jump to
            next instruction */
-        gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc);
-        s->is_jmp = DISAS_JUMP_NEXT;
+        s->condlabel = gen_new_label();
+        gen_test_cc[cond ^ 1](s->condlabel);
+        s->condjmp = 1;
+        //gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc);
+        //s->is_jmp = DISAS_JUMP_NEXT;
     }
     if ((insn & 0x0f900000) == 0x03000000) {
         if ((insn & 0x0ff0f000) != 0x0360f000)
@@ -1961,8 +1968,11 @@ static void disas_thumb_insn(DisasContex
             break;
         }
         /* generate a conditional jump to next instruction */
-        gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc);
-        s->is_jmp = DISAS_JUMP_NEXT;
+        s->condlabel = gen_new_label();
+        gen_test_cc[cond ^ 1](s->condlabel);
+        s->condjmp = 1;
+        //gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc);
+        //s->is_jmp = DISAS_JUMP_NEXT;
         gen_movl_T1_reg(s, 15);
 
         /* jump to the offset */
@@ -2034,6 +2044,8 @@ static inline int gen_intermediate_code_
     dc->is_jmp = DISAS_NEXT;
     dc->pc = pc_start;
     dc->singlestep_enabled = env->singlestep_enabled;
+    dc->condjmp = 0;
+    nb_gen_labels = 0;
     lj = -1;
     do {
         if (env->nb_breakpoints > 0) {
@@ -2057,25 +2069,41 @@ static inline int gen_intermediate_code_
             gen_opc_pc[lj] = dc->pc;
             gen_opc_instr_start[lj] = 1;
         }
+
         if (env->thumb)
           disas_thumb_insn(dc);
         else
           disas_arm_insn(env, dc);
+
+        if (dc->condjmp && !dc->is_jmp) {
+            gen_set_label(dc->condlabel);
+            dc->condjmp = 0;
+        }
+        /* Translation stops when a conditional branch is enoutered.
+         * Otherwise the subsequent code could get translated several times.
+         */
     } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
              !env->singlestep_enabled &&
              (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32));
+    /* It this stage dc->condjmp will only be set when the skipped
+     * instruction was a conditional branch, and teh PC has already been
+     * written.  */
     if (__builtin_expect(env->singlestep_enabled, 0)) {
         /* Make sure the pc is updated, and raise a debug exception.  */
-        if (dc->is_jmp == DISAS_NEXT || dc->is_jmp == DISAS_JUMP_NEXT) {
+        if (dc->condjmp) {
+            gen_op_debug();
+            gen_set_label(dc->condlabel);
+        }
+        if (dc->condjmp || !dc->is_jmp) {
             gen_op_movl_T0_im((long)dc->pc);
             gen_op_movl_reg_TN[0][15]();
+            dc->condjmp = 0;
         }
         gen_op_debug();
     } else {
         switch(dc->is_jmp) {
-        case DISAS_JUMP_NEXT:
         case DISAS_NEXT:
-            gen_op_jmp((long)dc->tb, (long)dc->pc);
+            gen_op_jmp1((long)dc->tb, (long)dc->pc);
             break;
         default:
         case DISAS_JUMP:
@@ -2088,6 +2116,11 @@ static inline int gen_intermediate_code_
             /* nothing more to generate */
             break;
         }
+        if (dc->condjmp) {
+            gen_set_label(dc->condlabel);
+            gen_op_jmp1((long)dc->tb, (long)dc->pc);
+            dc->condjmp = 0;
+        }
     }
     *gen_opc_ptr = INDEX_op_end;
 

reply via email to

[Prev in Thread] Current Thread [Next in Thread]